-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use jiti for sync loading from TS Plugin (#803)
- Loading branch information
Showing
3 changed files
with
35 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 29 additions & 49 deletions
78
packages/typescript-plugin/src/typescript-server-plugin.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,37 @@ | ||
import type ts from 'typescript'; | ||
const { createJiti } = require('jiti'); | ||
const jiti = createJiti(__filename); | ||
|
||
// Top level "imports" need to be CJS `require`s because TS Plugins must be CJS; | ||
// we dynamically import() the ESM modules we need below within the async fn | ||
// to cross the gap between CJS and ESM. | ||
const { | ||
createAsyncLanguageServicePlugin, | ||
} = require('@volar/typescript/lib/quickstart/createAsyncLanguageServicePlugin.js'); | ||
createLanguageServicePlugin, | ||
} = require('@volar/typescript/lib/quickstart/createLanguageServicePlugin.js'); | ||
|
||
/** | ||
* Volar provides two variants of functions for initializing a TS Plugin: | ||
* - createLanguageServicePlugin | ||
* - createAsyncLanguageServicePlugin | ||
* | ||
* The only difference is whether their setup callback is an async function or not. | ||
* The reason we use the async variant is because of our use of `await import`, which | ||
* we need in order to import the ESM glint package into our CJS VSCode extension. | ||
* | ||
* Unfortunately this singular tick of async appears to be causing a few race conditions, | ||
* in particular that when freshly booting VSCode on a .gts file, there might not be | ||
* any diagnostic messages until something "kicks" the TS Plugin to run, e.g. | ||
* by editing the file. | ||
*/ | ||
const plugin = createAsyncLanguageServicePlugin( | ||
['.gts', '.gjs', '.hbs'], | ||
(fileName: string) => { | ||
if (fileName.endsWith('.gts')) { | ||
return 3 satisfies ts.ScriptKind.TS; | ||
} else if (fileName.endsWith('.gjs')) { | ||
return 1 satisfies ts.ScriptKind.JS; | ||
} | ||
return 3 satisfies ts.ScriptKind.TS; | ||
}, | ||
async (_ts: any, info: any) => { | ||
// The diagnostics race condition mentioned above appears to happen or at least | ||
// be exacerbated by the fact that we use `await import` here. | ||
const glintCore = await import('@glint/core'); | ||
const plugin = createLanguageServicePlugin((_ts: typeof import('typescript'), info: any) => { | ||
/** | ||
* we use the jiti (https://github.com/unjs/jiti) runtime to make it possible to | ||
* synchronously load the ESM glint libaries from the current CommonJS context. It is a requirement | ||
* that TypeScript plugins are written in CommonJS, which poses issues with | ||
* having Glint be authored in ESM due to the requirement that typically `await import` | ||
* is required to load ESM modules from CJS. But with jiti we can synchronously load the ESM | ||
* modules from CJS which lets us avoid a ton of hacks and complexity we (or Volar) | ||
* would otherwise have to write to bridge the sync/async APIs. | ||
*/ | ||
const glintCore = jiti('@glint/core'); | ||
|
||
const { findConfig, createEmberLanguagePlugin } = glintCore; | ||
const { findConfig, createEmberLanguagePlugin } = glintCore; | ||
|
||
const cwd = info.languageServiceHost.getCurrentDirectory(); | ||
const glintConfig = findConfig(cwd); | ||
const cwd = info.languageServiceHost.getCurrentDirectory(); | ||
const glintConfig = findConfig(cwd); | ||
|
||
if (glintConfig && glintConfig.enableTsPlugin) { | ||
const gtsLanguagePlugin = createEmberLanguagePlugin(glintConfig); | ||
return { | ||
languagePlugins: [gtsLanguagePlugin], | ||
}; | ||
} else { | ||
return { | ||
languagePlugins: [], | ||
}; | ||
} | ||
}, | ||
); | ||
if (glintConfig && glintConfig.enableTsPlugin) { | ||
const gtsLanguagePlugin = createEmberLanguagePlugin(glintConfig); | ||
return { | ||
languagePlugins: [gtsLanguagePlugin], | ||
}; | ||
} else { | ||
return { | ||
languagePlugins: [], | ||
}; | ||
} | ||
}); | ||
|
||
export = plugin; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters