Files
volar-docs/docs/typescript-plugin-deep-dive.md
2025-11-09 22:22:52 -06:00

6.6 KiB
Raw Permalink Blame History

TypeScript Plugin Deep Dive (@volar/vue-typescript, @vue/language-core)

Docs IndexRepo READMEPlugin AuthoringConfiguration & ProjectsTesting & CI

Volars superpowers come from its tight integration with TypeScript. This guide explains how the Vue/TypeScript bridge works, what hooks you can customize, and how to extend or troubleshoot it.

Architecture Overview

tsserver (TypeScript LS)
  ▲
  │ ts plugin: @volar/vue-typescript
  │   - understands .vue files via language plugins
  │   - surfaces template types to TS
  │   - provides extra diagnostics/completions
  │
Volar Language Service
  ▲
  │ @vue/language-core (compiles SFC)
  │ @volar/typescript (bridge utilities)

Key Packages

  • @vue/language-core: Parses .vue SFCs, generates script blocks, template AST, source maps.
  • @volar/vue-language-core: Default Volar language plugin for .vue.
  • @volar/vue-typescript: TypeScript plugin that plugs into tsserver to expose .vue virtual files.
  • @volar/typescript: Shared helpers for creating TS hosts, merging language + TS snapshots.

Enabling the TypeScript Plugin

VS Code / Volar Extension

Handled automatically when you install the official Volar extension. To customize:

{
  "volar.takeOverMode.enabled": true,
  "volar.tsPlugin": true
}

Neovim / Other Editors

Point the language server at the bundled TS plugin:

require('lspconfig').volar.setup{
  init_options = {
    typescript = {
      tsdk = '/path/to/node_modules/typescript/lib',
    },
  },
}

tsconfig.json

Ensure .vue files are included and allowJs or allowNonTsExtensions is enabled:

{
  "compilerOptions": {
    "allowJs": true,
    "allowNonTsExtensions": true,
    "types": ["vue"]
  },
  "include": ["src/**/*.vue", "src/**/*.ts"]
}

Plugin Internals

Language Plugin (@volar/vue-language-core)

Handles:

  • Parsing <script>, <template>, <style> blocks.
  • Generating virtual TypeScript/JS files with embedded template expressions (.ts + .d.ts).
  • Mapping template expressions to TypeScript expressions (for hover, completion, diagnostics).

Customization Points:

  • resolveTemplateCompilerOptions: adjust template compilation (e.g., macros).
  • compileTemplate: override the default compiler for experimental syntax.

TypeScript Plugin (@volar/vue-typescript)

Responsibilities:

  • Register .vue as a script kind with TS.
  • Provide virtual files to tsserver (getScriptSnapshot, getScriptVersion).
  • Inject specialized TS plugin features (two-slash queries, SFC-specific completions).

Key APIs:

import { createLanguageServerPlugin } from '@volar/vue-typescript';

const plugin = createLanguageServerPlugin(ts, { resolveConfig });
  • resolveConfig(uri) return Vue compiler options (vueCompilerOptions) for each workspace folder.
  • getExternalFiles(project) optionally add extra files (e.g., global components d.ts).

Shared Utilities (@volar/typescript)

  • createLanguageServiceHost(ts, sys, language, asScriptId, projectHost) builds a TS host aware of Volar language scripts.
  • createUriConverter(rootFolders) keeps file/URI conversions consistent.
  • decorateLanguageServiceHost wrap TS host to intercept methods.

Customizing Behavior

Compiler Options (vueCompilerOptions)

Add to tsconfig.json:

{
  "vueCompilerOptions": {
    "target": 3.3,
    "plugins": ["@vue-macros/volar"],
    "data": {
      "useDefineModel": true,
      "macros": ["defineProps", "defineSlots"]
    },
    "experimentalDisableTemplateSupport": false,
    "extensions": ["vue", "md", "mdx"]
  }
}

Notable flags:

  • target: matches Vue runtime version; ensures correct emit.
  • plugins: register compiler transformations (macros, legacy compat).
  • data.useDefineModel: enables <script setup> defineModel.
  • experimentalDisableTemplateSupport: disable template analysis to speed up script-only workflows.
  • extensions: treat additional file extensions as Vue SFCs.

TS Plugin Options

When loading the plugin manually:

createLanguageServer({
  plugins: [
    vueTypescriptPlugin({
      resolveConfig: (workspaceUri) => customVueCompilerOptions[workspaceUri],
      getDocumentRegistry: () => ts.createDocumentRegistry(true),
    }),
  ],
});
  • resolveConfig: supply per-workspace config.
  • getDocumentRegistry: share TS document registry for incremental builds.
  • additionalExtensions: support .md or .html files as SFCs.

Third-Party Macros

Integrate macros by hooking into the compiler plugin system:

import MyMacroPlugin from 'my-vue-macro/volar';

vueCompilerOptions: {
  plugins: [
    MyMacroPlugin({
      // plugin-specific options
    }),
  ],
}

Diagnostics Control

  • Use volar.takeOverMode.diagnosticStyle (VS Code) or vueCompilerOptions.strictTemplates to tune template diagnostics.
  • On the TS side, configure tsconfig.json compilerOptions (strict, noUnusedLocals) to control script diagnostics as usual.

Debugging Techniques

  1. tsserver.log enable via tsserver.logDirectory to inspect how Volar registers .vue files.
  2. VOLAR_TRACE=log inspect plugin initialization, config resolution.
  3. codeGen.getText() inspection verify generated TS code for templates.
  4. TS Server Plugins run tsserver manually with --logVerbosity verbose to trace plugin hooks.

Common Pitfalls

Issue Cause Fix
Duplicate diagnostics Two TS servers running (built-in + Volar) Enable Take Over Mode or disable built-in TS extension.
No template types allowJs / allowNonTsExtensions missing Update tsconfig.
Custom macros undefined Plugin not added to vueCompilerOptions.plugins Register macro plugin and ensure its installed.
TS version mismatch Editor uses different TS than CLI Align typescript dependency across workspace and server.

Extending Beyond Vue

You can build TypeScript plugins for other component formats (e.g., .svelte, .astro) by:

  1. Implementing a language plugin (virtual code) similar to @volar/vue-language-core.
  2. Wiring it into @volar/typescript (custom createLanguageServiceHost).
  3. Providing compiler options/resolvers akin to vueCompilerOptions.

Using the Vue plugin as a reference accelerates custom component language development.

With a solid understanding of the TypeScript plugin stack, you can tailor Volars TS integration for any advanced use case—macros, alternate file extensions, strict template checks, or entirely new component languages.