Build Your First VS Code Extension: A Step‑by‑Step Tutorial

This tutorial walks developers through the complete process of creating a simple Visual Studio Code extension—from installing Node.js, Git, and Yeoman, to generating project scaffolding, configuring package.json, writing activation code, adding commands and menu items, and testing the extension—while highlighting VS Code's multi‑process architecture and extension limitations.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Build Your First VS Code Extension: A Step‑by‑Step Tutorial

Introduction

Visual Studio Code (VS Code) is a popular, open‑source editor built with TypeScript and Electron. It has over 115k stars on GitHub and a lightweight design that supports many languages through a modular extension system.

Project repository: https://github.com/microsoft/vscode

VS Code Architecture

VS Code runs with several processes:

Main process – handles window management, inter‑process communication, and auto‑updates.

Renderer process – renders the web UI.

Extension host process – runs each extension in an isolated Node.js environment.

Debug process – provides debugging capabilities.

Language services – supply IntelliSense, diagnostics, and navigation for many languages.

Environment Preparation

Install Node.js and Git, then install Yeoman and the VS Code Extension Generator globally: npm install -g yo generator-code Successful installation is confirmed by the command‑line output.

Initialize the Extension Project

Run the generator to scaffold a new extension: yo code The generator asks a series of questions. For this tutorial choose the JavaScript option (the second choice) and fill in the requested fields such as extension name, identifier, description, and package manager.

Project Structure and Configuration

The generated package.json contains key fields:

{
  "name": "test-extension",
  "displayName": "test-extension",
  "description": "vscode extension sample",
  "version": "0.0.1",
  "engines": { "vscode": "^1.52.0" },
  "categories": ["Other"],
  "activationEvents": ["onCommand:test-extension.helloWorld"],
  "main": "./extension.js",
  "contributes": {
    "commands": [{
      "command": "test-extension.helloWorld",
      "title": "Hello World"
    }]
  },
  "scripts": {
    "lint": "eslint .",
    "pretest": "npm run lint",
    "test": "node ./test/runTest.js"
  },
  "devDependencies": {
    "@types/vscode": "^1.55.0",
    "@types/glob": "^7.1.3",
    "@types/mocha": "^8.0.4",
    "@types/node": "^12.11.7",
    "eslint": "^7.19.0",
    "glob": "^7.1.6",
    "mocha": "^8.2.1",
    "typescript": "^4.1.3",
    "vscode-test": "^1.5.0"
  }
}

Adjust the engines.vscode version if your VS Code is older (e.g., change to ^1.52.0).

Extension Entry Point

The generated extension.js defines two lifecycle functions:

// Import the VS Code API
const vscode = require('vscode');
/**
 * @param {vscode.ExtensionContext} context
 */
function activate(context) {
  console.log('Congratulations, your extension "test-extension" is now active!');
  let disposable = vscode.commands.registerCommand('test-extension.helloWorld', function () {
    vscode.window.showInformationMessage('Hello World from test-extension!');
  });
  context.subscriptions.push(disposable);
}
function deactivate() {}
module.exports = { activate, deactivate };

The activate function registers a command that shows an information message; deactivate is called when the extension is unloaded.

Adding a Custom Button via Menus

To add a button to the editor title bar, modify package.json:

"activationEvents": ["*"],
"contributes": {
  "commands": [
    { "command": "test.button", "title": "按钮", "icon": { "light": "./media/light/preview.svg", "dark": "./media/dark/preview.svg" } }
  ],
  "menus": {
    "editor/title": [{ "command": "test.button", "group": "navigation" }]
  }
}

Then extend extension.js to register the new command:

function activate(context) {
  console.log('我在这里!!');
  let disposable = vscode.commands.registerCommand('test-extension.helloWorld', function () {
    vscode.window.showInformationMessage('我改变了 command 的名字!');
  });
  let button = vscode.commands.registerCommand('test.button', function () {
    vscode.window.showInformationMessage('按钮点击');
  });
  context.subscriptions.push(disposable, button);
}

Now the button appears in the editor title bar and shows a message when clicked.

Menu Visibility Conditions

You can restrict the button to JavaScript files using a when clause:

"menus": {
  "editor/title": [{
    "command": "test.button",
    "group": "navigation",
    "when": "resourceLangId == javascript"
  }]
}

The group property controls ordering; navigation has the highest priority.

Summary and Limitations

VS Code extensions let you add commands, menus, and UI elements within a well‑defined sandbox. Extensions cannot directly manipulate the VS Code DOM or inject arbitrary CSS/HTML, which ensures UI stability, prevents breakage from underlying web‑technology changes, and keeps user interactions predictable.

While this guide covers only a small portion of the extension API, it demonstrates the core workflow: set up the environment, scaffold a project, configure package.json, write activation code, and test the result.

Future topics may explore language‑server features such as auto‑completion and diagnostics.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptpluginNode.jsVS CodeExtension DevelopmentYeoman
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.