Skip to content

Commit 48d74c8

Browse files
authored
Resolve remark plugins synchronously (#500)
TypeScript plugins only support a synchronous API. Volar has a way to support asynchronous plugins, but it’s hacky and keeps breaking. This change makes the loading of remark plugins synchronous, allowing us to make the TypeScript plugin synchronous as well. For now jiti is used to load plugins synchronously. As soon as VSCode ships with a Node.js version that supports `require(esm)`, we can replace jiti with `createRequire()`.
1 parent d440c79 commit 48d74c8

File tree

8 files changed

+73
-70
lines changed

8 files changed

+73
-70
lines changed

.changeset/eighty-cats-glow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@mdx-js/typescript-plugin': minor
3+
---
4+
5+
Make the plugin synchronous

.changeset/petite-keys-count.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@mdx-js/typescript-plugin': minor
3+
'@mdx-js/language-server': minor
4+
---
5+
6+
Use jiti to load ESM synchronously

.changeset/social-items-cut.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@mdx-js/language-service': minor
3+
---
4+
5+
Make resolveRemarkPlugins synchronous

packages/language-server/lib/index.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
#!/usr/bin/env node
22

33
/**
4-
* @import {PluggableList, Plugin} from 'unified'
4+
* @import {PluggableList} from 'unified'
55
*/
66

77
import assert from 'node:assert'
88
import path from 'node:path'
99
import process from 'node:process'
10-
import {pathToFileURL} from 'node:url'
1110
import {
1211
createMdxLanguagePlugin,
1312
createMdxServicePlugin,
@@ -19,7 +18,7 @@ import {
1918
createTypeScriptProject,
2019
loadTsdkByPath
2120
} from '@volar/language-server/node.js'
22-
import {loadPlugin} from 'load-plugin'
21+
import {createJiti} from 'jiti'
2322
import remarkFrontmatter from 'remark-frontmatter'
2423
import remarkGfm from 'remark-gfm'
2524
import {create as createMarkdownServicePlugin} from 'volar-service-markdown'
@@ -52,8 +51,8 @@ connection.onInitialize(async (parameters) => {
5251
createTypeScriptProject(
5352
typescript,
5453
diagnosticMessages,
55-
async ({configFileName}) => ({
56-
languagePlugins: await getLanguagePlugins(configFileName)
54+
({configFileName}) => ({
55+
languagePlugins: getLanguagePlugins(configFileName)
5756
})
5857
),
5958
getLanguageServicePlugins()
@@ -81,7 +80,7 @@ connection.onInitialize(async (parameters) => {
8180
/**
8281
* @param {string | undefined} tsconfig
8382
*/
84-
async function getLanguagePlugins(tsconfig) {
83+
function getLanguagePlugins(tsconfig) {
8584
/** @type {PluggableList | undefined} */
8685
let plugins
8786
let checkMdx = false
@@ -100,12 +99,11 @@ connection.onInitialize(async (parameters) => {
10099
undefined,
101100
tsconfig
102101
)
103-
plugins = await resolveRemarkPlugins(
102+
const jiti = createJiti(tsconfig)
103+
104+
plugins = resolveRemarkPlugins(
104105
commandLine.raw?.mdx,
105-
(name) =>
106-
/** @type {Promise<Plugin>} */ (
107-
loadPlugin(name, {prefix: 'remark', from: pathToFileURL(cwd) + '/'})
108-
)
106+
(name) => jiti(name).default
109107
)
110108
checkMdx = Boolean(commandLine.raw?.mdx?.checkMdx)
111109
jsxImportSource = commandLine.options.jsxImportSource || jsxImportSource

packages/language-server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"dependencies": {
3434
"@mdx-js/language-service": "0.6.2",
3535
"@volar/language-server": "~2.4.0",
36-
"load-plugin": "^6.0.0",
36+
"jiti": "^2.0.0",
3737
"remark-frontmatter": "^5.0.0",
3838
"remark-gfm": "^4.0.0",
3939
"volar-service-markdown": "0.0.64",

packages/language-service/lib/tsconfig.js

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
*
88
* @param {unknown} mdxConfig
99
* The parsed command line options from which to resolve plugins.
10-
* @param {(name: string) => Plugin | PromiseLike<Plugin>} resolvePlugin
10+
* @param {(name: string) => Plugin} resolvePlugin
1111
* A function which takes a plugin name, and resolvs it to a remark plugin.
12-
* @returns {Promise<PluggableList | undefined>}
12+
* @returns {PluggableList | undefined}
1313
* An array of resolved plugins, or `undefined` in case of an invalid
1414
* configuration.
1515
*/
16-
export async function resolveRemarkPlugins(mdxConfig, resolvePlugin) {
16+
export function resolveRemarkPlugins(mdxConfig, resolvePlugin) {
1717
if (
1818
typeof mdxConfig !== 'object' ||
1919
!mdxConfig ||
@@ -36,7 +36,7 @@ export async function resolveRemarkPlugins(mdxConfig, resolvePlugin) {
3636
return
3737
}
3838

39-
/** @type {Promise<Pluggable>[]} */
39+
/** @type {Pluggable[]} */
4040
const plugins = []
4141
for (const maybeTuple of pluginArray) {
4242
const [name, ...options] = Array.isArray(maybeTuple)
@@ -47,12 +47,8 @@ export async function resolveRemarkPlugins(mdxConfig, resolvePlugin) {
4747
continue
4848
}
4949

50-
plugins.push(
51-
Promise.resolve(name)
52-
.then(resolvePlugin)
53-
.then((plugin) => [plugin, ...options])
54-
)
50+
plugins.push([resolvePlugin(name), ...options])
5551
}
5652

57-
return Promise.all(plugins)
53+
return plugins
5854
}

packages/typescript-plugin/lib/index.cjs

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,60 @@
22

33
/**
44
* @import {TsConfigSourceFile} from 'typescript'
5-
* @import {Plugin} from 'unified'
65
*/
76

8-
const {pathToFileURL} = require('node:url')
97
const {
108
createMdxLanguagePlugin,
119
resolveRemarkPlugins
1210
} = require('@mdx-js/language-service')
1311
const {
14-
createAsyncLanguageServicePlugin
15-
} = require('@volar/typescript/lib/quickstart/createAsyncLanguageServicePlugin.js')
16-
const {loadPlugin} = require('load-plugin')
12+
createLanguageServicePlugin
13+
} = require('@volar/typescript/lib/quickstart/createLanguageServicePlugin.js')
14+
const {createJiti} = require('jiti')
1715
const {default: remarkFrontmatter} = require('remark-frontmatter')
1816
const {default: remarkGfm} = require('remark-gfm')
1917

20-
const plugin = createAsyncLanguageServicePlugin(
21-
['.mdx'],
22-
2 /* JSX */,
23-
async (ts, info) => {
24-
if (info.project.projectKind !== ts.server.ProjectKind.Configured) {
25-
return {
26-
languagePlugins: [
27-
createMdxLanguagePlugin([
28-
[remarkFrontmatter, ['toml', 'yaml']],
29-
remarkGfm
30-
])
31-
]
32-
}
33-
}
34-
35-
const cwd = info.project.getCurrentDirectory()
36-
const configFile = /** @type {TsConfigSourceFile} */ (
37-
info.project.getCompilerOptions().configFile
38-
)
39-
40-
const commandLine = ts.parseJsonSourceFileConfigFileContent(
41-
configFile,
42-
ts.sys,
43-
cwd,
44-
undefined,
45-
configFile.fileName
46-
)
47-
48-
const plugins = await resolveRemarkPlugins(
49-
commandLine.raw?.mdx,
50-
(name) =>
51-
/** @type {Promise<Plugin>} */ (
52-
loadPlugin(name, {prefix: 'remark', from: pathToFileURL(cwd) + '/'})
53-
)
54-
)
55-
18+
const plugin = createLanguageServicePlugin((ts, info) => {
19+
if (info.project.projectKind !== ts.server.ProjectKind.Configured) {
5620
return {
5721
languagePlugins: [
58-
createMdxLanguagePlugin(
59-
plugins || [[remarkFrontmatter, ['toml', 'yaml']], remarkGfm],
60-
Boolean(commandLine.raw?.mdx?.checkMdx),
61-
commandLine.options.jsxImportSource
62-
)
22+
createMdxLanguagePlugin([
23+
[remarkFrontmatter, ['toml', 'yaml']],
24+
remarkGfm
25+
])
6326
]
6427
}
6528
}
66-
)
29+
30+
const cwd = info.project.getCurrentDirectory()
31+
const configFile = /** @type {TsConfigSourceFile} */ (
32+
info.project.getCompilerOptions().configFile
33+
)
34+
35+
const commandLine = ts.parseJsonSourceFileConfigFileContent(
36+
configFile,
37+
ts.sys,
38+
cwd,
39+
undefined,
40+
configFile.fileName
41+
)
42+
43+
const jiti = createJiti(configFile.fileName)
44+
45+
const plugins = resolveRemarkPlugins(
46+
commandLine.raw?.mdx,
47+
(name) => jiti(name).default
48+
)
49+
50+
return {
51+
languagePlugins: [
52+
createMdxLanguagePlugin(
53+
plugins || [[remarkFrontmatter, ['toml', 'yaml']], remarkGfm],
54+
Boolean(commandLine.raw?.mdx?.checkMdx),
55+
commandLine.options.jsxImportSource
56+
)
57+
]
58+
}
59+
})
6760

6861
module.exports = plugin

packages/typescript-plugin/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"dependencies": {
3737
"@mdx-js/language-service": "0.6.2",
3838
"@volar/typescript": "~2.4.0",
39-
"load-plugin": "^6.0.0",
39+
"jiti": "^2.0.0",
4040
"remark-frontmatter": "^5.0.0",
4141
"remark-gfm": "^4.0.0"
4242
},

0 commit comments

Comments
 (0)