diff --git a/packages/typescript-plugin/package.json b/packages/typescript-plugin/package.json index c3b0e2d6..c25a7a3c 100644 --- a/packages/typescript-plugin/package.json +++ b/packages/typescript-plugin/package.json @@ -21,6 +21,7 @@ "prepack": "yarn build" }, "dependencies": { + "jiti": "~2.4.2", "@glint/core": "^1.4.0", "@volar/typescript": "2.4.11" }, diff --git a/packages/typescript-plugin/src/typescript-server-plugin.ts b/packages/typescript-plugin/src/typescript-server-plugin.ts index a7caf23d..a9b6deaa 100644 --- a/packages/typescript-plugin/src/typescript-server-plugin.ts +++ b/packages/typescript-plugin/src/typescript-server-plugin.ts @@ -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; diff --git a/yarn.lock b/yarn.lock index a413c6ef..ede8ee26 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9686,6 +9686,11 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" +jiti@~2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"