Files
volar-docs/docs/monaco-playground.md
2025-11-09 22:22:52 -06:00

2.9 KiB
Raw Blame History

Building a Volar-Powered Monaco Playground

Docs IndexRepo READMEVolar Kit & EditorLive Examples

This guide walks through wiring Volars language service into a browser-based playground (Vue SFC REPL, documentation site, or sandbox) using @volar/monaco.

Architecture

Monaco Editor (main thread)
  │
  ├─ Worker (language service)
  │    ├─ TypeScript runtime
  │    ├─ Volar language service
  │    └─ Virtual file system (in-memory / IndexedDB)
  └─ UI (tabs, preview)

Step 1: Install Dependencies

npm install monaco-editor @volar/monaco typescript

Step 2: Worker Setup

// volar.worker.ts
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import { setupLanguageServiceForMonaco } from '@volar/monaco';

setupLanguageServiceForMonaco(monaco, {
  loadTypescript: () => import('typescript/lib/typescript.js'),
  loadLanguageService: () => import('./volar-service-entry'),
});

volar-service-entry exports createLanguageService(env) that mirrors your servers factory.

Step 3: Main Thread Wiring

import * as monaco from 'monaco-editor';

monaco.languages.register({ id: 'vue' });
monaco.languages.onLanguage('vue', () => {
  new Worker(new URL('./volar.worker.ts', import.meta.url), { type: 'module' });
});

const model = monaco.editor.createModel('<template>hi</template>', 'vue', monaco.Uri.parse('file:///App.vue'));
monaco.editor.create(document.getElementById('editor')!, { model });

Step 4: Virtual File System

Track files and sync them with the language service host:

const files = new Map<string, string>();

function syncModel(model: monaco.editor.ITextModel) {
  const uri = model.uri.toString();
  files.set(uri, model.getValue());
  languageServiceHost.writeFile(uri, model.getValue());
}

monaco.editor.onDidCreateModel((model) => {
  syncModel(model);
  model.onDidChangeContent(() => syncModel(model));
});

Persist files using localStorage, IndexedDB, or encoded URLs so sessions can be shared.

Step 5: Preview / Output Integration

  • Render an iframe or use the Vue runtime to preview components.
  • Listen for diagnostics via Monaco markers and show a summary list.
  • Capture console output from the preview iframe for debugging.

Performance Tips

  1. Lazy-load worker bundle when a Vue file is opened.
  2. Debounce file sync to avoid flooding the worker.
  3. Reuse the same TypeScript module across workers (via CDN) to reduce bundle size.
  4. For large projects, load files on demand instead of preloading entire repos.

Example Projects

By reusing your existing Volar language-service factory in the browser, you guarantee parity between editor IntelliSense and playground experiences.