From 4e31ae1f8e8793080f4fd6e4e06cd2fa6e36928e Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 23 Apr 2025 13:38:51 -0400 Subject: [PATCH 1/4] Start server once we know any workspace folder needs it --- packages/vscode-tailwindcss/src/analyze.ts | 82 ++++++++++++++-------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/packages/vscode-tailwindcss/src/analyze.ts b/packages/vscode-tailwindcss/src/analyze.ts index ec9b2b9a..f45c7a46 100644 --- a/packages/vscode-tailwindcss/src/analyze.ts +++ b/packages/vscode-tailwindcss/src/analyze.ts @@ -29,33 +29,53 @@ export async function anyWorkspaceFoldersNeedServer({ folders, token }: SearchOp if (typeof configFilePath === 'object' && Object.values(configFilePath).length > 0) return true } - let configs: Array<() => Thenable> = [] - let stylesheets: Array<() => Thenable> = [] + // If any search returns that it needs a workspace then the server needs to be started + // and the remainder of the searches will be cancelled + let searches = folders.map((folder) => + workspaceFoldersNeedServer({ folder, token }).then((found) => { + if (found) return true - for (let folder of folders) { - let exclusions = getExcludePatterns(folder).flatMap((pattern) => braces.expand(pattern)) - let exclude = `{${exclusions.join(',').replace(/{/g, '%7B').replace(/}/g, '%7D')}}` - - configs.push(() => - workspace.findFiles( - new RelativePattern(folder, `**/${CONFIG_GLOB}`), - exclude, - undefined, - token, - ), - ) - - stylesheets.push(() => - workspace.findFiles(new RelativePattern(folder, `**/${CSS_GLOB}`), exclude, undefined, token), - ) + // We use `throw` so we can use Promise.any(…) + throw new Error(DUMMY_ERROR_MESSAGE) + }), + ) + + const DUMMY_ERROR_MESSAGE = 'Workspace folder not needed' + + try { + return await Promise.any(searches) + } catch (err) { + for (let anErr of (err as AggregateError).errors ?? []) { + if (typeof anErr === 'object' && err.message === DUMMY_ERROR_MESSAGE) { + continue + } + + console.error(anErr) + } + + return false } +} + +export interface FolderSearchOptions { + folder: WorkspaceFolder + token: CancellationToken +} + +async function workspaceFoldersNeedServer({ folder, token }: FolderSearchOptions) { + let exclusions = getExcludePatterns(folder).flatMap((pattern) => braces.expand(pattern)) + let exclude = `{${exclusions.join(',').replace(/{/g, '%7B').replace(/}/g, '%7D')}}` // If we find a config file then we need the server - let configUrls = await Promise.all(configs.map((fn) => fn())) - for (let group of configUrls) { - if (group.length > 0) { - return true - } + let configs = await workspace.findFiles( + new RelativePattern(folder, `**/${CONFIG_GLOB}`), + exclude, + undefined, + token, + ) + + if (configs.length > 0) { + return true } // If we find a possibly-related stylesheet then we need the server @@ -65,12 +85,16 @@ export async function anyWorkspaceFoldersNeedServer({ folders, token }: SearchOp // This is also, unfortunately, prone to starting the server unncessarily // in projects that don't use TailwindCSS so we do this one-by-one instead // of all at once to keep disk I/O low. - let stylesheetUrls = await Promise.all(stylesheets.map((fn) => fn())) - for (let group of stylesheetUrls) { - for (let file of group) { - if (await fileMayBeTailwindRelated(file)) { - return true - } + let stylesheets = await workspace.findFiles( + new RelativePattern(folder, `**/${CSS_GLOB}`), + exclude, + undefined, + token, + ) + + for (let file of stylesheets) { + if (await fileMayBeTailwindRelated(file)) { + return true } } } From d44b014485bf58c207e0621f4742d044c32b1f4c Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 23 Apr 2025 13:39:17 -0400 Subject: [PATCH 2/4] Cancel remaining workspace searches once we know a server is needed --- packages/vscode-tailwindcss/src/api.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/vscode-tailwindcss/src/api.ts b/packages/vscode-tailwindcss/src/api.ts index d7f67de6..7be69aa1 100644 --- a/packages/vscode-tailwindcss/src/api.ts +++ b/packages/vscode-tailwindcss/src/api.ts @@ -11,11 +11,13 @@ export async function createApi({ context, outputChannel }: ApiOptions) { async function workspaceNeedsLanguageServer() { if (folderAnalysis) return folderAnalysis + let found = false let source: CancellationTokenSource | null = new CancellationTokenSource() source.token.onCancellationRequested(() => { source?.dispose() source = null + if (found) return outputChannel.appendLine( 'Server was not started. Search for Tailwind CSS-related files was taking too long.', @@ -32,7 +34,8 @@ export async function createApi({ context, outputChannel }: ApiOptions) { }) let result = await folderAnalysis - source?.dispose() + found = true + source?.cancel() return result } From 05f3d509db32998800ae1023a9e09472392cf696 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 23 Apr 2025 13:48:30 -0400 Subject: [PATCH 3/4] =?UTF-8?q?Don=E2=80=99t=20start=20language=20server?= =?UTF-8?q?=20for=20preprocessor=20files=20with=20`@import`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/vscode-tailwindcss/src/analyze.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/vscode-tailwindcss/src/analyze.ts b/packages/vscode-tailwindcss/src/analyze.ts index f45c7a46..1f5c4de0 100644 --- a/packages/vscode-tailwindcss/src/analyze.ts +++ b/packages/vscode-tailwindcss/src/analyze.ts @@ -108,10 +108,19 @@ export async function fileMayBeTailwindRelated(uri: Uri) { let buffer = await workspace.fs.readFile(uri) let contents = buffer.toString() - return ( - HAS_CONFIG.test(contents) || - HAS_IMPORT.test(contents) || - HAS_TAILWIND.test(contents) || - HAS_THEME.test(contents) - ) + // This is a clear signal that this is Tailwind related in v0–v4 + if (HAS_CONFIG.test(contents)) return true + + if (uri.path.endsWith('.css')) { + // In v4 these are Tailwind related *in .css files only* + // other stylesheets like lesss, stylus, etc… don't consider these files + if (HAS_THEME.test(contents)) return true + if (HAS_TAILWIND.test(contents)) return true + + // @import *might* signal the need for the language server we'll have to + // start it, let it check, and hope we were right. + if (HAS_IMPORT.test(contents)) return true + } + + return false } From 3737a963004fbb597169742f3c9ddf5a73b28a7f Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 9 May 2025 18:55:42 -0400 Subject: [PATCH 4/4] Update changelog --- packages/vscode-tailwindcss/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index e57ef565..6d2dbfab 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -6,6 +6,8 @@ - Ignore Python virtual env directories by default ([#1336](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1336)) - Ignore Yarn v2+ metadata & cache directories by default ([#1336](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1336)) - Ignore some build caches by default ([#1336](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1336)) +- Boot langauage server quicker in multi-root workspaces ([#1334](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1334)) +- Don't start language server if we only see `@import` in preprocessor files ([#1334](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1334)) # 0.14.16