Skip to content

Commit

Permalink
perf: Removed unneeded arrays created for media query scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
CatchABus committed Apr 30, 2024
1 parent 7aa7735 commit 6fdadee
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 51 deletions.
91 changes: 41 additions & 50 deletions packages/core/ui/styling/css-selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -974,22 +974,13 @@ interface SelectorMap {
[key: string]: SelectorCore[];
}

export class SelectorScope<T extends Node> implements LookupSorter {
export abstract class SelectorScope<T extends Node> implements LookupSorter {
private id: SelectorMap = {};
private class: SelectorMap = {};
private type: SelectorMap = {};
private universal: SelectorCore[] = [];

public position: number;

constructor(rulesets: RuleSet[], position: number) {
this.position = position;
this.lookupRulesets(rulesets);
}

protected lookupRulesets(rulesets: RuleSet[]) {
rulesets.forEach((ruleset) => ruleset.lookupSort(this));
}
public position: number = 0;

getSelectorCandidates(node: T) {
const { cssClasses, id, cssType } = node;
Expand Down Expand Up @@ -1033,8 +1024,8 @@ export class SelectorScope<T extends Node> implements LookupSorter {
export class MediaQuerySelectorScope<T extends Node> extends SelectorScope<T> {
private _mediaQueryString: string;

constructor(rulesets: RuleSet[], position: number, mediaQueryString: string) {
super(rulesets, position);
constructor(mediaQueryString: string) {
super();

this._mediaQueryString = mediaQueryString;
}
Expand All @@ -1045,59 +1036,57 @@ export class MediaQuerySelectorScope<T extends Node> extends SelectorScope<T> {
}

export class StyleSheetSelectorScope<T extends Node> extends SelectorScope<T> {
private mediaQuerySelectorGroups: MediaQuerySelectorScope<T>[];
private mediaQuerySelectorScopes: MediaQuerySelectorScope<T>[];

constructor(rulesets: RuleSet[]) {
super(rulesets, 0);
}
super();

private addMediaSelectorScope(mediaQueryString: string, rulesets: RuleSet[]) {
const selectorScope = new MediaQuerySelectorScope(rulesets, this.position, mediaQueryString);
this.lookupRulesets(rulesets);
}

// Update the position of current scope based on where the media query scope left off
this.position = selectorScope.position;
private createMediaQuerySelectorScope(mediaQueryString: string): MediaQuerySelectorScope<T> {
const selectorScope = new MediaQuerySelectorScope(mediaQueryString);
selectorScope.position = this.position;

if (!this.mediaQuerySelectorGroups) {
this.mediaQuerySelectorGroups = [];
if (this.mediaQuerySelectorScopes) {
this.mediaQuerySelectorScopes.push(selectorScope);
} else {
this.mediaQuerySelectorScopes = [selectorScope];
}
this.mediaQuerySelectorGroups.push(selectorScope);

return selectorScope;
}

protected lookupRulesets(rulesets: RuleSet[]) {
let currentMediaString: string;
let pendingMediaRulesets: RuleSet[];
private lookupRulesets(rulesets: RuleSet[]) {
let lastMediaSelectorScope: MediaQuerySelectorScope<T>;

rulesets.forEach((ruleset) => {
// Check if there are no more rulesets for the same media query and create the selector scope
if (currentMediaString && currentMediaString !== ruleset.mediaQueryString) {
// Initialization becomes inside iteration to maintain the correct selectors starting position and increment it appropriately
this.addMediaSelectorScope(currentMediaString, pendingMediaRulesets);

currentMediaString = null;
pendingMediaRulesets = null;
}
for (let i = 0, length = rulesets.length; i < length; i++) {
const ruleset = rulesets[i];

if (ruleset.mediaQueryString) {
// Store rulesets as they're needed for next selector scope instance
if (!currentMediaString) {
currentMediaString = ruleset.mediaQueryString;
pendingMediaRulesets = [ruleset];
// Create media query selector scope and register selector lookups there
if (!lastMediaSelectorScope) {
lastMediaSelectorScope = this.createMediaQuerySelectorScope(ruleset.mediaQueryString);
} else {
if (ruleset.mediaQueryString === currentMediaString) {
pendingMediaRulesets.push(ruleset);
if (lastMediaSelectorScope.mediaQueryString !== ruleset.mediaQueryString) {
// Once done with current media query scope, update stylesheet scope position
this.position = lastMediaSelectorScope.position;
lastMediaSelectorScope = null;
}
}
}

if (lastMediaSelectorScope) {
ruleset.lookupSort(lastMediaSelectorScope);
} else {
ruleset.lookupSort(this);
}
});

// There are still pending rulesets so it's time to create the final selector scope
if (currentMediaString) {
this.addMediaSelectorScope(currentMediaString, pendingMediaRulesets);
}

currentMediaString = null;
pendingMediaRulesets = null;
// If reference of last media selector scope is still kept, update stylesheet scope position
if (lastMediaSelectorScope) {
this.position = lastMediaSelectorScope.position;
lastMediaSelectorScope = null;
}
}

Expand All @@ -1106,12 +1095,14 @@ export class StyleSheetSelectorScope<T extends Node> extends SelectorScope<T> {
const selectors = this.getSelectorCandidates(node);

// Validate media queries and include their selectors if needed
if (this.mediaQuerySelectorGroups) {
if (this.mediaQuerySelectorScopes) {
// Cache media query results to avoid validations of other identical queries
const validatedMediaQueries: string[] = [];

for (const selectorScope of this.mediaQuerySelectorGroups) {
for (let i = 0, length = this.mediaQuerySelectorScopes.length; i < length; i++) {
const selectorScope = this.mediaQuerySelectorScopes[i];
const isMatchingAllQueries = matchMediaQueryString(selectorScope.mediaQueryString, validatedMediaQueries);

if (isMatchingAllQueries) {
const mediaQuerySelectors = selectorScope.getSelectorCandidates(node);
selectors.push(...mediaQuerySelectors);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/ui/styling/style-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ export class CssState {
const animations: kam.KeyframeAnimation[] = [];

matchingSelectors.forEach((selector) => {
const ruleAnimations: kam.KeyframeAnimationInfo[] = selector.ruleset[animationsSymbol];
const ruleAnimations: kam.KeyframeAnimationInfo[] = selector.ruleset?.[animationsSymbol];
if (ruleAnimations) {
ensureKeyframeAnimationModule();
for (const animationInfo of ruleAnimations) {
Expand Down

0 comments on commit 6fdadee

Please sign in to comment.