Files
volar-docs/docs/performance-and-debugging.md
2025-11-09 22:22:52 -06:00

7.0 KiB
Raw Permalink Blame History

Performance & Debugging Playbook

Docs IndexRepo READMETesting & CITelemetry

Volars language server is capable of analyzing massive Vue codebases, but only if you configure, profile, and debug it thoughtfully. This playbook covers every tool, environment flag, and technique for keeping your integrations fast and diagnosable.

Philosophies

  1. Measure first Always gather profiles/metrics before optimizing.
  2. Avoid duplication Hook into Volars existing document, project, and TypeScript caches instead of re-reading files.
  3. Fail loudly Surface configuration errors, missing schemas, and long-running operations via logs/telemetry so users know what to fix.

Profiling Toolkit

1. Volars Built-in Tracing

Set environment variables before launching your LSP:

VOLAR_TRACE=protocol VOLAR_TRACE_DIR=/tmp/volar-trace npm run dev
  • protocol: logs LSP traffic (requests, responses).
  • log: internal logging.

In VS Code, set "volar.vueserver.trace.server": "verbose" to mirror the same behavior.

2. CPU & Heap Snapshots

Run the server with --inspect:

node --inspect-brk dist/server.js
  • Use Chrome DevTools or VS Codes debugger to capture CPU profiles and heap snapshots.
  • Focus on provideDiagnostics and provideCompletionItems if latency spikes while typing.

3. TypeScript Tracing

Enable TS compiler traces to see how TypeScript handles your virtual files:

{
  "vueCompilerOptions": {},
  "tsserver": {
    "logDirectory": "./.ts-log",
    "trace": "messages"
  }
}

Review .ts-log/tsserver.log for slow operations (syntaxDiag, semanticDiag, etc.).

Hotspots & Mitigations

Hotspot Symptom Mitigation
Diagnostics re-run on every keystroke CPU spikes Debounce validations (VALIDATION_DELAY), skip unchanged documents, skip workspace diagnostics unless requested.
Re-parsing large snapshots Memory churn Cache AST/metadata on IScriptSnapshot instances and reuse in language-service plugins.
Schema fetch storms Network latency Cache with cacheSchemas, support offline file:// URIs, respect HTTP cache headers.
Duplicate TypeScript programs Slow TS features Use createTypeScriptProject once per config and reuse the returned project.
Logging too verbose Performance drag Gate debug logging behind env vars / user settings.

Debugging Scenarios

Scenario 1: Missing Diagnostics

Checklist:

  1. Verify provideDiagnostics runs by logging entry/exit.
  2. Ensure mappings have verification: true.
  3. Confirm the documents language ID matches your plugins target.
  4. Check connection.sendDiagnostics for errors (watch the LSP trace).

Scenario 2: Incorrect Hover Text

  1. Inspect the generated virtual code (codeGen.getText()) to ensure the content is what you expect.
  2. Use @volar/source-map to verify the mapping covers the range you hovered.
  3. Check that provideHover returns MarkdownString/string in the format the client expects (no stray triple backticks unless intended).

Scenario 3: Memory Leak

  1. Take heap snapshots before/after opening large files.
  2. Confirm you dispose snapshots (call dispose on IScriptSnapshot if you allocate custom ones).
  3. Remove references to old projects/documents when workspace folders change (watch server.workspaceFolders.onDidChange).

Scenario 4: Take Over Mode Conflicts

  1. Verify only one TypeScript server is running (disable built-in TS in VS Code when using Volar).
  2. Check tsserver.log to ensure the Volar TS plugin is loaded once per project.
  3. Provide documentation/instructions for users to disable conflicting extensions.

Logging & Diagnostics

Structured Logging

const log = (message: string, data?: unknown) => {
  connection.console.info(`[json-yaml] ${message} ${data ? JSON.stringify(data) : ''}`);
};
  • Use connection.console for logs visible in the clients output channel.
  • Reserve console.error for actionable failures (schema fetch errors, config parse failures).

Telemetry Hooks

connection.telemetry.logEvent({
  type: 'json-yaml.schemaFetch',
  uri,
  duration,
  success,
});
  • Emit events for expensive operations (schema fetch, TypeScript project reload) to help downstream clients aggregate data.
  • Keep personally identifiable information out of telemetry payloads.

Work Done Progress

const progress = await connection.window.createWorkDoneProgress();
progress.begin('Fetching schemas', 0, 'Starting');
progress.report(50, 'Halfway');
progress.done();
  • Use for long-running operations (initial project load, workspace diagnostics).

Best Practices for Performance-Sensitive Hooks

Diagnostics

  • Track pending validations per URI; cancel the previous timer when new edits arrive.
  • Compare document versions before publishing to avoid stale updates.
  • Use workspace diagnostics sparingly; provide a manual “Refresh Diagnostics” command if theyre expensive in your environment.

Completions

  • Precompute completion data (e.g., known components, JSON schema values) and reuse across requests.
  • Return resolved items via resolveCompletionItem only when the client asks; keep the initial list lightweight.

Hovers

  • Avoid heavy computation in provideHover. Pre-parse metadata (docstrings, schema descriptions) when loading the project.
  • Cache hover results for stable nodes (component props) and invalidate when the underlying file changes.

TypeScript Integration

  • Use createTypeScriptProject once per config and share the result across all language services to leverage TSs incremental caching.
  • Avoid calling project.reload() unless absolutely necessary; prefer targeted invalidation (e.g., language.scripts.delete(uri)).

Troubleshooting Checklist

  1. Is the issue limited to specific files? Inspect their generated output and mappings.
  2. Does it happen after hot reload or configuration changes? Check applyConfiguration to ensure youre not re-registering plugins or leaking state.
  3. Is TypeScript raising errors? Examine tsserver.log and ensure your TS plugin is registering correctly.
  4. Are you duplicating watchers? One file watcher per project is sufficient; extra watchers can saturate the event loop.
  5. Is schema resolution slow? Provide resolveWorkspaceUri to avoid hitting network paths unnecessarily and cache responses aggressively.

When to Ask for Help

  • Capture logs (VOLAR_TRACE, tsserver.log, heap/CPU profiles) and file an issue with the relevant data.
  • Include your tsconfig/jsconfig, workspace structure, and steps to reproduce.
  • Mention whether Take Over Mode is enabled and which editor youre using.

By following this playbook, you can keep Volar integrations responsive while making it easy to diagnose issues when they arise. Profile often, log judiciously, and share configuration knobs with your users so they can tailor performance to their workflow.