Skip to content

Commit d30c825

Browse files
committed
Restart server if a CSS config file is created and no projects exist
1 parent 8d5c813 commit d30c825

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

packages/tailwindcss-language-server/src/tw.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import { readCssFile } from './util/css'
5252
import { ProjectLocator, type ProjectConfig } from './project-locator'
5353
import type { TailwindCssSettings } from '@tailwindcss/language-service/src/util/state'
5454
import { createResolver, Resolver } from './resolver'
55-
import { retry } from './util/retry'
55+
import { analyzeStylesheet } from './version-guesser.js'
5656

5757
const TRIGGER_CHARACTERS = [
5858
// class attributes
@@ -412,6 +412,31 @@ export class TW {
412412
needsRestart = true
413413
break
414414
}
415+
416+
//
417+
else {
418+
// If the main CSS file in a project is deleted and then re-created
419+
// the server won't restart because the project is gone by now and
420+
// there's no concept of a "config file" for us to compare with
421+
//
422+
// So we'll check if the stylesheet could *potentially* create
423+
// a new project but we'll only do so if no projects were found
424+
//
425+
// If we did this all the time we'd potentially restart the server
426+
// unncessarily a lot while the user is editing their stylesheets
427+
if (this.projects.size > 0) continue
428+
429+
let content = await readCssFile(change.file)
430+
if (!content) continue
431+
432+
let stylesheet = analyzeStylesheet(content)
433+
if (!stylesheet.root) continue
434+
435+
if (!stylesheet.versions.includes('4')) continue
436+
437+
needsRestart = true
438+
break
439+
}
415440
}
416441

417442
let isConfigFile = isConfigMatcher(normalizedFilename)

packages/tailwindcss-language-server/tests/env/restart.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,80 @@ defineTest({
8787
})
8888
},
8989
})
90+
91+
defineTest({
92+
name: 'Server is "restarted" when a config file is removed',
93+
fs: {
94+
'app.css': css`
95+
@import 'tailwindcss';
96+
97+
@theme {
98+
--color-primary: #c0ffee;
99+
}
100+
`,
101+
},
102+
prepare: async ({ root }) => ({
103+
client: await createClient({
104+
root,
105+
capabilities(caps) {
106+
caps.workspace!.didChangeWatchedFiles!.dynamicRegistration = false
107+
},
108+
}),
109+
}),
110+
handle: async ({ root, client }) => {
111+
let doc = await client.open({
112+
lang: 'html',
113+
text: '<div class="text-primary">',
114+
})
115+
116+
// <div class="text-primary">
117+
// ^
118+
let hover = await doc.hover({ line: 0, character: 13 })
119+
120+
expect(hover).toEqual({
121+
contents: {
122+
language: 'css',
123+
value: dedent`
124+
.text-primary {
125+
color: var(--color-primary) /* #c0ffee */;
126+
}
127+
`,
128+
},
129+
range: {
130+
start: { line: 0, character: 12 },
131+
end: { line: 0, character: 24 },
132+
},
133+
})
134+
135+
// Remove the CSS file
136+
let didRestart = new Promise((resolve) => {
137+
client.conn.onNotification('@/tailwindCSS/serverRestarted', resolve)
138+
})
139+
await fs.unlink(path.resolve(root, 'app.css'))
140+
await didRestart
141+
142+
// <div class="text-primary">
143+
// ^
144+
let hover2 = await doc.hover({ line: 0, character: 13 })
145+
expect(hover2).toEqual(null)
146+
147+
// Re-create the CSS file
148+
let didRestartAgain = new Promise((resolve) => {
149+
client.conn.onNotification('@/tailwindCSS/serverRestarted', resolve)
150+
})
151+
await fs.writeFile(
152+
path.resolve(root, 'app.css'),
153+
css`
154+
@import 'tailwindcss';
155+
`,
156+
)
157+
await didRestartAgain
158+
159+
await new Promise((resolve) => setTimeout(resolve, 500))
160+
161+
// <div class="text-primary">
162+
// ^
163+
let hover3 = await doc.hover({ line: 0, character: 13 })
164+
expect(hover3).toEqual(null)
165+
},
166+
})

0 commit comments

Comments
 (0)