fix: Ensure CSS support is checked more robustly (#1106)

* fix: Ensure CSS support is checked more robustly

* Apply formatting changes

* apply eslint changes

* Update packages/rrweb/src/record/observer.ts

Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>

* fix: do not use window in module scope

---------

Co-authored-by: mydea <mydea@users.noreply.github.com>
Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
This commit is contained in:
Francesco Novy
2023-02-09 09:19:53 +01:00
committed by GitHub
parent 25a4f5ab6c
commit cb1580008d

View File

@@ -54,11 +54,6 @@ type WindowWithAngularZone = IWindow & {
export const mutationBuffers: MutationBuffer[] = [];
export const processedNodeManager = new ProcessedNodeManager();
const isCSSGroupingRuleSupported = typeof CSSGroupingRule !== 'undefined';
const isCSSMediaRuleSupported = typeof CSSMediaRule !== 'undefined';
const isCSSSupportsRuleSupported = typeof CSSSupportsRule !== 'undefined';
const isCSSConditionRuleSupported = typeof CSSConditionRule !== 'undefined';
// Event.path is non-standard and used in some older browsers
type NonStandardEvent = Omit<Event, 'composedPath'> & {
path: EventTarget[];
@@ -488,13 +483,13 @@ function getNestedCSSRulePositions(rule: CSSRule): number[] {
const positions: number[] = [];
function recurse(childRule: CSSRule, pos: number[]) {
if (
(isCSSGroupingRuleSupported &&
(hasNestedCSSRule('CSSGroupingRule') &&
childRule.parentRule instanceof CSSGroupingRule) ||
(isCSSMediaRuleSupported &&
(hasNestedCSSRule('CSSMediaRule') &&
childRule.parentRule instanceof CSSMediaRule) ||
(isCSSSupportsRuleSupported &&
(hasNestedCSSRule('CSSSupportsRule') &&
childRule.parentRule instanceof CSSSupportsRule) ||
(isCSSConditionRuleSupported &&
(hasNestedCSSRule('CSSConditionRule') &&
childRule.parentRule instanceof CSSConditionRule)
) {
const rules = Array.from(
@@ -643,20 +638,20 @@ function initStyleSheetObserver(
const supportedNestedCSSRuleTypes: {
[key: string]: GroupingCSSRuleTypes;
} = {};
if (isCSSGroupingRuleSupported) {
if (canMonkeyPatchNestedCSSRule('CSSGroupingRule')) {
supportedNestedCSSRuleTypes.CSSGroupingRule = win.CSSGroupingRule;
} else {
// Some browsers (Safari) don't support CSSGroupingRule
// https://caniuse.com/?search=cssgroupingrule
// fall back to monkey patching classes that would have inherited from CSSGroupingRule
if (isCSSMediaRuleSupported) {
if (canMonkeyPatchNestedCSSRule('CSSMediaRule')) {
supportedNestedCSSRuleTypes.CSSMediaRule = win.CSSMediaRule;
}
if (isCSSConditionRuleSupported) {
if (canMonkeyPatchNestedCSSRule('CSSConditionRule')) {
supportedNestedCSSRuleTypes.CSSConditionRule = win.CSSConditionRule;
}
if (isCSSSupportsRuleSupported) {
if (canMonkeyPatchNestedCSSRule('CSSSupportsRule')) {
supportedNestedCSSRuleTypes.CSSSupportsRule = win.CSSSupportsRule;
}
}
@@ -1168,3 +1163,24 @@ export function initObservers(
pluginHandlers.forEach((h) => h());
};
}
type CSSGroupingProp =
| 'CSSGroupingRule'
| 'CSSMediaRule'
| 'CSSSupportsRule'
| 'CSSConditionRule';
function hasNestedCSSRule(prop: CSSGroupingProp): boolean {
return typeof window[prop] !== 'undefined';
}
function canMonkeyPatchNestedCSSRule(prop: CSSGroupingProp): boolean {
return Boolean(
typeof window[prop] !== 'undefined' &&
// Note: Generally, this check _shouldn't_ be necessary
// However, in some scenarios (e.g. jsdom) this can sometimes fail, so we check for it here
window[prop].prototype &&
'insertRule' in window[prop].prototype &&
'deleteRule' in window[prop].prototype,
);
}