diff --git a/packages/tailwindcss-language-server/src/util/v4/design-system.ts b/packages/tailwindcss-language-server/src/util/v4/design-system.ts index f312b95c..b7bf8daf 100644 --- a/packages/tailwindcss-language-server/src/util/v4/design-system.ts +++ b/packages/tailwindcss-language-server/src/util/v4/design-system.ts @@ -13,6 +13,7 @@ import { plugins } from './plugins' const HAS_V4_IMPORT = /@import\s*(?:'tailwindcss'|"tailwindcss")/ const HAS_V4_THEME = /@theme\s*\{/ +const COMPILE_CACHE = Symbol('LSP_COMPILE_CACHE') export async function isMaybeV4(css: string): Promise { // Look for: @@ -215,6 +216,11 @@ export async function loadDesignSystem( }), }) + // This object doesn't exist in older versions but we can patch it in so it + // seems like it always existed. + design.storage ??= {} + design.storage[COMPILE_CACHE] = {} + // Step 4: Augment the design system with some additional APIs that the LSP needs Object.assign(design, { dependencies: () => dependencies, @@ -227,25 +233,42 @@ export async function loadDesignSystem( // - Replace `candidatesToCss` with a `candidatesToAst` API // First step would be to convert to a PostCSS AST by transforming the nodes directly // Then it would be to drop the PostCSS AST representation entirely in all v4 code paths - compile(classes: string[]): (postcss.Root | null)[] { - let css = design.candidatesToCss(classes) + compile(classes: string[]): postcss.Root[] { + // 1. Compile any uncached classes + let cache = design.storage[COMPILE_CACHE] as Record + let uncached = classes.filter((name) => cache[name] === undefined) + + let css = design.candidatesToCss(uncached) let errors: any[] = [] - let roots = css.map((str) => { - if (str === null) return postcss.root() + for (let [idx, cls] of uncached.entries()) { + let str = css[idx] + + if (str === null) { + cache[cls] = postcss.root() + continue + } try { - return postcss.parse(str.trimEnd()) + cache[cls] = postcss.parse(str.trimEnd()) } catch (err) { errors.push(err) - return postcss.root() + cache[cls] = postcss.root() + continue } - }) + } if (errors.length > 0) { console.error(JSON.stringify(errors)) } + // 2. Pull all the classes from the cache + let roots: postcss.Root[] = [] + + for (let cls of classes) { + roots.push(cache[cls].clone()) + } + return roots }, diff --git a/packages/tailwindcss-language-service/src/util/find.ts b/packages/tailwindcss-language-service/src/util/find.ts index 1bd51cfa..ab1df1f6 100644 --- a/packages/tailwindcss-language-service/src/util/find.ts +++ b/packages/tailwindcss-language-service/src/util/find.ts @@ -1,4 +1,4 @@ -import type { Range, Position } from 'vscode-languageserver' +import { type Range, type Position, LRUCache } from 'vscode-languageserver' import type { TextDocument } from 'vscode-languageserver-textdocument' import type { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state' import lineColumn from 'line-column' @@ -591,8 +591,20 @@ export function findHelperFunctionsInRange( return fns } +let lineTableCache = new LRUCache>(20) + +function createLineTable(str: string) { + let existing = lineTableCache.get(str) + if (existing) return existing + + let table = lineColumn(str + '\n') + lineTableCache.set(str, table) + return table +} + export function indexToPosition(str: string, index: number): Position { - const { line, col } = lineColumn(str + '\n').fromIndex(index) ?? { line: 1, col: 1 } + let table = createLineTable(str) + let { line, col } = table.fromIndex(index) ?? { line: 1, col: 1 } return { line: line - 1, character: col - 1 } } diff --git a/packages/tailwindcss-language-service/src/util/v4/design-system.ts b/packages/tailwindcss-language-service/src/util/v4/design-system.ts index 2ddcc2b3..2e00d8ce 100644 --- a/packages/tailwindcss-language-service/src/util/v4/design-system.ts +++ b/packages/tailwindcss-language-service/src/util/v4/design-system.ts @@ -50,6 +50,10 @@ export interface DesignSystem { // Added in v4.1.15 canonicalizeCandidates?(classes: string[], options?: CanonicalizeOptions): string[] + + // Added in v4.1.16 + // We can patch it into any design system if it doesn't exist though + storage?: Record } export interface DesignSystem { diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index d8c536d0..d817fbb7 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -3,6 +3,7 @@ ## Prerelease - Add a source to all emitted diagnostics ([#1491](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1491)) +- Improve performance in large files ([#1507](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1507)) ## 0.14.29