Skip to content

Commit

Permalink
Perform a soft reload of some project state when editing theme files (#…
Browse files Browse the repository at this point in the history
…918)

* Perform a soft reload of some project state when editing theme files

* Format

---------

Co-authored-by: Kris Braun <kris.braun@gmail.com>
  • Loading branch information
thecrypticace and KrisBraun committed Mar 5, 2024
1 parent c67c85f commit 8764dc0
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 29 deletions.
38 changes: 38 additions & 0 deletions packages/tailwindcss-language-server/src/projects.ts
Expand Up @@ -108,6 +108,8 @@ export interface ProjectService {
onCodeAction(params: CodeActionParams): Promise<CodeAction[]>
onDocumentLinks(params: DocumentLinkParams): DocumentLink[]
sortClassLists(classLists: string[]): string[]

reload(): Promise<void>
}

export enum DocumentSelectorPriority {
Expand Down Expand Up @@ -975,6 +977,42 @@ export async function createProjectService(
enable() {
enabled = true
},

async reload() {
if (!state.v4) return

console.log('---- RELOADING DESIGN SYSTEM ----')
let css = await readCssFile(state.configPath)
let designSystem = await loadDesignSystem(
state.modules.tailwindcss.module,
state.configPath,
css,
)

// TODO: This is weird and should be changed
// We use Object.create so no global state is mutated until necessary
let pseudoState = Object.create(state, {
designSystem: {
value: designSystem,
},
})

let classList = designSystem.getClassList().map((className) => {
return [
className[0],
{
...className[1],
color: getColor(pseudoState, className[0]),
},
]
})

state.designSystem = designSystem
state.classList = classList as any

console.log('---- RELOADED ----')
},

state,
documentSelector() {
return documentSelector
Expand Down
92 changes: 63 additions & 29 deletions packages/tailwindcss-language-server/src/tw.ts
Expand Up @@ -177,7 +177,7 @@ export class TW {
isDefaultVersion: false,
},
}
},
}
)
} else {
console.log("Searching for Tailwind CSS projects in the workspace's folders.")
Expand Down Expand Up @@ -224,9 +224,10 @@ export class TW {
console.log(`[Global] Creating projects: ${JSON.stringify(workspaceDescription)}`)

const onDidChangeWatchedFiles = async (
changes: Array<{ file: string; type: FileChangeType }>,
changes: Array<{ file: string; type: FileChangeType }>
): Promise<void> => {
let needsRestart = false
let needsSoftRestart = false

changeLoop: for (let change of changes) {
let normalizedFilename = normalizePath(change.file)
Expand All @@ -242,12 +243,10 @@ export class TW {
for (let [, project] of this.projects) {
let twVersion = require('tailwindcss/package.json').version
try {
let v = require(
resolveFrom(
path.dirname(project.projectConfig.configPath),
'tailwindcss/package.json',
),
).version
let v = require(resolveFrom(
path.dirname(project.projectConfig.configPath),
'tailwindcss/package.json'
)).version
if (typeof v === 'string') {
twVersion = v
}
Expand All @@ -259,6 +258,20 @@ export class TW {
}
}

for (let [, project] of this.projects) {
if (!project.state.v4) continue

let reloadableFiles = [
project.projectConfig.configPath,
...project.projectConfig.config.entries.map((entry) => entry.path),
]

if (!changeAffectsFile(normalizedFilename, reloadableFiles)) continue

needsSoftRestart = true
break changeLoop
}

let isCssFile = minimatch(normalizedFilename, `**/${CSS_GLOB}`, {
dot: true,
})
Expand Down Expand Up @@ -300,6 +313,15 @@ export class TW {
return
}

if (needsSoftRestart) {
try {
await this.softRestart()
} catch {
this.restart()
}
return
}

for (let [, project] of this.projects) {
project.onFileEvents(changes)
}
Expand All @@ -316,11 +338,11 @@ export class TW {
.filter(
(change, changeIndex, changes) =>
changes.findIndex((c) => c.file === change.file && c.type === change.type) ===
changeIndex,
changeIndex
)

await onDidChangeWatchedFiles(normalizedChanges)
}),
})
)

let disposable = await this.connection.client.register(
Expand All @@ -331,7 +353,7 @@ export class TW {
{ globPattern: `**/${PACKAGE_LOCK_GLOB}` },
{ globPattern: `**/${CSS_GLOB}` },
],
},
}
)

this.disposables.push(disposable)
Expand Down Expand Up @@ -360,14 +382,14 @@ export class TW {
base,
(err, events) => {
onDidChangeWatchedFiles(
events.map((event) => ({ file: event.path, type: typeMap[event.type] })),
events.map((event) => ({ file: event.path, type: typeMap[event.type] }))
)
},
{
ignore: ignore.map((ignorePattern) =>
path.resolve(base, ignorePattern.replace(/^[*/]+/, '').replace(/[*/]+$/, '')),
path.resolve(base, ignorePattern.replace(/^[*/]+/, '').replace(/[*/]+$/, ''))
),
},
}
)

this.disposables.push({
Expand All @@ -388,7 +410,7 @@ export class TW {
stabilityThreshold: 100,
pollInterval: 20,
},
},
}
)

await new Promise<void>((resolve) => {
Expand All @@ -399,17 +421,17 @@ export class TW {
.on('add', (file) =>
onDidChangeWatchedFiles([
{ file: path.resolve(base, file), type: FileChangeType.Created },
]),
])
)
.on('change', (file) =>
onDidChangeWatchedFiles([
{ file: path.resolve(base, file), type: FileChangeType.Changed },
]),
])
)
.on('unlink', (file) =>
onDidChangeWatchedFiles([
{ file: path.resolve(base, file), type: FileChangeType.Deleted },
]),
])
)

this.disposables.push({
Expand All @@ -433,9 +455,9 @@ export class TW {
projectConfig,
this.initializeParams,
this.watchPatterns,
configTailwindVersionMap.get(projectConfig.configPath),
),
),
configTailwindVersionMap.get(projectConfig.configPath)
)
)
)

// init projects for documents that are _already_ open
Expand Down Expand Up @@ -465,19 +487,19 @@ export class TW {
for (let [, project] of this.projects) {
project.onUpdateSettings(settings)
}
}),
})
)

this.disposables.push(
this.connection.onShutdown(() => {
this.dispose()
}),
})
)

this.disposables.push(
this.documentService.onDidChangeContent((change) => {
this.getProject(change.document)?.provideDiagnostics(change.document)
}),
})
)

this.disposables.push(
Expand All @@ -487,7 +509,7 @@ export class TW {
project.enable()
project.tryInit()
}
}),
})
)
}

Expand All @@ -501,7 +523,7 @@ export class TW {
projectConfig: ProjectConfig,
params: InitializeParams,
watchPatterns: (patterns: string[]) => void,
tailwindVersion: string,
tailwindVersion: string
): Promise<void> {
let key = String(this.projectCounter++)
const project = await createProjectService(
Expand All @@ -524,7 +546,7 @@ export class TW {
() => this.refreshDiagnostics(),
(patterns: string[]) => watchPatterns(patterns),
tailwindVersion,
this.settingsCache.get,
this.settingsCache.get
)
this.projects.set(key, project)

Expand Down Expand Up @@ -571,11 +593,11 @@ export class TW {

private onRequest(
method: '@/tailwindCSS/sortSelection',
params: { uri: string; classLists: string[] },
params: { uri: string; classLists: string[] }
): { error: string } | { classLists: string[] }
private onRequest(
method: '@/tailwindCSS/getProject',
params: { uri: string },
params: { uri: string }
): { version: string } | null
private onRequest(method: string, params: any): any {
if (method === '@/tailwindCSS/sortSelection') {
Expand Down Expand Up @@ -776,6 +798,18 @@ export class TW {
this.initPromise = undefined
this.init()
}

async softRestart(): Promise<void> {
// Tell each v4 project to reload it's design system
for (let [, project] of this.projects) {
if (!project.state.v4) continue

// "soft"-reload the project
try {
await project.reload()
} catch {}
}
}
}

function supportsDynamicRegistration(params: InitializeParams): boolean {
Expand Down

0 comments on commit 8764dc0

Please sign in to comment.