Skip to content

Commit 487121a

Browse files
committed
#136: Speed up tailwindcss/classnames-order with officialSorting: true
Using chrome://inspect/, I found that the `createContext` function from the Tailwind API took a lot of time to execute. It turned out that this function was called more than only a few times, so I have optimized this by adding a cache. The cache uses a `WeakMap`, storing a `contextFallback` 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. Interestingly enough, the time to execute the `create` function for an ESLint rule is not included in the time reported by `TIMING=1`, as can be seen in the details below. However, on my codebase (which I can't share, unfortunately), this roughly halves the total runtime of the `eslint .` command when using only `tailwindcss/*` rules. Details of the run time: Commands executed: ``` $ TIMING=1 node --inspect ./node_modules/.bin/eslint . $ time node --inspect ./node_modules/.bin/eslint . ``` Before this commit: ``` Rule | Time (ms) | Relative :----------------------------------------------|----------:|--------: tailwindcss/no-custom-classname | 491.130 | 32.6% tailwindcss/enforces-shorthand | 483.797 | 32.1% tailwindcss/no-contradicting-classname | 293.046 | 19.4% tailwindcss/classnames-order | 206.097 | 13.7% tailwindcss/migration-from-tailwind-2 | 16.470 | 1.1% tailwindcss/enforces-negative-arbitrary-values | 16.250 | 1.1% ``` After this commit: ``` Rule | Time (ms) | Relative :----------------------------------------------|----------:|--------: tailwindcss/no-custom-classname | 482.266 | 34.0% tailwindcss/enforces-shorthand | 434.553 | 30.6% tailwindcss/no-contradicting-classname | 276.010 | 19.5% tailwindcss/classnames-order | 180.044 | 12.7% tailwindcss/migration-from-tailwind-2 | 24.113 | 1.7% tailwindcss/enforces-negative-arbitrary-values | 20.486 | 1.4% ``` Note that the timings above are single runs, not averages. Repeated runs show that the _reported_ time for `classnames-order` does not change significantly. However, the output of `time` shows a different picture: before this commit, the `wall` time is 19s and the `user` time is 30s; after this commit, the `wall` time is 10s and the `user` time is 17s. These timings are averaged over 5 runs. 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 } } } ```
1 parent 33d513a commit 487121a

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

lib/rules/classnames-order.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const createContextFallback = require('tailwindcss/lib/lib/setupContextUtils').c
2222
// messageId will still be usable in tests.
2323
const INVALID_CLASSNAMES_ORDER_MSG = 'Invalid Tailwind CSS classnames order';
2424

25+
const contextFallbackCache = new WeakMap();
26+
2527
module.exports = {
2628
meta: {
2729
docs: {
@@ -88,7 +90,14 @@ module.exports = {
8890
const removeDuplicates = getOption(context, 'removeDuplicates');
8991

9092
const mergedConfig = customConfig.resolve(twConfig);
91-
const contextFallback = officialSorting ? createContextFallback(mergedConfig) : null;
93+
const contextFallback = officialSorting
94+
? (
95+
// Set the created contextFallback in the cache if it does not exist yet.
96+
contextFallbackCache.has(mergedConfig)
97+
? contextFallbackCache
98+
: contextFallbackCache.set(mergedConfig, createContextFallback(mergedConfig))
99+
).get(mergedConfig)
100+
: null;
92101

93102
//----------------------------------------------------------------------
94103
// Helpers

0 commit comments

Comments
 (0)