diff --git a/extensions/vscode/src/features/doctor.ts b/extensions/vscode/src/features/doctor.ts index e4f0a88a7..aceb78d22 100644 --- a/extensions/vscode/src/features/doctor.ts +++ b/extensions/vscode/src/features/doctor.ts @@ -1,5 +1,5 @@ import { getTsdk } from '@volar/vscode'; -import { ParseSFCRequest } from '@vue/language-server'; +import { GetConnectedNamedPipeServerRequest, ParseSFCRequest } from '@vue/language-server'; import * as semver from 'semver'; import * as vscode from 'vscode'; import type { BaseLanguageClient } from 'vscode-languageclient'; @@ -257,6 +257,20 @@ export async function register(context: vscode.ExtensionContext, client: BaseLan }); } + // #3942 + const namedPipe = await client.sendRequest(GetConnectedNamedPipeServerRequest.type, fileUri.fsPath.replace(/\\/g, '/')); + if (namedPipe?.serverKind === 0) { + problems.push({ + title: 'Missing jsconfig/tsconfig', + message: [ + 'The current file does not have a matching tsconfig/jsconfig, and extension version 2.0 will not work properly for this at the moment.', + 'To avoid this problem, you can create a jsconfig in the project root, or downgrade to 1.8.27.', + '', + 'Issue: https://github.com/vuejs/language-tools/issues/3942', + ].join('\n'), + }); + } + // check outdated vue language plugins // check node_modules has more than one vue versions // check ESLint, Prettier... diff --git a/packages/language-server/lib/protocol.ts b/packages/language-server/lib/protocol.ts index 3ab50a9fa..d85d71f2a 100644 --- a/packages/language-server/lib/protocol.ts +++ b/packages/language-server/lib/protocol.ts @@ -39,3 +39,13 @@ export namespace ParseSFCRequest { export type ErrorType = never; export const type = new vscode.RequestType('vue/parseSfc'); } + +export namespace GetConnectedNamedPipeServerRequest { + export type ParamsType = string; + export type ResponseType = { + path: string, + serverKind: number, + } | undefined; + export type ErrorType = never; + export const type = new vscode.RequestType('vue/namedPipeServer'); +} diff --git a/packages/language-server/node.ts b/packages/language-server/node.ts index 35f202a4f..c54d890e9 100644 --- a/packages/language-server/node.ts +++ b/packages/language-server/node.ts @@ -5,6 +5,7 @@ import { ServiceEnvironment, convertAttrName, convertTagName, createVueServicePl import { DetectNameCasingRequest, GetConvertAttrCasingEditsRequest, GetConvertTagCasingEditsRequest, ParseSFCRequest } from './lib/protocol'; import type { VueInitializationOptions } from './lib/types'; import * as tsPluginClient from '@vue/typescript-plugin/lib/client'; +import { GetConnectedNamedPipeServerRequest } from './lib/protocol'; export const connection: Connection = createConnection(); @@ -122,6 +123,13 @@ connection.onRequest(GetConvertAttrCasingEditsRequest.type, async params => { } }); +connection.onRequest(GetConnectedNamedPipeServerRequest.type, async fileName => { + const connected = await tsPluginClient.connectForFile(fileName); + if (connected) { + return connected[1]; + } +}); + async function getService(uri: string) { return (await server.projects.getProject(uri)).getLanguageService(); } diff --git a/packages/typescript-plugin/lib/client.ts b/packages/typescript-plugin/lib/client.ts index 27d553281..e97cc495e 100644 --- a/packages/typescript-plugin/lib/client.ts +++ b/packages/typescript-plugin/lib/client.ts @@ -81,17 +81,18 @@ export function getElementAttrs( } async function sendRequest(request: Request) { - const client = await connectForFile(request.args[0]); - if (!client) { + const connected = await connectForFile(request.args[0]); + if (!connected) { console.warn('[Vue Named Pipe Client] No server found for', request.args[0]); return; } + const [client] = connected; const result = await sendRequestWorker(request, client); client.end(); return result; } -async function connectForFile(fileName: string) { +export async function connectForFile(fileName: string) { if (!fs.existsSync(pipeTable)) { return; } @@ -106,7 +107,7 @@ async function connectForFile(fileName: string) { if (client) { const response = await sendRequestWorker({ type: 'containsFile', args: [fileName] }, client); if (response) { - return client; + return [client, server] as const; } } } @@ -114,7 +115,7 @@ async function connectForFile(fileName: string) { if (!path.relative(server.currentDirectory, fileName).startsWith('..')) { const client = await connect(server.path); if (client) { - return client; + return [client, server] as const; } } } diff --git a/packages/typescript-plugin/lib/server.ts b/packages/typescript-plugin/lib/server.ts index 65a052f6d..9df744b67 100644 --- a/packages/typescript-plugin/lib/server.ts +++ b/packages/typescript-plugin/lib/server.ts @@ -81,7 +81,7 @@ export function startNamedPipeServer(serverKind: ts.server.ProjectKind, currentD connection.on('error', err => console.error('[Vue Named Pipe Server]', err.message)); }); - clearupPipeTable(); + cleanupPipeTable(); if (!fs.existsSync(pipeTable)) { fs.writeFileSync(pipeTable, JSON.stringify([] satisfies NamedPipeServer[])); @@ -101,7 +101,7 @@ export function startNamedPipeServer(serverKind: ts.server.ProjectKind, currentD server.listen(pipeFile); } -function clearupPipeTable() { +function cleanupPipeTable() { if (!fs.existsSync(pipeTable)) { return; }