Skip to content

Commit 15d2792

Browse files
committed
cache properties and values per utility
Right now all plugins are implemented using functions so they are a literal black box. In a perfect world, we can leverage the ASTs from the `@utility` CSS plugins. To work around this, we use the `getClassList` Intellisense API, and pre-compute all utilities + modifiers (~19k total). This way we can consider each of them a "static" utility. Next, we index by property, value and list of utilities which is also cached in a bigger shared DefaultMap. This eventually produces: ```json { 'width': { '16px': ['w-4', 'size-4'], … }, 'height': { '16px': ['h-4', 'size-4'] }, … } ``` Later we can use these lookups to find the intersection between the used utilities. This means that if you are using `w-4 h-4`, that we can get `size-4` out of it.
1 parent 7526411 commit 15d2792

File tree

1 file changed

+52
-1
lines changed

1 file changed

+52
-1
lines changed

packages/tailwindcss/src/signatures.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { substituteAtApply } from './apply'
2-
import { atRule, styleRule, toCss, type AstNode } from './ast'
2+
import { atRule, cloneAstNode, styleRule, toCss, type AstNode } from './ast'
33
import { printArbitraryValue } from './candidate'
44
import { constantFoldDeclaration } from './constant-fold-declaration'
55
import { CompileAstFlags, type DesignSystem } from './design-system'
@@ -172,6 +172,8 @@ function canonicalizeAst(ast: AstNode[], options: SignatureOptions) {
172172
}
173173
},
174174
})
175+
176+
return ast
175177
}
176178

177179
// Resolve theme values to their inlined value.
@@ -279,6 +281,50 @@ function resolveVariablesInValue(value: string, designSystem: DesignSystem): str
279281
return value
280282
}
281283

284+
// Index all static utilities by property and value
285+
export const staticUtilitiesByPropertyAndValue = new DefaultMap((_optiones: SignatureOptions) => {
286+
return new DefaultMap((_property: string) => {
287+
return new DefaultMap((_value: string) => {
288+
return new Set<string>()
289+
})
290+
})
291+
})
292+
293+
export const computeUtilityProperties = new DefaultMap((options: SignatureOptions) => {
294+
return new DefaultMap((className) => {
295+
let localPropertyValueLookup = new DefaultMap((_property) => new Set<string>())
296+
let designSystem = options.designSystem
297+
298+
if (
299+
options.designSystem.theme.prefix &&
300+
!className.startsWith(options.designSystem.theme.prefix)
301+
) {
302+
className = `${options.designSystem.theme.prefix}:${className}`
303+
}
304+
let parsed = designSystem.parseCandidate(className)
305+
if (parsed.length === 0) return localPropertyValueLookup
306+
307+
walk(
308+
canonicalizeAst(
309+
designSystem.compileAstNodes(parsed[0]).map((x) => cloneAstNode(x.node)),
310+
options,
311+
),
312+
(node) => {
313+
if (node.kind === 'declaration') {
314+
localPropertyValueLookup.get(node.property).add(node.value!)
315+
staticUtilitiesByPropertyAndValue
316+
.get(options)
317+
.get(node.property)
318+
.get(node.value!)
319+
.add(className)
320+
}
321+
},
322+
)
323+
324+
return localPropertyValueLookup
325+
})
326+
})
327+
282328
// For all static utilities in the system, compute a lookup table that maps the
283329
// utility signature to the utility name. This is used to find the utility name
284330
// for a given utility signature.
@@ -291,6 +337,9 @@ export const preComputedUtilities = new DefaultMap((options: SignatureOptions) =
291337
let signatures = computeUtilitySignature.get(options)
292338
let lookup = new DefaultMap<string, string[]>(() => [])
293339

340+
// Right now all plugins are implemented using functions so they are a black
341+
// box. Let's use the `getClassList` and consider every known suggestion as a
342+
// static utility for now.
294343
for (let [className, meta] of designSystem.getClassList()) {
295344
let signature = signatures.get(className)
296345
if (typeof signature !== 'string') continue
@@ -306,6 +355,7 @@ export const preComputedUtilities = new DefaultMap((options: SignatureOptions) =
306355
}
307356

308357
lookup.get(signature).push(className)
358+
computeUtilityProperties.get(options).get(className)
309359

310360
for (let modifier of meta.modifiers) {
311361
// Modifiers representing numbers can be computed and don't need to be
@@ -319,6 +369,7 @@ export const preComputedUtilities = new DefaultMap((options: SignatureOptions) =
319369
let signature = signatures.get(classNameWithModifier)
320370
if (typeof signature !== 'string') continue
321371
lookup.get(signature).push(classNameWithModifier)
372+
computeUtilityProperties.get(options).get(classNameWithModifier)
322373
}
323374
}
324375

0 commit comments

Comments
 (0)