Extension Anatomy

In the last topic, you were able to get a basic extension running. How does it work under the hood?

The Hello World extension does 3 things:

Understanding these three concepts is crucial to writing extensions in VS Code:

In general, your extension would use a combination of Contribution Points and VS Code API to extend VS Code’s functionality. The Extension Capabilities Overview topic helps you find the right Contribution Point and VS Code API for your extension.

Let’s take a closer look at Hello World sample’s source code and see how these concepts apply to it.

Extension File Structure

  1. .
  2. ├── .vscode
  3. ├── launch.json // Config for launching and debugging the extension
  4. └── tasks.json // Config for build task that compiles TypeScript
  5. ├── .gitignore // Ignore build output and node_modules
  6. ├── README.md // Readable description of your extension's functionality
  7. ├── src
  8. └── extension.ts // Extension source code
  9. ├── package.json // Extension manifest
  10. ├── tsconfig.json // TypeScript configuration

You can read more about the configuration files:

  • launch.json used to configure VS Code Debugging
  • tasks.json for defining VS Code Tasks
  • tsconfig.json consult the TypeScript Handbook

However, let’s focus on package.json and extension.ts, which are essential to understanding the Hello World extension.

Extension Manifest

Each VS Code extension must have a package.json as its Extension Manifest. The package.json contains a mix of Node.js fields such as scripts and dependencies and VS Code specific fields such as publisher, activationEvents and contributes. You can find description of all VS Code specific fields in Extension Manifest Reference. Here are some most important fields:

  • name and publisher: VS Code uses <publisher>.<name> as a unique ID for the extension. For example, the Hello World sample has the ID vscode-samples.helloworld-sample. VS Code uses the ID to uniquely identify your extension
  • main: The extension entry point.
  • activationEvents and contributes: Activation Events and Contribution Points.
  • engines.vscode: This specifies the minimum version of VS Code API that the extension depends on.
  1. {
  2. "name": "helloworld-sample",
  3. "displayName": "helloworld-sample",
  4. "description": "HelloWorld example for VS Code",
  5. "version": "0.0.1",
  6. "publisher": "vscode-samples",
  7. "repository": "https://github.com/microsoft/vscode-extension-samples/helloworld-sample",
  8. "engines": {
  9. "vscode": "^1.34.0"
  10. },
  11. "categories": ["Other"],
  12. "activationEvents": ["onCommand:extension.helloWorld"],
  13. "main": "./out/extension.js",
  14. "contributes": {
  15. "commands": [
  16. {
  17. "command": "extension.helloWorld",
  18. "title": "Hello World"
  19. }
  20. ]
  21. },
  22. "scripts": {
  23. "vscode:prepublish": "npm run compile",
  24. "compile": "tsc -p ./",
  25. "watch": "tsc -watch -p ./"
  26. },
  27. "devDependencies": {
  28. "@types/node": "^8.10.25",
  29. "@types/vscode": "^1.34.0",
  30. "tslint": "^5.16.0",
  31. "typescript": "^3.4.5"
  32. }
  33. }

Extension Entry File

The extension entry file exports two functions, activate and deactivate. activate is executed when your registered Activation Event happens. deactivate gives you a chance to clean up before your extension becomes deactivated. For many extensions, explicit cleanup may not be required, and the deactivate method can be removed. However, if an extension needs to perform an operation when VS Code is shutting down or the extension is disabled or uninstalled, this is the method to do so.

The vscode module contains a script located at ./node_modules/vscode/bin/install. The script pulls the VS Code API definition file depending on the engines.vscode field in package.json. After running the script, you would get IntelliSense, jump to definition and other TypeScript language features in your code.

  1. // The module 'vscode' contains the VS Code extensibility API
  2. // Import the module and reference it with the alias vscode in your code below
  3. import * as vscode from 'vscode';
  4. // this method is called when your extension is activated
  5. // your extension is activated the very first time the command is executed
  6. export function activate(context: vscode.ExtensionContext) {
  7. // Use the console to output diagnostic information (console.log) and errors (console.error)
  8. // This line of code will only be executed once when your extension is activated
  9. console.log('Congratulations, your extension "helloworld-sample" is now active!');
  10. // The command has been defined in the package.json file
  11. // Now provide the implementation of the command with registerCommand
  12. // The commandId parameter must match the command field in package.json
  13. let disposable = vscode.commands.registerCommand('extension.helloWorld', () => {
  14. // The code you place here will be executed every time your command is executed
  15. // Display a message box to the user
  16. vscode.window.showInformationMessage('Hello World!');
  17. });
  18. context.subscriptions.push(disposable);
  19. }
  20. // this method is called when your extension is deactivated
  21. export function deactivate() {}