Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
#136: Speed up tailwindcss/enforces-shorthand
Using chrome://inspect/, I found that the `patchRegex` function took a
lot of time to calculate. It looked like it was often called with the
same parameters, which I have optimized by adding a cache.

The cache uses a `WeakMap`, storing a plain string-to-string object for
every `config` object that is passed to `patchRegex`. I chose to use
`WeakMap` here because the Tailwind CSS config object may change over
time (see lib/util/customConfig.js), and this allows the garbage
collector to clean the cache when an old config is no longer used.

On my codebase (which I can't share, unfortunately), this greatly
reduces the run time of the `tailwindcss/enforces-shorthand` rule.

Details of the run time:

Command executed:
```
$ TIMING=1 node --inspect ./node_modules/.bin/eslint .
```

Before this commit:
```
Rule                                           | Time (ms) | Relative
:----------------------------------------------|----------:|--------:
tailwindcss/enforces-shorthand                 |  2444.777 |    70.0%
tailwindcss/no-custom-classname                |   487.850 |    14.0%
tailwindcss/no-contradicting-classname         |   289.491 |     8.3%
tailwindcss/classnames-order                   |   229.961 |     6.6%
tailwindcss/migration-from-tailwind-2          |    20.250 |     0.6%
tailwindcss/enforces-negative-arbitrary-values |    17.669 |     0.5%
```

After this commit:
```
Rule                                           | Time (ms) | Relative
:----------------------------------------------|----------:|--------:
tailwindcss/enforces-shorthand                 |   564.097 |    32.8%
tailwindcss/no-custom-classname                |   531.374 |    30.9%
tailwindcss/no-contradicting-classname         |   341.007 |    19.8%
tailwindcss/classnames-order                   |   238.749 |    13.9%
tailwindcss/enforces-negative-arbitrary-values |    22.539 |     1.3%
tailwindcss/migration-from-tailwind-2          |    20.349 |     1.2%
```

Note that the timings above are single runs, not averages, but repeated
runs show a similar pattern.

ESLint config used (which, for testing, I have adapted in such a way
that _only_ the `tailwindcss/*` rules are executed):
```
{
  "env": {"browser": true, "es2020": true, "node": true},
  "extends": ["plugin:tailwindcss/recommended"],
  "overrides": [{"files": ["*.ts", "*.tsx"]}],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {"jsx": true},
    "sourceType": "module"
  },
  "plugins": ["react", "@typescript-eslint"],
  "settings": {
    "react": {"version": "detect"},
    "tailwindcss": {
      "cssFiles": ["src/**/*.css"],
      "officialSorting": true
    }
  }
}
```
  • Loading branch information
mpsijm committed Jun 1, 2022
commit 33d513af1d9986505d2f5320d13ea0c677690800
15 changes: 12 additions & 3 deletions lib/util/groupMethods.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,23 @@ function generateOptions(propName, keys, config, isNegative = false) {
}
}

const cachedRegexes = new WeakMap();

/**
* Customize the regex based on config
*
* @param {String} re Regular expression
* @param {Object} config The merged Tailwind CSS config
* @returns {String} Patched version with config values and additinal parameters
* @returns {String} Patched version with config values and additional parameters
*/
function patchRegex(re, config) {
if (!cachedRegexes.has(config)) {
cachedRegexes.set(config, {});
}
const cache = cachedRegexes.get(config);
if (re in cache) {
return cache[re];
}
let patched = '\\!?';
// Prefix
if (config.prefix.length) {
Expand All @@ -281,7 +290,7 @@ function patchRegex(re, config) {
const resArray = [...res];
const props = resArray.map((arr) => arr[1]);
if (props.length === 0) {
return `${patched}(${replaced})`;
return cache[re] = `${patched}(${replaced})`;
}
// e.g. backgroundColor, letterSpacing, -margin...
props.forEach((prop) => {
Expand Down Expand Up @@ -336,7 +345,7 @@ function patchRegex(re, config) {
const opts = generateOptions(absoluteProp, keys, config, isNegative);
replaced = replaced.replace(token, opts);
});
return `${patched}(${replaced})`;
return cache[re] = `${patched}(${replaced})`;
}

/**
Expand Down