---
title: 03-扩展剖析
date: 2025-07-31 22:49:30
icon: famicons:logo-markdown
index: true
tags:
categories:
---

<!-- more -->

# 扩展剖析

>[扩展剖析 | Visual Studio Code 扩展 API - VSCode 编辑器](https://vscode.js.cn/api/get-started/extension-anatomy)

在上一主题中，你已经能够运行一个基本的扩展。那么它在底层是如何工作的呢？`Hello World` 扩展做了 3 件事：

- 注册`onCommand`**激活事件**：onCommand:helloworld.helloWorld，因此当用户运行Hello World命令时，扩展就会被激活。

  > **注意：**从 [VS Code 1.74.0](https://vscode.js.cn/updates/v1_74#_implicit-activation-events-for-declared-extension-contributions) 开始，在 `package.json` 的 `commands` 部分中声明的命令在被调用时会自动激活扩展，无需在 `activationEvents` 中显式添加 `onCommand` 条目。

- 使用 [`contributes.commands`](https://vscode.js.cn/api/references/contribution-points#contributes.commands) [**贡献点**](https://vscode.js.cn/api/references/contribution-points)，使 `Hello World` 命令在命令面板中可用，并将其绑定到命令 ID `helloworld.helloWorld`。

- 使用 [`commands.registerCommand`](https://vscode.js.cn/api/references/vscode-api#commands.registerCommand) [**VS Code API**](https://vscode.js.cn/api/references/vscode-api)，将一个函数绑定到已注册的命令 ID `helloworld.helloWorld`。

理解这三个概念对于在 VS Code 中编写扩展至关重要：

- [**激活事件**](https://vscode.js.cn/api/references/activation-events)：扩展被激活的事件。
- [**贡献点**](https://vscode.js.cn/api/references/contribution-points)：你在 `package.json` [扩展清单](https://vscode.js.cn/api/get-started/extension-anatomy#extension-manifest)中进行的静态声明，用于扩展 VS Code。
- [**VS Code API**](https://vscode.js.cn/api/references/vscode-api)：你可以在扩展代码中调用的 JavaScript API 集合。

通常，你的扩展会结合使用贡献点和 VS Code API 来扩展 VS Code 的功能。[扩展功能概述](https://vscode.js.cn/api/extension-capabilities/overview)主题将帮助你为扩展找到合适的贡献点和 VS Code API。

让我们仔细看看 `Hello World` 示例的源代码，了解这些概念是如何应用的。

## 一、[扩展文件结构](https://vscode.js.cn/api/get-started/extension-anatomy#extension-file-structure)

```bash
.
├── .vscode
│   ├── launch.json     // Config for launching and debugging the extension
│   └── tasks.json      // Config for build task that compiles TypeScript
├── .gitignore          // Ignore build output and node_modules
├── README.md           // Readable description of your extension's functionality
├── src
│   └── extension.ts    // Extension source code
├── package.json        // Extension manifest
├── tsconfig.json       // TypeScript configuration
```

你可以阅读更多关于配置文件的信息：

- `launch.json` 用于配置 VS Code [调试](https://vscode.js.cn/docs/debugtest/debugging)
- `tasks.json` 用于定义 VS Code [任务](https://vscode.js.cn/docs/debugtest/tasks)
- `tsconfig.json` 请查阅 TypeScript [手册](https://typescript.net.cn/docs/handbook/tsconfig-json.html)

然而，让我们重点关注 `package.json` 和 `extension.ts`，它们对于理解 `Hello World` 扩展至关重要。

### 1. [扩展清单](https://vscode.js.cn/api/get-started/extension-anatomy#extension-manifest)

每个 VS Code 扩展都必须有一个 `package.json` 作为其[扩展清单](https://vscode.js.cn/api/references/extension-manifest)。`package.json` 混合了 Node.js 字段，如 `scripts` 和 `devDependencies`，以及 VS Code 特定的字段，如 `publisher`、`activationEvents` 和 `contributes`。你可以在[扩展清单参考](https://vscode.js.cn/api/references/extension-manifest)中找到所有 VS Code 特定字段的描述。以下是一些最重要的字段：

- `name` 和 `publisher`：VS Code 使用 `<publisher>.<name>` 作为扩展的唯一 ID。例如，Hello World 示例的 ID 是 `vscode-samples.helloworld-sample`。VS Code 使用此 ID 来唯一识别你的扩展。
- `main`：扩展入口点。
- `activationEvents` 和 `contributes`：[激活事件](https://vscode.js.cn/api/references/activation-events)和[贡献点](https://vscode.js.cn/api/references/contribution-points)。
- `engines.vscode`：这指定了扩展所依赖的 VS Code API 的最低版本。

```typescript
{
  "name": "helloworld-sample",
  "displayName": "helloworld-sample",
  "description": "HelloWorld example for VS Code",
  "version": "0.0.1",
  "publisher": "vscode-samples",
  "repository": "https://github.com/microsoft/vscode-extension-samples/helloworld-sample",
  "engines": {
    "vscode": "^1.51.0"
  },
  "categories": ["Other"],
  "activationEvents": [],
  "main": "./out/extension.js",
  "contributes": {
    "commands": [
      {
        "command": "helloworld.helloWorld",
        "title": "Hello World"
      }
    ]
  },
  "scripts": {
    "vscode:prepublish": "npm run compile",
    "compile": "tsc -p ./",
    "watch": "tsc -watch -p ./"
  },
  "devDependencies": {
    "@types/node": "^8.10.25",
    "@types/vscode": "^1.51.0",
    "tslint": "^5.16.0",
    "typescript": "^3.4.5"
  }
}
```

> **注意**：如果你的扩展目标是 1.74 之前的 VS Code 版本，你必须在 `activationEvents` 中明确列出 `onCommand:helloworld.helloWorld`。

## 二、[扩展入口文件](https://vscode.js.cn/api/get-started/extension-anatomy#extension-entry-file)

扩展入口文件导出了两个函数：`activate` 和 `deactivate`。当注册的**激活事件**发生时，`activate` 被执行。`deactivate` 则在扩展停用之前给你一个清理的机会。对于许多扩展，可能不需要显式清理，并且可以删除 `deactivate` 方法。但是，如果扩展需要在 VS Code 关闭或扩展被禁用或卸载时执行操作，这就是执行此操作的方法。

VS Code 扩展 API 在 [@types/vscode](https://npmjs.net.cn/package/@types/vscode) 类型定义中声明。`vscode` 类型定义的版本由 `package.json` 中 `engines.vscode` 字段的值控制。`vscode` 类型为你的代码提供智能感知（IntelliSense）、转到定义（Go to Definition）以及其他 TypeScript 语言特性。

```typescript
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
  // Use the console to output diagnostic information (console.log) and errors (console.error)
  // This line of code will only be executed once when your extension is activated
  console.log('Congratulations, your extension "helloworld-sample" is now active!');

  // The command has been defined in the package.json file
  // Now provide the implementation of the command with registerCommand
  // The commandId parameter must match the command field in package.json
  let disposable = vscode.commands.registerCommand('helloworld.helloWorld', () => {
    // The code you place here will be executed every time your command is executed

    // Display a message box to the user
    vscode.window.showInformationMessage('Hello World!');
  });

  context.subscriptions.push(disposable);
}

// this method is called when your extension is deactivated
export function deactivate() {}
```

