~/vscode-extensions/extension-erstellen-yeoman/

VS-Code-Extension erstellen mit Yeoman und dem Extension Generator

Mit yo code zum lauffähigen Gerüst: welche Vorlagen es gibt, was in package.json und extension.ts steht, wie Sie einen eigenen Befehl bauen und im Extension Development Host testen.

Eine VS-Code-Extension erstellen Sie am schnellsten mit Yeoman und dem offiziellen Generator generator-code. Der Befehl npx --package yo --package generator-code -- yo code fragt einige Eckdaten ab und erzeugt ein lauffähiges Projekt in TypeScript oder JavaScript, inklusive Debug-Konfiguration und Testgerüst. Mit F5 startet ein zweites VS-Code-Fenster, in dem Ihre Extension aktiv ist. In diesem Artikel bauen Sie darauf eine kleine eigene Funktion: einen Wortzähler für markierten Text.

Voraussetzungen

  • Visual Studio Code in einer aktuellen Version
  • Node.js in einer aktuellen LTS-Version mit npm
  • Git, da der Generator auf Wunsch ein Repository anlegt
  • Grundkenntnisse in TypeScript oder JavaScript. Wie Sie ein Build-Setup mit TypeScript allgemein aufsetzen, zeigt der Artikel TypeScript und Vite für Erweiterungen einrichten.

Schritt 1: Generator starten

npx --package yo --package generator-code -- yo code

Wer den Generator häufiger nutzt, kann beide Pakete auch global installieren (npm install --global yo generator-code) und dann nur yo code aufrufen. Der Generator stellt nacheinander Fragen:

Frage Empfehlung für den Einstieg
Art der Extension New Extension (TypeScript)
Name der Extension Anzeigename, etwa „Wortzähler“
Identifier technischer Name in Kleinbuchstaben, etwa wortzaehler
Beschreibung ein Satz, was die Extension tut
Git-Repository anlegen ja
Bundler für den Anfang ohne, später esbuild oder webpack
Paketmanager npm

Neben Code-Extensions bietet der Generator auch Vorlagen ohne Programmierung: Farbthemen, Sprachunterstützung mit Syntaxhervorhebung, Code-Snippets, Tastenbelegungen und Extension-Pakete, die mehrere Extensions bündeln. Dazu kommen Vorlagen für Sprachpakete, Notebook-Renderer und Web-Extensions.

Schritt 2: Die Projektstruktur

wortzaehler/
├── .vscode/
│   ├── launch.json        Debug-Konfiguration für F5
│   └── tasks.json         Watch-Task für den Compiler
├── src/
│   ├── extension.ts       Einstiegspunkt
│   └── test/              Testgerüst
├── package.json           Manifest der Extension
├── tsconfig.json
├── .vscodeignore          Dateien, die nicht ins Paket gehören
├── CHANGELOG.md
└── README.md

package.json: das Manifest

Die package.json ist nicht nur eine npm-Datei, sondern das Manifest der Extension. Die wichtigsten Felder:

  • engines.vscode: niedrigste VS-Code-Version, mit der die Extension funktioniert.
  • main: Pfad zur kompilierten Einstiegsdatei, etwa ./out/extension.js.
  • contributes: alles, was die Extension deklarativ beiträgt, etwa Befehle, Menüeinträge, Einstellungen, Tastenkürzel oder Sprachen.
  • activationEvents: wann die Extension geladen wird. Für Befehle aus contributes leitet VS Code das in aktuellen Versionen automatisch ab, sodass die Liste oft leer bleiben kann.

extension.ts: der Einstiegspunkt

Die Datei exportiert zwei Funktionen. activate() läuft, sobald die Extension aktiviert wird, deactivate() beim Herunterfahren. Alles, was Sie registrieren, legen Sie in context.subscriptions ab, damit VS Code es beim Deaktivieren sauber aufräumt.

Schritt 3: Mit F5 testen

Öffnen Sie den Projektordner in VS Code und drücken Sie F5. Es öffnet sich ein zweites Fenster mit dem Titel Extension Development Host. Dort ist Ihre Extension geladen. Öffnen Sie die Befehlspalette (Strg+Umschalt+P beziehungsweise Cmd+Umschalt+P auf dem Mac) und rufen Sie den Beispielbefehl „Hello World“ auf. Unten rechts erscheint eine Meldung.

Haltepunkte setzen Sie im Hauptfenster in extension.ts. Ausgaben von console.log erscheinen in der Debug-Konsole des Hauptfensters. Nach Änderungen laden Sie das Testfenster mit dem Befehl „Developer: Reload Window“ neu.

Schritt 4: Einen eigenen Befehl bauen

Ersetzen Sie das Beispiel durch einen Wortzähler. Zuerst die Deklaration in der package.json:

"contributes": {
  "commands": [
    {
      "command": "wortzaehler.zaehlen",
      "title": "Wörter in der Auswahl zählen",
      "category": "Wortzähler"
    }
  ],
  "configuration": {
    "title": "Wortzähler",
    "properties": {
      "wortzaehler.zeichenAnzeigen": {
        "type": "boolean",
        "default": false,
        "description": "Zusätzlich die Zahl der Zeichen anzeigen."
      }
    }
  }
}

Dann die Umsetzung in src/extension.ts:

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  const befehl = vscode.commands.registerCommand('wortzaehler.zaehlen', () => {
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
      vscode.window.showWarningMessage('Kein Editor geöffnet.');
      return;
    }

    const auswahl = editor.selection;
    const text = auswahl.isEmpty
      ? editor.document.getText()
      : editor.document.getText(auswahl);

    const woerter = text.trim() === '' ? 0 : text.trim().split(/\s+/).length;
    const config = vscode.workspace.getConfiguration('wortzaehler');

    let meldung = `${woerter} Wörter`;
    if (config.get<boolean>('zeichenAnzeigen')) {
      meldung += `, ${text.length} Zeichen`;
    }
    vscode.window.showInformationMessage(meldung);
  });

  context.subscriptions.push(befehl);
}

export function deactivate() {}

Die Befehls-ID wortzaehler.zaehlen muss in package.json und in registerCommand exakt übereinstimmen. Die Einstellung erscheint automatisch in den VS-Code-Einstellungen unter „Wortzähler“.

Befehl in ein Menü legen

Über contributes.menus platzieren Sie Befehle etwa im Kontextmenü des Editors. Mit einer when-Bedingung zeigen Sie ihn nur an, wenn Text markiert ist:

"menus": {
  "editor/context": [
    { "command": "wortzaehler.zaehlen", "when": "editorHasSelection" }
  ]
}

Schritt 5: Tests ausführen

Das Gerüst enthält ein Testsetup, das VS Code in einer eigenen Instanz startet und Ihre Tests darin ausführt. Mit npm test laufen sie auf der Kommandozeile, alternativ über die Testansicht in VS Code. Für Extensions mit Logik lohnt es sich, diese in reine Funktionen auszulagern, etwa die Wortzählung, und sie getrennt von der VS-Code-API zu testen.

Bündeln mit esbuild

Ohne Bundler liefert die Extension viele einzelne Dateien und den Ordner node_modules aus. Das macht das Paket groß und den Start langsamer, weil VS Code jede Datei einzeln laden muss. Ein Bundler fasst den Code samt Abhängigkeiten in eine Datei zusammen. Wenn Sie im Generator bereits esbuild oder webpack gewählt haben, ist alles vorbereitet. Andernfalls lässt sich esbuild nachrüsten: Es erhält src/extension.ts als Einstiegspunkt, schreibt nach dist/extension.js, und das Modul vscode wird als extern markiert, weil VS Code es zur Laufzeit bereitstellt. Anschließend zeigt main in der package.json auf die gebündelte Datei, und .vscodeignore schließt Quellcode und node_modules aus.

Wichtig ist das Zusammenspiel mit dem Debugging: Damit Haltepunkte in den TypeScript-Dateien weiterhin funktionieren, muss der Bundler Source Maps erzeugen.

Web-Extensions: VS Code im Browser

VS Code läuft auch im Browser, etwa auf vscode.dev. Dort stehen weder Node.js noch das Dateisystem des Rechners zur Verfügung. Extensions, die auch dort funktionieren sollen, deklarieren in der package.json zusätzlich einen Einstiegspunkt unter browser und dürfen nur Browser-kompatible APIs nutzen. Der Generator bietet dafür eine eigene Vorlage an. Wer von Anfang an auf Node-spezifische Module verzichtet, wo es geht, kann eine Extension später leichter für beide Umgebungen anbieten.

Code sinnvoll aufteilen

Bei wachsenden Extensions lohnt eine klare Struktur: extension.ts registriert nur Befehle und Anbieter, die eigentliche Logik liegt in eigenen Modulen. So bleibt die Aktivierung schlank, und Sie können die Logik ohne laufende VS-Code-Instanz testen. Einstellungen lesen Sie nicht einmalig beim Start, sondern bei Bedarf oder reagieren mit vscode.workspace.onDidChangeConfiguration auf Änderungen.

Was die API sonst noch bietet

Der Wortzähler zeigt nur einen kleinen Ausschnitt. Die VS-Code-API erlaubt unter anderem:

  • Statusleisten-Einträge mit vscode.window.createStatusBarItem(), etwa für einen dauerhaft sichtbaren Zähler
  • Eigene Ansichten in der Seitenleiste über Tree Views
  • Webviews für eigene Oberflächen mit HTML, CSS und JavaScript
  • Sprachfunktionen wie Vervollständigung, Hover-Infos und Diagnosen

Für umfangreiche Sprachunterstützung setzt man meist auf einen Language Server statt auf Einzelfunktionen. Wie das funktioniert, erklärt der Artikel Language Server Protocol einfach erklärt.

Typische Stolpersteine

  • Befehl nicht gefunden: IDs in package.json und Code vergleichen, Watch-Task auf Fehler prüfen.
  • Extension lädt zu früh: Aktivierungsereignisse wie * lassen die Extension bei jedem Start laden und bremsen VS Code. Verwenden Sie gezielte Ereignisse.
  • Ressourcen nicht freigegeben: Alles, was Sie registrieren, gehört in context.subscriptions.
  • Mindestversion zu hoch: engines.vscode und die Version des Pakets @types/vscode passen zusammen, sonst nutzen Sie versehentlich APIs, die ältere Versionen nicht kennen.
  • README unverändert gelassen: Das Veröffentlichungswerkzeug verweigert den Dienst, solange die Vorlagen-README unverändert ist.

Nächster Schritt: Veröffentlichen

Läuft Ihre Extension zuverlässig, können Sie sie als .vsix-Datei weitergeben oder im Visual Studio Marketplace veröffentlichen. Den Ablauf mit Publisher-Konto, Token und dem Werkzeug vsce beschreibt der Artikel VS-Code-Extension im Marketplace veröffentlichen mit vsce.

faq

Fragen und Antworten

TypeScript oder JavaScript für die erste Extension?
TypeScript. Die VS-Code-API ist vollständig typisiert, und der Editor zeigt Ihnen beim Tippen Methoden, Parameter und Dokumentation an. Das spart viel Sucharbeit in der Dokumentation. JavaScript funktioniert ebenfalls, bietet aber weniger Hilfe bei Fehlern.
Warum taucht mein Befehl nicht in der Befehlspalette auf?
Meist stimmt die Befehls-ID in package.json nicht mit der in registerCommand überein, oder der Build ist fehlgeschlagen. Prüfen Sie die Ausgabe des Watch-Tasks und die Debug-Konsole. Auch eine zu hohe Mindestversion in engines.vscode kann verhindern, dass die Extension geladen wird.
Brauche ich einen Bundler?
Für den Anfang nicht zwingend. Für die Veröffentlichung empfiehlt sich ein Bundler wie esbuild oder webpack, weil die Extension dann schneller lädt und das Paket kleiner wird. Für Web-Extensions, die auch in VS Code im Browser laufen sollen, ist Bündeln Pflicht.
Funktioniert meine Extension auch in anderen Editoren auf VS-Code-Basis?
Häufig ja, denn viele Editoren übernehmen die Extension-API von VS Code. Sie beziehen Extensions aber teils nicht aus dem Visual Studio Marketplace, sondern aus Open VSX. Wer diese Nutzer erreichen will, veröffentlicht zusätzlich dort.