Skip to content

Conversation

@thecrypticace
Copy link
Contributor

@thecrypticace thecrypticace commented Dec 3, 2025

This will be used to improve performance and potentially enable future features that require generated CSS source locations.

Note: This is still 100% internal API. You can only access this via __unstable__loadDesignSystem for a reason. We may chance the structure of the arguments and/or return values as needed.

This will be used to help speed up AST conversions significantly
@thecrypticace thecrypticace requested a review from a team as a code owner December 3, 2025 23:56
@coderabbitai
Copy link

coderabbitai bot commented Dec 4, 2025

Walkthrough

The design-system module now exposes a new public method candidatesToAst(classes: string[]): AstNode[][] and the buildDesignSystem(theme, utilitiesSrc?) factory accepts an optional utilitiesSrc (source location) argument. Internal helpers candidatesToAst and candidatesToCss were added and the returned DesignSystem exposes both. The index module now passes utilitiesNode?.src into buildDesignSystem during parseCss() and preserves source location when parsing CSS via CSS.parse(css, { from: opts.from }). Tests were updated to exercise the AST output and fix parsing typos.

Pre-merge checks

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Expose candidatesToAst to the language server' clearly and directly describes the main change - exposing a new AST function to the language server, matching the PR objectives.
Description check ✅ Passed The description explains the purpose of the changes (performance improvement and enabling future features with source locations) and notes the API is internal, relating to the changeset.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4cee91 and 5a36b3c.

📒 Files selected for processing (3)
  • packages/tailwindcss/src/design-system.ts (5 hunks)
  • packages/tailwindcss/src/index.ts (2 hunks)
  • packages/tailwindcss/src/intellisense.test.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
packages/tailwindcss/src/design-system.ts (4)
packages/tailwindcss/src/ast.ts (2)
  • AstNode (68-68)
  • optimizeAst (220-672)
packages/tailwindcss/src/source-maps/source.ts (1)
  • SourceLocation (27-27)
packages/tailwindcss/src/compile.ts (1)
  • compileCandidates (11-121)
packages/tailwindcss/src/walk.ts (1)
  • WalkAction (10-20)
packages/tailwindcss/src/index.ts (1)
packages/tailwindcss/src/design-system.ts (1)
  • buildDesignSystem (70-255)
packages/tailwindcss/src/intellisense.test.ts (1)
packages/tailwindcss/src/ast.ts (2)
  • rule (87-93)
  • decl (95-102)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Linux / cli
  • GitHub Check: Linux / postcss
  • GitHub Check: Linux / vite
  • GitHub Check: Linux / upgrade
  • GitHub Check: Linux
🔇 Additional comments (12)
packages/tailwindcss/src/design-system.ts (6)

2-2: LGTM!

The new imports for AstNode, SourceLocation, WalkAction, and walk are appropriate for the new candidatesToAst functionality.

Also applies to: 22-22, 28-28


64-64: LGTM!

The type extension is consistent with the implementation and follows the existing pattern for candidatesToCss.


70-73: LGTM!

The optional utilitiesSrc parameter cleanly extends the factory signature while maintaining backward compatibility.


118-148: Mutating cached AST nodes with node.src ??= utilitiesSrc.

The walk callback mutates node.src on cached AST nodes returned by compileCandidates. While the comment on lines 132-135 explains this is safe because the cache is destroyed on rebuild, this relies on an implicit invariant that consumers don't reuse nodes across rebuilds.

This is fine for the current IntelliSense use case, but consider documenting this mutation behavior in the function's JSDoc if this API becomes more widely used.


150-154: LGTM!

Refactoring candidatesToCss to derive from candidatesToAst ensures consistency between CSS and AST outputs. The mapping logic is clean and correct.


164-165: LGTM!

Both functions are correctly exposed on the DesignSystem object, maintaining the public API contract.

packages/tailwindcss/src/intellisense.test.ts (4)

3-3: LGTM!

The import of decl and rule from ./ast is necessary for constructing expected AST nodes in the new test.


169-187: LGTM!

The test comprehensively validates candidatesToAst behavior:

  • Valid candidates return proper AST structures
  • Non-existent candidates return empty arrays
  • Explicitly invalidated candidates (bg-[#fff]) return empty arrays
  • Escaped selectors (.bg-\\[\\#000\\]) are correctly handled

This mirrors the existing candidatesToCss test for consistency.


262-262: Good catch on the typo fix.

Removed the extraneous l character after the plugin path string.


299-299: Good catch on the typo fix.

Removed the extraneous l character after the plugin path string.

packages/tailwindcss/src/index.ts (2)

598-598: LGTM!

Passing utilitiesNode?.src to buildDesignSystem enables source location tracking for generated utility CSS. The optional chaining correctly handles cases where utilitiesNode may be null.


858-858: LGTM!

Adding { from: opts.from } to CSS.parse ensures source locations are preserved when loading design systems, which is essential for the new candidatesToAst functionality to provide accurate source mapping.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/tailwindcss/src/design-system.ts (1)

114-151: candidatesToAst/candidatesToCss behavior aligns with the compilation pipeline; consider deduplicating src-propagation logic

The per-class compileCandidates call, invalid-candidate guard (wasValid + empty array), optional utilitiesNode.src propagation via walk, and use of optimizeAst(…, Polyfills.None) give you a clean, source-aware AST tailored for IntelliSense, and reusing it in candidatesToCss avoids double work. One small polish opportunity: the walk(…, node.src ??= utilitiesNode.src) pattern is now duplicated here and in compileAst.build in index.ts; factoring this into a shared helper (e.g., attachUtilitySources(astNodes, utilitiesNode)) would keep source-location behavior in one place.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a92fa97 and a4cee91.

📒 Files selected for processing (2)
  • packages/tailwindcss/src/design-system.ts (5 hunks)
  • packages/tailwindcss/src/index.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/tailwindcss/src/index.ts (1)
packages/tailwindcss/src/design-system.ts (1)
  • buildDesignSystem (69-251)
packages/tailwindcss/src/design-system.ts (3)
packages/tailwindcss/src/ast.ts (3)
  • AstNode (68-68)
  • optimizeAst (220-672)
  • toCss (674-879)
packages/tailwindcss/src/walk.ts (1)
  • WalkAction (10-20)
packages/tailwindcss/src/value-parser.ts (1)
  • toCss (41-56)
🔇 Additional comments (4)
packages/tailwindcss/src/design-system.ts (2)

2-2: Imports for AST typing and walking are appropriate

Pulling in type AstNode from ./ast and WalkAction/walk from ./walk matches the new usage in candidatesToAst and keeps types explicit without affecting runtime behavior. No issues here.

Also applies to: 27-27


61-67: DesignSystem API extension and buildDesignSystem signature look correct

Adding candidatesToAst(classes: string[]): AstNode[][] to DesignSystem and wiring it (plus the refactored candidatesToCss) into the returned designSystem object is consistent with the stated IntelliSense use case. Making utilitiesNode an optional parameter on buildDesignSystem keeps the call sites backwards compatible while enabling source-aware behavior when it is provided.

Also applies to: 69-72, 160-162

packages/tailwindcss/src/index.ts (2)

598-605: Passing utilitiesNode into buildDesignSystem is consistent with the new AST APIs

Feeding utilitiesNode into buildDesignSystem(theme, utilitiesNode) nicely connects the parse phase to the new candidatesToAst logic that reuses utilitiesNode.src for generated utility nodes. This keeps the source-location handling centralized in the design system without changing behavior for callers that don’t use @tailwind utilities (where utilitiesNode is null).


829-844: Using CSS.parse with { from: opts.from } correctly enables source tracking for both compile and __unstable__loadDesignSystem

Parsing with CSS.parse(css, { from: opts.from }) in both compile and __unstable__loadDesignSystem aligns the AST’s src information with the caller-provided filename and matches the later use of toCss(newAst, !!opts.from) and utilitiesNode.src in downstream code. This is a straightforward, backwards-compatible improvement for source maps and language-server consumers.

Also applies to: 858-859

@thecrypticace thecrypticace force-pushed the feat/intellisense-sourcemaps branch from a4cee91 to 5a36b3c Compare December 8, 2025 15:14
@thecrypticace thecrypticace merged commit 820d907 into main Dec 8, 2025
7 checks passed
@thecrypticace thecrypticace deleted the feat/intellisense-sourcemaps branch December 8, 2025 15:54
thecrypticace added a commit to tailwindlabs/tailwindcss-intellisense that referenced this pull request Dec 8, 2025
Companion PR to tailwindlabs/tailwindcss#19405

The aim of this PR is to improve the performance around looking up /
compiling candidates into utilities when using v4.

It does this in three stages:

1. For earlier versions (v4.0–v4.1.17) we swap out PostCSS (mostly) with
our own CSS parser. The implementation is tailored to improve
performance and memory usage for how we use it. This also means I've
been able to optimize how we walk the AST and remove mutations in many
places.

There *are* still some internal APIs that use PostCSS because they
interface with multiple versions of Tailwind CSS. These still use
PostCSS and we translate our AST into a PostCSS AST for these cases.
Eventually these APIs will also be converted to use our internal CSS AST
directly — we'll support old versions by converting *from PostCSS* to
our internal AST — that is for a future PR.

2. For new enough versions, since our AST here mirrors the one in
Tailwind CSS, we can use the nodes directly from Tailwind CSS itself
instead of generating the code inside Tailwind CSS, serializing to a
string, and then finally re-parsing. This is exactly what the
`candidatesToAst` API enables (will ship in Tailwind CSS v4.1.18).

3. A large portion of the candidate compiling perf is spent on color
lookups. The above will help with that significantly but there's still a
large amount of time analyzing declaration values for colors. This PR
replaces our unwieldy color regex to pick out potential colors with a
fine tuned parser.

This speedup gives us a good bit more headroom for re-enabling mask
utility color swatches. The overhead from parsing an extra 5k utilities
is still too significant but it is now *much* lower than before. The
next big improvements will need to happen in core.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants