VSCode Language Client
The `vscode-languageclient` package provides the foundational client-side implementation for integrating Language Servers into VS Code extensions. It fully adheres to the Language Server Protocol (LSP), abstracting away the complexities of inter-process communication, managing the language server's lifecycle (startup, shutdown, restart), and seamlessly mapping LSP messages to the corresponding VS Code API calls. This library is the official, actively maintained client by Microsoft, ensuring deep integration and compatibility with the editor's evolving features and API, making it the de-facto standard for building robust language extensions. The current stable version is 9.0.1, with active development evident through frequent `10.0.0-next.x` pre-releases, often aligning with major VS Code updates. Its release cadence is primarily driven by the needs of VS Code's extension ecosystem.
Common errors
-
Language client 'myLanguageServer' failed to launch.
cause The language server process specified in `serverOptions` failed to start, crashed immediately, or exited prematurely. This often points to an issue within the server's main script or its dependencies.fixVerify the `serverModule` path in `serverOptions` is correct and points to an executable script. Enable debugging for the server (e.g., using `--inspect` in `debugOptions`) and attach a debugger to diagnose server startup issues. Check the language client's output channel in VS Code for any logged server errors or messages. -
Cannot find module 'vscode'
cause This error occurs when client-side extension code, which relies on the `vscode` API, is executed outside of a running VS Code instance (e.g., directly in Node.js or a web browser). The `vscode` module is a host-provided API, not an npm installable package for runtime.fixEnsure your extension is correctly packaged and run within VS Code. When developing, use the 'Run Extension' debug configuration. If building for a specific environment, ensure `vscode` is correctly declared as a `peerDependency` in your extension's `package.json` and handled by your build process. -
Client requests textDocument/diagnostics before textDocument/didOpen
cause This was a known bug in specific `vscode-languageclient` versions (prior to `10.0.0-next.20`) where the client would send `textDocument/diagnostics` requests to the server before the `textDocument/didOpen` notification, leading to potential server errors or incorrect state where the server hadn't processed the document yet.fixUpdate `vscode-languageclient` to `10.0.0-next.20` or a later stable version (e.g., `10.0.0` once released) to resolve the incorrect request order and ensure proper document lifecycle management.
Warnings
- breaking Version 9.0.0 and above of `vscode-languageclient` explicitly require VS Code engine version `^1.82.0` or higher. Using older VS Code versions may lead to activation failures or unexpected behavior.
- gotcha In `vscode-languageclient` versions prior to `10.0.0-next.20`, the client could prematurely request `textDocument/diagnostics` before sending the `textDocument/didOpen` notification to the server. This could lead to server errors if the server expects the document to be open first.
- gotcha Specific `next` versions leading up to `10.0.0-next.11` of `vscode-languageclient` were found to have an 'output channel leak' when stopping a `LanguageClient`, potentially consuming resources over time with frequent client restarts.
- gotcha The `jsonrpc` package (a core dependency) introduced `NoInfer` for better typing in `10.0.0-next.11`. While an improvement, this might subtly change type inference in custom request/notification handlers if your code previously relied on broader type compatibility.
Install
-
npm install vscode-languageclient -
yarn add vscode-languageclient -
pnpm add vscode-languageclient
Imports
- LanguageClient
const { LanguageClient } = require('vscode-languageclient');import { LanguageClient } from 'vscode-languageclient/node'; - LanguageClientOptions
import { LanguageClientOptions } from 'vscode-languageclient/node'; - ServerOptions, TransportKind
import { ServerOptions, TransportKind } from 'vscode-languageclient/node';
Quickstart
import * as path from 'path';
import { ExtensionContext, workspace } from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient/node';
let client: LanguageClient;
export function activate(context: ExtensionContext) {
// The server is implemented in Node.js
// Path to the server module (your actual language server's main file)
const serverModule = context.asAbsolutePath(path.join('server', 'out', 'server.js'));
// Debug options for the server
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to it
const debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
// Server options: either run or debug mode
const serverOptions: ServerOptions = {
run: { module: serverModule, transport: TransportKind.stdio },
debug: { module: serverModule, transport: TransportKind.stdio, options: debugOptions }
};
// Options to control the language client
const clientOptions: LanguageClientOptions = {
// Register the server for documents matching a specific language ID or scheme
documentSelector: [{ scheme: 'file', language: 'plaintext' }],
synchronize: {
// Notify the server about file changes to '.clientrc' files in the workspace
fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
},
outputChannelName: 'My Language Client',
traceOutputChannel: workspace.window.createOutputChannel('My Language Client Trace')
};
// Create the language client and start it. This will also launch the server.
client = new LanguageClient(
'myLanguageServer',
'My Language Server',
serverOptions,
clientOptions
);
// Start the client. This returns a disposable which will stop the client
// when the extension is deactivated.
client.start();
// Add the client to the context's subscriptions so it is stopped on deactivate
context.subscriptions.push(client);
}
export function deactivate(): Thenable<void> | undefined {
if (!client) {
return undefined;
}
return client.stop();
}