6.6 KiB
TypeScript Plugin Deep Dive (@volar/vue-typescript, @vue/language-core)
Docs Index • Repo README • Plugin Authoring • Configuration & Projects • Testing & CI
Volar’s 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.vueSFCs, generates script blocks, template AST, source maps.@volar/vue-language-core: Default Volar language plugin for.vue.@volar/vue-typescript: TypeScript plugin that plugs intotsserverto expose.vuevirtual 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
.vueas 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.mdor.htmlfiles 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) orvueCompilerOptions.strictTemplatesto tune template diagnostics. - On the TS side, configure
tsconfig.jsoncompilerOptions(strict,noUnusedLocals) to control script diagnostics as usual.
Debugging Techniques
tsserver.log– enable viatsserver.logDirectoryto inspect how Volar registers.vuefiles.VOLAR_TRACE=log– inspect plugin initialization, config resolution.codeGen.getText()inspection – verify generated TS code for templates.- TS Server Plugins – run
tsservermanually with--logVerbosity verboseto 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 it’s 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:
- Implementing a language plugin (virtual code) similar to
@volar/vue-language-core. - Wiring it into
@volar/typescript(customcreateLanguageServiceHost). - 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 Volar’s TS integration for any advanced use case—macros, alternate file extensions, strict template checks, or entirely new component languages.