Skip to content

Commit b274db2

Browse files
feat(vscode): introduce vue.server.path setting (#5647)
Co-authored-by: 山吹色御守 <[email protected]> Co-authored-by: KazariEX <[email protected]>
1 parent a40c6d8 commit b274db2

File tree

8 files changed

+90
-21
lines changed

8 files changed

+90
-21
lines changed

extensions/vscode/index.ts

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import * as interpolationDecorators from './lib/interpolationDecorators';
2121
import * as reactivityVisualization from './lib/reactivityVisualization';
2222
import * as welcome from './lib/welcome';
2323

24-
let client: lsp.BaseLanguageClient | undefined;
25-
let needRestart = false;
24+
const serverPath = resolveServerPath();
25+
const neededRestart = !patchTypeScriptExtension();
2626

2727
for (
2828
const incompatibleExtensionId of [
@@ -44,6 +44,8 @@ for (
4444
}
4545

4646
export = defineExtension(() => {
47+
let client: lsp.BaseLanguageClient | undefined;
48+
4749
const context = extensionContext.value!;
4850
const volarLabs = createLabsInfo();
4951
const activeTextEditor = useActiveTextEditor();
@@ -59,7 +61,7 @@ export = defineExtension(() => {
5961

6062
nextTick(() => stop());
6163

62-
if (needRestart) {
64+
if (neededRestart) {
6365
vscode.window.showInformationMessage(
6466
'Please restart the extension host to activate Vue support.',
6567
'Restart Extension Host',
@@ -75,9 +77,12 @@ export = defineExtension(() => {
7577
return;
7678
}
7779

78-
watch(() => config.server.includeLanguages, async () => {
80+
watch(() => [
81+
config.server.path,
82+
config.server.includeLanguages,
83+
], async () => {
7984
const reload = await vscode.window.showInformationMessage(
80-
'Please restart extension host to apply the new language settings.',
85+
'Please restart extension host to apply the new server settings.',
8186
'Restart Extension Host',
8287
);
8388
if (reload) {
@@ -95,7 +100,14 @@ export = defineExtension(() => {
95100
);
96101
}
97102

98-
volarLabs.addLanguageClient(client = launch(context));
103+
if (config.server.path && !serverPath) {
104+
vscode.window.showErrorMessage('Cannot find @vue/language-server.');
105+
return;
106+
}
107+
108+
client = launch(serverPath ?? vscode.Uri.joinPath(context.extensionUri, 'dist', 'language-server.js').fsPath);
109+
110+
volarLabs.addLanguageClient(client);
99111

100112
const selectors = config.server.includeLanguages;
101113

@@ -123,19 +135,18 @@ export = defineExtension(() => {
123135
return volarLabs.extensionExports;
124136
});
125137

126-
function launch(context: vscode.ExtensionContext) {
127-
const serverModule = vscode.Uri.joinPath(context.extensionUri, 'dist', 'language-server.js');
138+
function launch(serverPath: string) {
128139
const client = new lsp.LanguageClient(
129140
'vue',
130141
'Vue',
131142
{
132143
run: {
133-
module: serverModule.fsPath,
144+
module: serverPath,
134145
transport: lsp.TransportKind.ipc,
135146
options: {},
136147
},
137148
debug: {
138-
module: serverModule.fsPath,
149+
module: serverPath,
139150
transport: lsp.TransportKind.ipc,
140151
options: { execArgv: ['--nolazy', '--inspect=' + 6009] },
141152
},
@@ -179,21 +190,52 @@ function launch(context: vscode.ExtensionContext) {
179190
return client;
180191
}
181192

182-
const tsExtension = vscode.extensions.getExtension('vscode.typescript-language-features')!;
183-
if (tsExtension.isActive) {
184-
needRestart = true;
193+
function resolveServerPath() {
194+
const tsPluginPackPath = path.join(__dirname, '..', 'node_modules', 'vue-typescript-plugin-pack', 'index.js');
195+
196+
if (!config.server.path) {
197+
fs.writeFileSync(tsPluginPackPath, `module.exports = require("../../dist/typescript-plugin.js");`);
198+
return;
199+
}
200+
201+
if (path.isAbsolute(config.server.path)) {
202+
const entryFile = require.resolve('./index.js', { paths: [config.server.path] });
203+
const tsPluginPath = require.resolve('@vue/typescript-plugin', { paths: [path.dirname(entryFile)] });
204+
fs.writeFileSync(tsPluginPackPath, `module.exports = require("${tsPluginPath}");`);
205+
return entryFile;
206+
}
207+
208+
for (const { uri } of vscode.workspace.workspaceFolders ?? []) {
209+
if (uri.scheme !== 'file') {
210+
continue;
211+
}
212+
try {
213+
const serverPath = path.join(uri.fsPath, config.server.path);
214+
const entryFile = require.resolve('./index.js', { paths: [serverPath] });
215+
const tsPluginPath = require.resolve('@vue/typescript-plugin', { paths: [path.dirname(entryFile)] });
216+
fs.writeFileSync(tsPluginPackPath, `module.exports = require("${tsPluginPath}");`);
217+
return entryFile;
218+
}
219+
catch {}
220+
}
185221
}
186-
else {
222+
223+
function patchTypeScriptExtension() {
224+
const tsExtension = vscode.extensions.getExtension('vscode.typescript-language-features')!;
225+
if (tsExtension.isActive) {
226+
return false;
227+
}
228+
187229
const fs = require('node:fs');
188230
const readFileSync = fs.readFileSync;
189231
const extensionJsPath = require.resolve('./dist/extension.js', { paths: [tsExtension.extensionPath] });
190232
const { publisher, name } = require('./package.json');
191233
const vueExtension = vscode.extensions.getExtension(`${publisher}.${name}`)!;
192-
const vuePluginName = 'vue-typescript-plugin-pack';
234+
const tsPluginName = 'vue-typescript-plugin-pack';
193235

194236
vueExtension.packageJSON.contributes.typescriptServerPlugins = [
195237
{
196-
name: vuePluginName,
238+
name: tsPluginName,
197239
enableForWorkspaceTypeScriptVersions: true,
198240
configNamespace: 'typescript',
199241
languages: config.server.includeLanguages,
@@ -218,7 +260,7 @@ else {
218260
// sort plugins for johnsoncodehk.tsslint, zardoy.ts-essential-plugins
219261
text = text.replace(
220262
'"--globalPlugins",i.plugins',
221-
s => s + `.sort((a,b)=>(b.name==="${vuePluginName}"?-1:0)-(a.name==="${vuePluginName}"?-1:0))`,
263+
s => s + `.sort((a,b)=>(b.name==="${tsPluginName}"?-1:0)-(a.name==="${tsPluginName}"?-1:0))`,
222264
);
223265

224266
return text;
@@ -232,4 +274,5 @@ else {
232274
const patchedModule = require(extensionJsPath);
233275
Object.assign(loadedModule.exports, patchedModule);
234276
}
277+
return true;
235278
}

extensions/vscode/lib/generated-meta.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Meta info
55
export const publisher = 'Vue';
66
export const name = 'volar';
7-
export const version = '3.0.6';
7+
export const version = '3.0.7';
88
export const displayName = 'Vue (Official)';
99
export const description = 'Language Support for Vue';
1010
export const extensionId = `${publisher}.${name}`;
@@ -40,6 +40,7 @@ export type ConfigKey =
4040
| 'vue.editor.focusMode'
4141
| 'vue.editor.reactivityVisualization'
4242
| 'vue.editor.templateInterpolationDecorators'
43+
| 'vue.server.path'
4344
| 'vue.server.includeLanguages'
4445
| 'vue.codeActions.askNewComponentName'
4546
| 'vue.suggest.componentNameCasing'
@@ -62,6 +63,7 @@ export interface ConfigKeyTypeMap {
6263
'vue.editor.focusMode': boolean;
6364
'vue.editor.reactivityVisualization': boolean;
6465
'vue.editor.templateInterpolationDecorators': boolean;
66+
'vue.server.path': string | undefined;
6567
'vue.server.includeLanguages': string[];
6668
'vue.codeActions.askNewComponentName': boolean;
6769
'vue.suggest.componentNameCasing': 'preferKebabCase' | 'preferPascalCase' | 'alwaysKebabCase' | 'alwaysPascalCase';
@@ -92,6 +94,7 @@ export interface ConfigShorthandMap {
9294
editorFocusMode: 'vue.editor.focusMode';
9395
editorReactivityVisualization: 'vue.editor.reactivityVisualization';
9496
editorTemplateInterpolationDecorators: 'vue.editor.templateInterpolationDecorators';
97+
serverPath: 'vue.server.path';
9598
serverIncludeLanguages: 'vue.server.includeLanguages';
9699
codeActionsAskNewComponentName: 'vue.codeActions.askNewComponentName';
97100
suggestComponentNameCasing: 'vue.suggest.componentNameCasing';
@@ -115,6 +118,7 @@ export interface ConfigShorthandTypeMap {
115118
editorFocusMode: boolean;
116119
editorReactivityVisualization: boolean;
117120
editorTemplateInterpolationDecorators: boolean;
121+
serverPath: string | undefined;
118122
serverIncludeLanguages: string[];
119123
codeActionsAskNewComponentName: boolean;
120124
suggestComponentNameCasing: 'preferKebabCase' | 'preferPascalCase' | 'alwaysKebabCase' | 'alwaysPascalCase';
@@ -160,12 +164,12 @@ export const configs = {
160164
} as ConfigItem<'vue.trace.server'>,
161165
/**
162166
* @key `vue.editor.focusMode`
163-
* @default `true`
167+
* @default `false`
164168
* @type `boolean`
165169
*/
166170
editorFocusMode: {
167171
key: 'vue.editor.focusMode',
168-
default: true,
172+
default: false,
169173
} as ConfigItem<'vue.editor.focusMode'>,
170174
/**
171175
* @key `vue.editor.reactivityVisualization`
@@ -185,6 +189,15 @@ export const configs = {
185189
key: 'vue.editor.templateInterpolationDecorators',
186190
default: true,
187191
} as ConfigItem<'vue.editor.templateInterpolationDecorators'>,
192+
/**
193+
* @key `vue.server.path`
194+
* @default `undefined`
195+
* @type `string`
196+
*/
197+
serverPath: {
198+
key: 'vue.server.path',
199+
default: undefined,
200+
} as ConfigItem<'vue.server.path'>,
188201
/**
189202
* @key `vue.server.includeLanguages`
190203
* @default `["vue"]`
@@ -336,6 +349,7 @@ export interface ScopedConfigKeyTypeMap {
336349
'editor.focusMode': boolean;
337350
'editor.reactivityVisualization': boolean;
338351
'editor.templateInterpolationDecorators': boolean;
352+
'server.path': string | undefined;
339353
'server.includeLanguages': string[];
340354
'codeActions.askNewComponentName': boolean;
341355
'suggest.componentNameCasing': 'preferKebabCase' | 'preferPascalCase' | 'alwaysKebabCase' | 'alwaysPascalCase';
@@ -365,9 +379,10 @@ export const scopedConfigs = {
365379
scope: 'vue',
366380
defaults: {
367381
'trace.server': 'off',
368-
'editor.focusMode': true,
382+
'editor.focusMode': false,
369383
'editor.reactivityVisualization': true,
370384
'editor.templateInterpolationDecorators': true,
385+
'server.path': undefined,
371386
'server.includeLanguages': ['vue'],
372387
'codeActions.askNewComponentName': true,
373388
'suggest.componentNameCasing': 'preferPascalCase',
@@ -398,6 +413,7 @@ export interface NestedConfigs {
398413
'templateInterpolationDecorators': boolean;
399414
};
400415
'server': {
416+
'path': string | undefined;
401417
'includeLanguages': string[];
402418
};
403419
'codeActions': {
@@ -451,6 +467,7 @@ export interface NestedScopedConfigs {
451467
'templateInterpolationDecorators': boolean;
452468
};
453469
'server': {
470+
'path': string | undefined;
454471
'includeLanguages': string[];
455472
};
456473
'codeActions': {

extensions/vscode/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@
272272
"default": true,
273273
"markdownDescription": "%configuration.editor.templateInterpolationDecorators%"
274274
},
275+
"vue.server.path": {
276+
"type": "string",
277+
"markdownDescription": "%configuration.server.path%"
278+
},
275279
"vue.server.includeLanguages": {
276280
"type": "array",
277281
"items": {

extensions/vscode/package.nls.ja.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"configuration.trace.server": "VS Code と Vue 言語サーバー間の通信をトレースします。",
3+
"configuration.server.path": "`@vue/language-server` モジュールへのパス。設定しない場合、拡張機能にバンドルされたサーバーが読み込まれます。",
34
"configuration.server.includeLanguages": "拡張機能を有効にする言語を指定します。",
45
"configuration.codeActions.askNewComponentName": "コンポーネントを抽出する時に新しいコンポーネント名を尋ねます。",
56
"configuration.suggest.componentNameCasing": "コンポーネント名の命名規則。",

extensions/vscode/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"configuration.trace.server": "Traces the communication between VS Code and the language server.",
3+
"configuration.server.path": "Path to the `@vue/language-server` module. If not set, the server will be loaded from the extension's bundled.",
34
"configuration.server.includeLanguages": "Configure the languages for which the extension should be activated.",
45
"configuration.codeActions.askNewComponentName": "Ask for new component name when extract component.",
56
"configuration.suggest.componentNameCasing": "Preferred component name case.",

extensions/vscode/package.nls.ru.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"configuration.trace.server": "Отслеживать коммуникацию между VS Code и языковым сервером Vue.",
3+
"configuration.server.path": "Путь к модулю `@vue/language-server`. Если не установлен, сервер будет загружен из пакета расширения.",
34
"configuration.server.includeLanguages": "Языки, для которых будет включено расширение.",
45
"configuration.codeActions.askNewComponentName": "Запрашивать новое имя компонента при извлечении компонента.",
56
"configuration.suggest.componentNameCasing": "Предпочитаемый формат имени компонента.",

extensions/vscode/package.nls.zh-CN.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"configuration.trace.server": "跟踪 VS Code 和 Vue 语言服务器之间的通信。",
3+
"configuration.server.path": "`@vue/language-server` 模块的路径。如果未设置,服务器将从扩展的捆绑包中加载。",
34
"configuration.server.includeLanguages": "配置扩展需要激活的语言类型。",
45
"configuration.codeActions.askNewComponentName": "提取组件时询问新组件名称。",
56
"configuration.suggest.componentNameCasing": "首选组件命名格式。",

extensions/vscode/package.nls.zh-TW.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"configuration.trace.server": "追蹤 VS Code 和 Vue 語言伺服器之間的通訊。",
3+
"configuration.server.path": "`@vue/language-server` 模組的路徑。如果未設定,伺服器將從擴充功能的捆綁包中載入。",
34
"configuration.server.includeLanguages": "配置擴充功能應該啟動的語言類型。",
45
"configuration.codeActions.askNewComponentName": "提取元件時詢問新元件名稱。",
56
"configuration.suggest.componentNameCasing": "首選元件名稱格式。",

0 commit comments

Comments
 (0)