Skip to content

Commit 00e0779

Browse files
Improve performance of control comments in postcss-custom-properties (#737)
* Improve performance of control comments in postcss-custom-properties Co-authored-by: Marvin Hagemeister <hello@marvinh.dev> * fix Co-authored-by: Marvin Hagemeister <hello@marvinh.dev>
1 parent 3d8231f commit 00e0779

File tree

4 files changed

+53
-22
lines changed

4 files changed

+53
-22
lines changed

plugins/postcss-custom-properties/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changes to PostCSS Custom Properties
22

3+
### Unreleased
4+
5+
- Improve plugin performance
6+
37
### 12.1.10 (October 20, 2022)
48

59
- Fix how `preserve: false` interacts with logic around duplicate code (see `12.1.9`).

plugins/postcss-custom-properties/src/lib/get-custom-properties-from-root.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import valuesParser from 'postcss-value-parser';
2-
import { isBlockIgnored } from './is-ignored';
2+
import { isBlockIgnored, isDeclarationIgnored } from './is-ignored';
33

44
// return custom selectors from the css root, conditionally removing them
55
export default function getCustomPropertiesFromRoot(root, opts): Map<string, valuesParser.ParsedValue> {
66
// initialize custom selectors
7-
const customPropertiesFromHtmlElement: Map<string, valuesParser.ParsedValue> = new Map();
8-
const customPropertiesFromRootPseudo: Map<string, valuesParser.ParsedValue> = new Map();
9-
const out: Map<string, valuesParser.ParsedValue> = new Map();
7+
const customPropertiesFromHtmlElement: Map<string, string> = new Map();
8+
const customPropertiesFromRootPseudo: Map<string, string> = new Map();
109

1110
// for each html or :root rule
1211
root.nodes.slice().forEach(rule => {
12+
if (isBlockIgnored(rule)) {
13+
return;
14+
}
15+
1316
const customPropertiesObject = isHtmlRule(rule)
1417
? customPropertiesFromHtmlElement
1518
: isRootRule(rule)
@@ -19,11 +22,11 @@ export default function getCustomPropertiesFromRoot(root, opts): Map<string, val
1922
// for each custom property
2023
if (customPropertiesObject) {
2124
rule.nodes.slice().forEach(decl => {
22-
if (decl.variable && !isBlockIgnored(decl)) {
25+
if (decl.variable && !isDeclarationIgnored(decl)) {
2326
const { prop } = decl;
2427

2528
// write the parsed value to the custom property
26-
customPropertiesObject.set(prop, valuesParser(decl.value));
29+
customPropertiesObject.set(prop, decl.value);
2730

2831
// conditionally remove the custom property declaration
2932
if (!opts.preserve) {
@@ -33,18 +36,19 @@ export default function getCustomPropertiesFromRoot(root, opts): Map<string, val
3336
});
3437

3538
// conditionally remove the empty html or :root rule
36-
if (!opts.preserve && isEmptyParent(rule) && !isBlockIgnored(rule)) {
39+
if (!opts.preserve && isEmptyParent(rule)) {
3740
rule.remove();
3841
}
3942
}
4043
});
4144

45+
const out: Map<string, valuesParser.ParsedValue> = new Map();
4246
for (const [name, value] of customPropertiesFromHtmlElement.entries()) {
43-
out.set(name, value);
47+
out.set(name, valuesParser(value));
4448
}
4549

4650
for (const [name, value] of customPropertiesFromRootPseudo.entries()) {
47-
out.set(name, value);
51+
out.set(name, valuesParser(value));
4852
}
4953

5054
// return all custom properties, preferring :root properties over html properties
Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,43 @@
1-
function isBlockIgnored(ruleOrDeclaration) {
2-
const rule = ruleOrDeclaration.selector ?
3-
ruleOrDeclaration : ruleOrDeclaration.parent;
1+
import type { Comment, Container, Declaration, Node } from 'postcss';
42

5-
return /(!\s*)?postcss-custom-properties:\s*off\b/i.test(rule.toString());
3+
const blockRegExp = /(!\s*)?postcss-custom-properties:\s*off\b/i;
4+
5+
const blockIgnoredCache = new WeakMap();
6+
7+
function isBlockIgnored(container: Container) {
8+
if (!container || !container.nodes) {
9+
return false;
10+
}
11+
12+
if (blockIgnoredCache.has(container)) {
13+
return blockIgnoredCache.get(container);
14+
}
15+
16+
const result = container.some((child) => isIgnoreComment(child, blockRegExp));
17+
blockIgnoredCache.set(container, result);
18+
19+
return result;
620
}
721

8-
function isRuleIgnored(rule) {
9-
const previous = rule.prev();
22+
const declarationRegExp = /(!\s*)?postcss-custom-properties:\s*ignore\s+next\b/i;
23+
24+
function isDeclarationIgnored(decl: Declaration) {
25+
if (!decl) {
26+
return false;
27+
}
28+
29+
if (isBlockIgnored(decl.parent)) {
30+
return true;
31+
}
32+
33+
return isIgnoreComment(decl.prev(), declarationRegExp);
34+
}
1035

11-
return Boolean(isBlockIgnored(rule) ||
12-
previous &&
13-
previous.type === 'comment' &&
14-
/(!\s*)?postcss-custom-properties:\s*ignore\s+next\b/i.test(previous.text));
36+
function isIgnoreComment(node: Node, regexp: RegExp) {
37+
return node && node.type === 'comment' && regexp.test((node as Comment).text);
1538
}
1639

1740
export {
1841
isBlockIgnored,
19-
isRuleIgnored,
42+
isDeclarationIgnored,
2043
};

plugins/postcss-custom-properties/src/lib/transform-properties.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import valuesParser from 'postcss-value-parser';
22
import transformValueAST from './transform-value-ast';
3-
import { isRuleIgnored } from './is-ignored';
43
import { Declaration } from 'postcss';
4+
import { isDeclarationIgnored } from './is-ignored';
55

66
// transform custom pseudo selectors with custom selectors
77
export default (decl, customProperties, opts) => {
8-
if (isTransformableDecl(decl) && !isRuleIgnored(decl)) {
8+
if (isTransformableDecl(decl) && !isDeclarationIgnored(decl)) {
99
const originalValue = decl.value;
1010
const valueAST = valuesParser(originalValue);
1111
let value = transformValueAST(valueAST, customProperties);

0 commit comments

Comments
 (0)