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 auscontributesleitet 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.jsonund 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.vscodeund die Version des Pakets@types/vscodepassen 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.
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.
Weiterlesen
- Extension veröffentlichen
Publisher-Konto, Zugriffstoken, Pflichtfelder in package.json, vsce package und vsce publish, Vorabversionen, Automatisierung und die zusätzliche Veröffentlichung auf Open VSX.
- Language Server Protocol
Ein Server, viele Editoren: wie das Language Server Protocol Sprachfunktionen vom Editor trennt, welche Nachrichten ausgetauscht werden und wann sich ein eigener Server lohnt.
- TypeScript und Vite einrichten
Ein Build-Setup für Erweiterungen: TypeScript-Konfiguration, Typen für die Browser-APIs, mehrere Einstiegspunkte mit Vite, die Sonderrolle der Content Scripts und Alternativen wie WXT.