Skip to content

Commit 22438ce

Browse files
Clarify how the configFile option works with v4 (#1167)
This updates the readme to detail how the `tailwindCSS.experimental.configFile` option is meant to be used with v4. This PR *also* does two additional things: - Makes sure this works even with the bundled / fallback version of v4 - Adds tests verifying this behavior --------- Co-authored-by: Jonathan Reinink <[email protected]>
1 parent deec3cc commit 22438ce

File tree

5 files changed

+237
-12
lines changed

5 files changed

+237
-12
lines changed

packages/tailwindcss-language-server/src/project-locator.ts

+17-8
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,23 @@ export class ProjectLocator {
101101
configPath: string,
102102
selectors: string[],
103103
): Promise<ProjectConfig | null> {
104-
let config: ConfigEntry = {
105-
type: 'js',
106-
path: configPath,
107-
source: 'js',
108-
entries: [],
109-
content: [],
110-
packageRoot: '',
111-
}
104+
let config: ConfigEntry = configPath.endsWith('.css')
105+
? {
106+
type: 'css',
107+
path: configPath,
108+
source: 'css',
109+
entries: [],
110+
content: [],
111+
packageRoot: '',
112+
}
113+
: {
114+
type: 'js',
115+
path: configPath,
116+
source: 'js',
117+
entries: [],
118+
content: [],
119+
packageRoot: '',
120+
}
112121

113122
let tailwind = await this.detectTailwindVersion(config)
114123

packages/tailwindcss-language-server/tests/common.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -261,14 +261,16 @@ export async function init(
261261
text,
262262
lang = 'html',
263263
dir = '',
264+
name = null,
264265
settings = {},
265266
}: {
266267
text: string
267268
lang?: string
268269
dir?: string
270+
name?: string
269271
settings?: Settings
270272
}) {
271-
let uri = resolveUri(dir, `file-${counter++}`)
273+
let uri = resolveUri(dir, name ?? `file-${counter++}`)
272274
docSettings.set(uri, settings)
273275

274276
let openPromise = openingDocuments.remember(uri, () => {

packages/tailwindcss-language-server/tests/env/v4.test.js

+185
Original file line numberDiff line numberDiff line change
@@ -344,3 +344,188 @@ defineTest({
344344
})
345345
},
346346
})
347+
348+
defineTest({
349+
name: 'v4, using local, with explicit CSS entrypoints',
350+
fs: {
351+
'package.json': json`
352+
{
353+
"dependencies": {
354+
"tailwindcss": "4.0.1"
355+
}
356+
}
357+
`,
358+
'a/app.css': css`
359+
@import 'tailwindcss';
360+
@theme {
361+
--color-primary: #000000;
362+
}
363+
`,
364+
'b/app.css': css`
365+
@import 'tailwindcss';
366+
@theme {
367+
--color-primary: #ffffff;
368+
}
369+
`,
370+
},
371+
prepare: async ({ root }) => ({ c: await init(root) }),
372+
handle: async ({ c }) => {
373+
await c.updateSettings({
374+
tailwindCSS: {
375+
experimental: {
376+
configFile: {
377+
'a/app.css': 'c/a/**',
378+
'b/app.css': 'c/b/**',
379+
},
380+
},
381+
},
382+
})
383+
384+
let documentA = await c.openDocument({
385+
lang: 'html',
386+
text: '<div class="bg-primary">',
387+
name: 'c/a/index.html',
388+
})
389+
390+
let documentB = await c.openDocument({
391+
lang: 'html',
392+
text: '<div class="bg-primary">',
393+
name: 'c/b/index.html',
394+
})
395+
396+
let hoverA = await c.sendRequest(HoverRequest.type, {
397+
textDocument: documentA,
398+
399+
// <div class="bg-primary">
400+
// ^
401+
position: { line: 0, character: 13 },
402+
})
403+
404+
let hoverB = await c.sendRequest(HoverRequest.type, {
405+
textDocument: documentB,
406+
407+
// <div class="bg-primary">
408+
// ^
409+
position: { line: 0, character: 13 },
410+
})
411+
412+
expect(hoverA).toEqual({
413+
contents: {
414+
language: 'css',
415+
value: dedent`
416+
.bg-primary {
417+
background-color: var(--color-primary) /* #000000 */;
418+
}
419+
`,
420+
},
421+
range: {
422+
start: { line: 0, character: 12 },
423+
end: { line: 0, character: 22 },
424+
},
425+
})
426+
427+
expect(hoverB).toEqual({
428+
contents: {
429+
language: 'css',
430+
value: dedent`
431+
.bg-primary {
432+
background-color: var(--color-primary) /* #ffffff */;
433+
}
434+
`,
435+
},
436+
range: {
437+
start: { line: 0, character: 12 },
438+
end: { line: 0, character: 22 },
439+
},
440+
})
441+
},
442+
})
443+
444+
defineTest({
445+
name: 'v4, using fallback, with explicit CSS entrypoints',
446+
fs: {
447+
'a/app.css': css`
448+
@import 'tailwindcss';
449+
@theme {
450+
--color-primary: #000000;
451+
}
452+
`,
453+
'b/app.css': css`
454+
@import 'tailwindcss';
455+
@theme {
456+
--color-primary: #ffffff;
457+
}
458+
`,
459+
},
460+
prepare: async ({ root }) => ({ c: await init(root) }),
461+
handle: async ({ c }) => {
462+
await c.updateSettings({
463+
tailwindCSS: {
464+
experimental: {
465+
configFile: {
466+
'a/app.css': 'c/a/**',
467+
'b/app.css': 'c/b/**',
468+
},
469+
},
470+
},
471+
})
472+
473+
let documentA = await c.openDocument({
474+
lang: 'html',
475+
text: '<div class="bg-primary">',
476+
name: 'c/a/index.html',
477+
})
478+
479+
let documentB = await c.openDocument({
480+
lang: 'html',
481+
text: '<div class="bg-primary">',
482+
name: 'c/b/index.html',
483+
})
484+
485+
let hoverA = await c.sendRequest(HoverRequest.type, {
486+
textDocument: documentA,
487+
488+
// <div class="bg-primary">
489+
// ^
490+
position: { line: 0, character: 13 },
491+
})
492+
493+
let hoverB = await c.sendRequest(HoverRequest.type, {
494+
textDocument: documentB,
495+
496+
// <div class="bg-primary">
497+
// ^
498+
position: { line: 0, character: 13 },
499+
})
500+
501+
expect(hoverA).toEqual({
502+
contents: {
503+
language: 'css',
504+
value: dedent`
505+
.bg-primary {
506+
background-color: var(--color-primary) /* #000000 */;
507+
}
508+
`,
509+
},
510+
range: {
511+
start: { line: 0, character: 12 },
512+
end: { line: 0, character: 22 },
513+
},
514+
})
515+
516+
expect(hoverB).toEqual({
517+
contents: {
518+
language: 'css',
519+
value: dedent`
520+
.bg-primary {
521+
background-color: var(--color-primary) /* #ffffff */;
522+
}
523+
`,
524+
},
525+
range: {
526+
start: { line: 0, character: 12 },
527+
end: { line: 0, character: 22 },
528+
},
529+
})
530+
},
531+
})

packages/vscode-tailwindcss/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Support style-rule like completions inside `@variant` ([#1165](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1165))
1212
- Make sure `@slot` isn't considered an unknown at-rule ([#1165](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1165))
1313
- Fix equivalent calculation when using prefixes in v4 ([#1166](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1166))
14+
- Fix use of `tailwindCSS.experimental.configFile` option when using the bundled version of v4 ([#1167](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1167))
1415

1516
## 0.14.2
1617

packages/vscode-tailwindcss/README.md

+31-3
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,43 @@ Enable the Node.js inspector agent for the language server and listen on the spe
164164

165165
**Default: `null`**
166166

167-
By default the extension will automatically use the first `tailwind.config.{js,cjs,mjs,ts,cts,mts}` file that it can find to provide Tailwind CSS IntelliSense. Use this setting to manually specify the config file(s) yourself instead.
167+
This setting allows you to manually specify the CSS entrypoints (for v4 projects) or the Tailwind configuration file (for v3 projects). By default, the extension attempts to detect your project setup automatically:
168168

169-
If your project contains a single Tailwind config file you can specify a string value:
169+
- **For Tailwind CSS v4**: The extension scans your project for CSS files and determines the "root" CSS file.
170+
- **For Tailwind CSS v3 (and earlier)**: The extension automatically uses the first `tailwind.config.{js,cjs,mjs,ts,cts,mts}` file it finds.
171+
172+
If IntelliSense is unable to detect your project, you can use this setting to define your config files manually.
173+
174+
#### Tailwind CSS v4.x (CSS entrypoints)
175+
176+
For v4 projects, specify the CSS file(s) that serve as your Tailwind entrypoints.
177+
178+
If your project contains a single CSS entrypoint, set this option to a string:
179+
180+
```json
181+
"tailwindCSS.experimental.configFile": "src/styles/app.css"
182+
```
183+
184+
For projects with multiple CSS entrypoints, use an object where each key is a file path and each value is a glob pattern (or array of patterns) representing the files it applies to:
185+
186+
```json
187+
"tailwindCSS.experimental.configFile": {
188+
"packages/a/src/app.css": "packages/a/src/**",
189+
"packages/b/src/app.css": "packages/b/src/**"
190+
}
191+
```
192+
193+
#### Tailwind CSS v3.x and earlier (config files)
194+
195+
For v3 projects and below, specify the Tailwind configuration file(s) instead.
196+
197+
If your project contains a single Tailwind config, set this option to a string:
170198

171199
```json
172200
"tailwindCSS.experimental.configFile": ".config/tailwind.config.js"
173201
```
174202

175-
For projects with multiple config files use an object where each key is a config file path and each value is a glob pattern (or array of glob patterns) representing the set of files that the config file applies to:
203+
For projects with multiple config files, use an object where each key is a config file path and each value is a glob pattern (or array of patterns) representing the files it applies to:
176204

177205
```json
178206
"tailwindCSS.experimental.configFile": {

0 commit comments

Comments
 (0)