Volar.js Documentation

repository·master·Indexed 23 days ago

https://github.com/volarjs/volar.js

A modular language tooling ecosystem providing advanced language intelligence, including IntelliSense, diagnostics, and formatting. It supports various environments such as VS Code, Monaco Editor, and standalone Node.js applications. Key components include @volar/kit for project monitoring and linting, @volar/monaco for Monaco Editor integration, and utilities for source mapping and language server testing.

Tokens
31.1K
Snippets
58
Records
163
Agent score
71%

What's inside Volar.js

  1. Overview of @volar/monaco

    master

    @volar/monaco bridges Volar.js language capabilities to the Monaco Editor. It provides IntelliSense, diagnostics (markers), and formatting, ensuring language behavior is consistent with IDEs while maintaining optimized performance. It also automatically fetches missing package types from a CDN.

    Note: This package does not handle syntax highlighting or language configuration (e.g., tokenization or bracket matching); those must be configured separately in Monaco.

  2. Integrate Volar.js with Monaco Editor using @volar/monaco

    master
    To bring Volar.js language services (such as syntax highlighting, code completion, and definition jumping) into a web-based editor, use the @volar/monaco package. It acts as a bridge between the @volar/language-service and the Monaco Editor environment.
  3. Use @volar/kit for Node.js applications

    master

    If you are building a Node.js application and need to access Volar's language features, use @volar/kit. It encapsulates @volar/language-service to provide a simplified interface for:

    • Diagnostics: Accessing error and warning information.
    • Formatting: Applying code formatting logic.
  4. Understand the Volar.js package architecture

    master

    Volar.js is organized into a layered architecture that separates core language processing from editor-specific integrations. The hierarchy flows from core processing up to specialized clients:

    1. @volar/language-core: The foundation. Handles core language processing like creating and updating virtual code objects.
    2. @volar/language-service: Built on top of language-core. Provides high-level IntelliSense features.
    3. @volar/language-server: An LSP (Language Server Protocol) implementation that exposes language-service capabilities to external clients.
    4. Clients/Integrations:
      • @volar/vscode: An LSP client that integrates the language server into VS Code.
      • @volar/kit: A wrapper for language-service designed for Node.js applications.
      • @volar/monaco: A bridge that integrates language-service into the Monaco Editor.
  5. Start a language server with @volar/test-utils

    master

    Use the startLanguageServer function to launch a language server instance for testing. This function returns a server handle that allows you to programmatically interact with the server (initializing, opening documents, and sending requests).

    startLanguageServer accepts:

    • modulePath: A string representing the path to the server module.
    • cwd (optional): A string or URL representing the current working directory.
    import { startLanguageServer } from '@volar/test-utils';
    
    const serverHandle = startLanguageServer('path/to/server/module');
  6. Setup a Volar Language Service Worker

    master

    To use Volar features in Monaco, you must implement a Web Worker that initializes a language service. You can use createSimpleWorkerLanguageService for general purposes or createTypeScriptWorkerLanguageService for TypeScript-specific support.

    Basic Worker Setup

    Use createSimpleWorkerLanguageService to initialize the worker context and environment.

    TypeScript Support

    To add TypeScript support, use createTypeScriptWorkerLanguageService. You must provide the typescript instance, compilerOptions, and a uriConverter to map between file names and vscode-uri objects. You should also include the volar-service-typescript plugin.

    Adding ATA (Automatic Type Acquisition) Support

    To enable automatic fetching of type definitions from npm, set the env.fs property using createNpmFileSystem() from @volar/jsdelivr within your worker initialization.

    // my-lang.worker.ts
    import * as worker from 'monaco-editor-core/esm/vs/editor/editor.worker';
    import type * as monaco from 'monaco-editor-core';
    import type { LanguageServiceEnvironment } from '@volar/language-service';
    import { createSimpleWorkerLanguageService } from '@volar/monaco/worker';
    import { URI } from 'vscode-uri';
    
    self.onmessage = () => {
    	worker.initialize((ctx: monaco.worker.IWorkerContext) => {
    		const env: LanguageServiceEnvironment = {
    			workspaceFolders: [
    				URI.parse('file:///'),
    			],
    		};
    		return createSimpleWorkerLanguageService({
    			workerContext: ctx,
    			env,
    			languagePlugins: [],
    			languageServicePlugins: [],
    		});
    	});
    };
  7. Enable Language Features and Diagnostics in Monaco

    master

    Once the worker is configured, use the @volar/monaco utility functions to activate core language features. You must first register the language in Monaco, then create a WebWorker instance, and finally call the activation functions.

    Key functions:

    • activateMarkers: Enables diagnostic markers (errors, warnings, etc.).
    • activateAutoInsertion: Enables automatic tag closing/insertion.
    • registerProviders: Registers IntelliSense/completion providers.

    All these functions require a sync files callback that returns an array of Uri objects representing the current files in the editor context.

    import type { WorkerLanguageService } from '@volar/monaco/worker';
    import { editor, languages, Uri } from 'monaco-editor-core';
    import { activateMarkers, activateAutoInsertion, registerProviders } from '@volar/monaco';
    
    languages.register({ id: 'my-lang', extensions: ['.my-lang'] });
    
    languages.onLanguage('my-lang', () => {
    	const worker = editor.createWebWorker<WorkerLanguageService>({
    		moduleId: 'vs/language/my-lang/myLangWorker',
    		label: 'my-lang',
    	});
    	activateMarkers(
    		worker,
    		['my-lang'],
    		'my-lang-markers-owner',
    		// sync files
    		() => [Uri.file('/Foo.my-lang'), Uri.file('/Bar.my-lang')],
    		editor
    	);
    	// auto close tags
    	activateAutoInsertion(
    		worker,
    		['my-lang'],
    		// sync files
    		() => [Uri.file('/Foo.my-lang'), Uri.file('/Bar.my-lang')],
    		editor
    	);
    	registerProviders(
    		worker,
    		['my-lang'],
    		// sync files
    		() => [Uri.file('/Foo.my-lang'), Uri.file('/Bar.my-lang')],
    		languages
    	)
    });
  8. Configure MonacoEnvironment for custom workers

    master

    To ensure Monaco uses your custom Volar worker instead of the default editor worker, you must assign a loader to the global MonacoEnvironment.getWorker function. This allows Monaco to route requests for specific language labels to your custom worker implementation.

    import editorWorker from 'monaco-editor-core/esm/vs/editor/editor.worker?worker';
    import myWorker from './my-lang.worker?worker';
    
    (self as any).MonacoEnvironment = {
    	getWorker(_: any, label: string) {
    		if (label === 'my-lang') {
    			return new myWorker();
    		}
    		return new editorWorker();
    	}
    }
  9. Use @volar/monaco for Monaco Editor integration

    master

    The @volar/monaco package provides tools to integrate Volar language services with the Monaco Editor. It exports functionality from two main modules:

    1. Editor utilities: Found in ./lib/editor.js, these handle the setup and lifecycle of the Monaco editor instance in relation to Volar.
    2. Language utilities: Found in ./lib/languages.js, these provide tools for configuring and managing language support within the Monaco environment.
  10. How Language Service plugins work via injection

    master

    The LanguageService uses an injection pattern to resolve language features. When a feature (like getHover) is called, the service uses the context.inject method to iterate through registered LanguageServicePlugin instances.

    1. The service checks if a plugin is disabled via context.disabledServicePlugins.
    2. It looks for a matching provide method on the plugin for the requested key.
    3. If found, the plugin's implementation is executed and returned.

    This allows developers to implement specific language features (e.g., provideHover, provideCompletionItems) within a plugin and have them automatically integrated into the main service lifecycle.

  11. Configure feature availability with CodeInformation

    master

    The CodeInformation interface is attached to CodeMappings to control which language features (like diagnostics or autocomplete) are active in specific regions of generated (virtual) code. This allows you to enable features in some parts of a generated file while disabling them in others.

    Available configuration properties:

    • verification: Controls diagnostics (syntactic/semantic) and code actions. Can be a boolean or an object with a shouldReport(source, code) callback to decide if a diagnostic should propagate back to the original source.
    • completion: Controls assisted completion. Can be a boolean or an object with isAdditional and onlyImport flags.
    • semantic: Controls hover, inlay hints, code lens, and semantic tokens. Can be a boolean or an object with a shouldHighlight() callback.
    • navigation: Controls reference relationships, renaming, and symbol resolution. Can be a boolean or an object with shouldHighlight(), shouldRename(), resolveRenameNewName(newName), and resolveRenameEditText(newText).
    • structure: A boolean indicating if the code correctly reflects structural information.
    • format: A boolean indicating if the code correctly reflects formatting information.
    export interface CodeInformation {
    	verification?: boolean | {
    		shouldReport?(source: string | undefined, code: string | number | undefined): boolean;
    	};
    	completion?: boolean | {
    		isAdditional?: boolean;
    		onlyImport?: boolean;
    	};
    	semantic?: boolean | {
    		shouldHighlight?(): boolean;
    	};
    	navigation?: boolean | {
    		shouldHighlight?(): boolean;
    		shouldRename?(): boolean;
    		resolveRenameNewName?(newName: string): string;
    		resolveRenameEditText?(newText: string): string;
    	};
    	structure?: boolean;
    	format?: boolean;
    }
  12. How Volar integrates with TypeScript via the Language Service Host

    master

    The createLanguageServiceHost function creates a specialized ts.LanguageServiceHost that handles several complex integration tasks:

    1. Plugin Extensions: It automatically detects and includes extra file extensions defined by Volar plugins (e.g., .vue, .svelte) in the readDirectory and getCompilationSettings calls. It sets allowNonTsExtensions to true automatically.
    2. Virtual Files & Generated Scripts: It manages the lifecycle of virtual files. If a Volar script is generated, the host can retrieve serviceScripts and extraServiceScripts provided by the language plugin, making them visible to the TypeScript compiler.
    3. Module Resolution: It enhances module resolution by using a ModuleResolutionCache and a custom resolveModuleName function that accounts for Volar's plugin-driven file resolution.
    4. Automatic Synchronization: The host implements a sync() mechanism that checks the projectHost.getProjectVersion() against the last known version. If the project has changed, it refreshes the file registry, virtual snapshots, and script versions to ensure the TypeScript service is working with up-to-date data.