VSCode Extension Expert
A comprehensive guide for developing Visual Studio Code extensions using TypeScript/JavaScript. This skill is built directly from the official VSCode extension samples repository and covers everything from basic extension creation to advanced language features, custom editors, and publishing workflows.
π― Getting Started with Official Generator
The best way to create a new VS Code extension is by using the official Yeoman generator tool.
Prerequisites
Ensure you have Node.js and Git installed.
Creating a New Extension
Option 1: One-time use (recommended)
npx --package yo --package generator-code -- yo code
Option 2: Global installation
npm install --global yo generator-code
yo code
After Creation
- Open the extension folder in VS Code
- Navigate to
src/extension.ts - Press F5 to launch Extension Development Host
- Test from Command Palette (Ctrl+Shift+P)
π οΈ How to Use This Skill
Starting a New Extension
"I want to create a new VS Code extension"
"Help me set up a VS Code extension project"
During Development
"How do I add a new command?"
"My extension isn't loading, can you help me debug?"
"I want to create a webview panel"
Working with Generated Projects
I'll respect your choices:
- Package manager: npm, yarn, pnpm, or bun
- Bundler: webpack, esbuild, or unbundled
- Language: TypeScript or JavaScript
- Extension type: commands, themes, language support, etc.
Core Concepts
Extension Anatomy
Basic package.json
{
"name": "my-extension",
"displayName": "My Extension",
"version": "0.0.1",
"engines": { "vscode": "^1.85.0" },
"categories": ["Other"],
"activationEvents": ["onCommand:extension.helloWorld"],
"main": "./out/extension.js",
"contributes": {
"commands": [{
"command": "extension.helloWorld",
"title": "Hello World"
}]
}
}
Extension Entry Point
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
console.log('Extension "my-extension" is now active!');
const disposable = vscode.commands.registerCommand('extension.helloWorld', () => {
vscode.window.showInformationMessage('Hello World!');
});
context.subscriptions.push(disposable);
}
export function deactivate() {}
Common Patterns
Command Registration
const commands = [
vscode.commands.registerCommand('extension.doSomething', () => {
// Implementation
}),
vscode.commands.registerCommand('extension.doSomethingElse', () => {
// Another command
})
];
context.subscriptions.push(...commands);
Status Bar Integration
const statusBarItem = vscode.window.createStatusBarItem(
vscode.StatusBarAlignment.Right,
100
);
statusBarItem.text = '$(gear) My Extension';
statusBarItem.tooltip = 'My Extension Status';
statusBarItem.command = 'extension.toggleFeature';
statusBarItem.show();
context.subscriptions.push(statusBarItem);
Webview Development
Basic Webview
export function createWebviewPanel(context: vscode.ExtensionContext) {
const panel = vscode.window.createWebviewPanel(
'myWebview',
'My Webview',
vscode.ViewColumn.One,
{
enableScripts: true,
retainContextWhenHidden: true
}
);
panel.webview.html = getWebviewContent(context.extensionUri);
panel.webview.onDidReceiveMessage(
message => {
switch (message.command) {
case 'alert':
vscode.window.showInformationMessage(message.text);
return;
}
},
undefined,
context.subscriptions
);
return panel;
}
Tree View Provider
export class TreeDataProvider implements vscode.TreeDataProvider<TreeItem> {
private _onDidChangeTreeData: vscode.EventEmitter<TreeItem | undefined | null | void> = new vscode.EventEmitter<TreeItem | undefined | null | void>();
readonly onDidChangeTreeData: vscode.Event<TreeItem | undefined | null | void> = this._onDidChangeTreeData.event;
private treeItems: TreeItem[] = [];
refresh(): void {
this._onDidChangeTreeData.fire();
}
getTreeItem(element: TreeItem): vscode.TreeItem {
return element;
}
getChildren(element?: TreeItem): Thenable<TreeItem[]> {
if (!element) {
return Promise.resolve(this.treeItems);
}
return Promise.resolve([]);
}
}
Language Features
Code Completion
export class CompletionItemProvider implements vscode.CompletionItemProvider {
provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position,
token: vscode.CancellationToken,
context: vscode.CompletionContext
): vscode.CompletionItem[] {
return [
new vscode.CompletionItem('console.log', vscode.CompletionItemKind.Method),
new vscode.CompletionItem('console.error', vscode.CompletionItemKind.Method)
];
}
}
vscode.languages.registerCompletionItemProvider(
'javascript',
new CompletionItemProvider(),
'.'
);
Configuration
Reading Settings
const config = vscode.workspace.getConfiguration('myExtension');
const enabled = config.get<boolean>('enabled', true);
const apiKey = config.get<string>('apiKey', '');
Configuration Schema (package.json)
{
"contributes": {
"configuration": {
"title": "My Extension",
"properties": {
"myExtension.enabled": {
"type": "boolean",
"default": true,
"description": "Enable/disable the extension"
}
}
}
}
}
Testing
Unit Tests
import * as assert from 'assert';
import * as vscode from 'vscode';
suite('Extension Test Suite', () => {
test('Extension should be present', () => {
assert.ok(vscode.extensions.getExtension('publisher.my-extension'));
});
test('Should register commands', async () => {
const commands = await vscode.commands.getCommands();
assert.ok(commands.includes('extension.helloWorld'));
});
});
Publishing
# Install vsce
npm install -g @vscode/vsce
# Create publisher
vsce create-publisher your-publisher-name
# Package and publish
vsce package
vsce publish
π Official Resources
Primary API Documentation (Authoritative)
Complete VS Code API: @source/vscode-docs/api/ - FIRST REFERENCE
Core References:
- Extension API:
@source/vscode-docs/api/references/vscode-api.md - Extension Manifest:
@source/vscode-docs/api/references/extension-manifest.md - Contribution Points:
@source/vscode-docs/api/references/contribution-points.md
Development Guides:
- Getting Started:
@source/vscode-docs/api/get-started/ - Extension Guides:
@source/vscode-docs/api/extension-guides/ - UX Guidelines:
@source/vscode-docs/api/ux-guidelines/
Code Examples
Core Features (@source/vscode-extension-samples/):
command-sample/- Command registrationtree-view-sample/- Custom tree viewscompletions-sample/- Code completionwebview-sample/- Custom UI panelscustom-editor-sample/- Custom file editors
Quick Reference
Essential APIs
vscode.commands.registerCommand()- Register commandsvscode.window.createWebviewPanel()- Create webviewsvscode.window.createTreeView()- Create tree viewsvscode.languages.registerCompletionItemProvider()- Add completionsvscode.workspace.getConfiguration()- Read settingsvscode.window.createStatusBarItem()- Status bar items
Common Contribution Points
contributes.commands- Register commandscontributes.views- Add view containerscontributes.configuration- Add settingscontributes.languages- Define new languagescontributes.themes- Custom themes
Essential Commands
npx --package yo --package generator-code -- yo code
npm run compile # Compile TypeScript
npm run watch # Watch for changes
npm test # Run tests
npm run package # Package extension
vsce publish # Publish to marketplace
Troubleshooting
Common Issues:
- Extension not loading: Check
engines.vscodeversion - Commands not registering: Verify command IDs match in package.json
- Activation issues: Check activationEvents
Debug Techniques:
- Use
console.log()(Developer Tools console) - Help > Toggle Developer Tools
- View > Output > Extension Host
See references/ADVANCED.md for advanced topics like file system providers, terminal integration, and performance optimization. See references/EXAMPLES.md for complete extension templates and detailed implementation examples.