拡張機能の構造
前のトピックでは、基本的な拡張機能を動作させるところまで進めました。では、内部ではどのような仕組みで動いているのでしょうか?
Hello World 拡張機能は、次の3つのことを行います。
onCommandアクティベーションイベント:onCommand:helloworld.helloWorldを登録します。これにより、ユーザーがHello Worldコマンドを実行したときに拡張機能がアクティブ化されます。注: VS Code 1.74.0 以降、
package.jsonのcommandsセクションで宣言されたコマンドは、activationEventsに明示的なonCommandエントリを指定しなくても、呼び出された時点で自動的に拡張機能がアクティブ化されます。contributes.commandsコントリビューションポイント を使用して、Hello Worldコマンドをコマンドパレットで利用可能にし、コマンドIDhelloworld.helloWorldにバインドします。commands.registerCommandVS Code API を使用して、関数を登録済みのコマンドIDhelloworld.helloWorldにバインドします。
これら3つの概念を理解することは、VS Code の拡張機能を開発する上で非常に重要です。
- アクティベーションイベント:拡張機能がアクティブ化されるきっかけとなるイベント。
- コントリビューションポイント:VS Code を拡張するために
package.json(拡張機能マニフェスト)内で行う静的な宣言。 - VS Code API:拡張機能コード内で呼び出すことができる JavaScript API のセット。
一般的に、拡張機能はコントリビューションポイントと VS Code API を組み合わせて VS Code の機能を拡張します。拡張機能の機能概要(Extension Capabilities Overview)トピックは、拡張機能に適したコントリビューションポイントや VS Code API を見つけるのに役立ちます。
それでは、Hello World サンプルのソースコードを詳しく見て、これらの概念がどのように適用されているかを確認しましょう。
拡張機能のファイル構造
.
├── .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
設定ファイルについての詳細は以下を参照してください。
しかし、ここでは Hello World 拡張機能を理解するために不可欠な package.json と extension.ts に焦点を当てます。
拡張機能マニフェスト
すべての VS Code 拡張機能には、拡張機能マニフェストとしての package.json が必要です。package.json には、scripts や devDependencies といった Node.js のフィールドと、publisher、activationEvents、contributes といった VS Code 固有のフィールドが混在しています。VS Code 固有の全フィールドの説明は 拡張機能マニフェストのリファレンス で確認できます。以下に、最も重要なフィールドをいくつか挙げます。
nameとpublisher:VS Code は<publisher>.<name>を拡張機能の一意のIDとして使用します。例えば、Hello World サンプルのIDはvscode-samples.helloworld-sampleです。VS Code はこのIDを使用して拡張機能を一意に識別します。main:拡張機能のエントリーポイント。activationEventsとcontributes:アクティベーションイベント と コントリビューションポイント。engines.vscode:拡張機能が依存する VS Code API の最小バージョンを指定します。
{
"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を明示的に記述する必要があります。
拡張機能エントリーファイル
拡張機能のエントリーファイルは、activate と deactivate という2つの関数をエクスポートします。activate は、登録したアクティベーションイベントが発生したときに実行されます。deactivate は、拡張機能が非アクティブ化される前にクリーンアップを行う機会を提供します。多くの拡張機能では明示的なクリーンアップは不要であり、deactivate メソッドを削除しても問題ありません。ただし、VS Code の終了時や拡張機能の無効化・アンインストール時に特定の操作を行う必要がある場合は、このメソッドを使用します。
VS Code 拡張機能 API は、@types/vscode 型定義で宣言されています。vscode 型定義のバージョンは、package.json の engines.vscode フィールドの値によって制御されます。vscode 型を使用することで、コード内で IntelliSense、定義への移動、その他の 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() {}