【VS Code拡張機能開発】チームの開発生産性を極限まで引き上げる!自分専用カスタムコマンドの作り方
こんにちは。テックリードとして日々チームの開発生産性とコード品質に向き合っている私から、今日はすべての開発者に送る「VS Code拡張機能(Extension)自作のすすめ」をお話しします。
世の中には数万を超える素晴らしい拡張機能が溢れていますが、「自社の特定レポジトリ構造に合わせた定型ファイルの生成」「複雑なクエリのフォーマット」「社内APIを叩いてスニペットを挿入する作業」など、プロジェクト固有の「面倒な繰り返し作業」はどうしても残ります。
「既存のツールでカバーできないなら、自分たちで作ればいい」。
今回は、Yeomanを用いた雛形の生成から、実務で即戦力となるコマンドの実装、そしてチーム全体へシームレスに展開するためのベストプラクティスまで、プロのアーキテクチャ視点で徹底解説します。
—
1. なぜ「拡張機能の自作」が開発スピードを劇的に変えるのか?
多くの開発者は、面倒な作業があるとシェルスクリプトを書いたり、マクロを組んだりします。しかし、それをVS Codeの「コマンドパレット(`Ctrl + Shift + P` / `Cmd + Shift + P`)」から直接呼び出せるようにした瞬間、UX(ユーザーエクスペリエンス)は劇的に向上します。
- コンテキストの維持: エディタから手を離さず、アクティブなファイルパスや選択テキストをそのまま処理できる。
- 強固な型安全性: TypeScriptベースで開発できるため、VS Codeの豊富なAPI(`vscode.window`, `vscode.workspace`)を安全かつ迷いなく叩ける。
- 圧倒的な属人化の排除: 拡張機能としてパッケージング(`.vsix`)すれば、チームメンバー全員が同一の操作感で自動化の恩恵を受けられる。
—
2. 開発環境のセットアップとYeomanによる最速の雛形生成
拡張機能の足回りを構築する際、手動で`package.json`やTypeScriptの設定を書くのは時間の無駄です。公式が提供するスキャッフォールディングツール `yo`(Yeoman)と `generator-code` を用いて、一瞬で堅牢なプロジェクト構造を構築します。
実行コマンドとプロセス
ターミナルを開き、以下のコマンドを実行してジェネレーターをインストールし、プロジェクトを生成します。
Node.js環境が必須です(LTS推奨)
拡張機能開発用のジェネレーターとTypeScriptコンパイラをグローバルインストール
npm install -g yo generator-code typescript
拡張機能生成ウィザードの起動
yo code
ウィザードでは、以下のように対話形式で選択します(TypeScript推奨)。
- `What type of extension do you want to create?` -> New Extension (TypeScript)
- `What’s the name of your extension?` -> dev-accelerator
- `What’s the identifier of your extension?` -> dev-accelerator
- `What’s the description of your extension?` -> Team specific productivity booster
- `Initialize a git repository?` -> Yes
生成されたディレクトリ構造の核心は、以下の2つのファイルに集約されます。
1. `package.json`: 拡張機能のメタデータ、依存関係、そして「どのコマンドをどこに配置するか(コントリビューションポイント)」を定義する設計図。
2. `src/extension.ts`: コマンドが実行された際に実際に動くロジックを記述するエントリーポイント。
—
3. 実装:アクティブなファイル名を元に「定型ドキュメント」を自動生成するコマンド
今回は実務で非常によくあるユースケースとして、「現在開いているファイルのパスと名前を取得し、タイムスタンプ付きのMarkdownログを自動で挿入するカスタムコマンド」を実装します。
package.json の設定(コントリビューションの定義)
まずは、VS Codeに対して「我が拡張機能にはこういうコマンドがありますよ」と宣言します。`package.json` の `contributes` プロジェクトを次のように記述します。
{
“name”: “dev-accelerator”,
“displayName”: “Dev Accelerator”,
“version”: “1.0.0”,
“engines”: {
“vscode”: “^1.75.0” // ターゲットとする最低限のVS Codeバージョン
},
“categories”: [
“Other”
],
“activationEvents”: [], // 最近のVS Codeではコマンド指定による自動アクティベーションが主流
“main”: “./out/extension.js”, // コンパイル後のエントリーポイント
“contributes”: {
“commands”: [
{
“command”: “dev-accelerator.insertAuditLog”, // コマンドID(一意である必要あり)
“title”: “Audit: タイムスタンプ付きログを挿入” // コマンドパレットに表示される名前
}
],
“keybindings”: [
{
“command”: “dev-accelerator.insertAuditLog”,
“key”: “ctrl+alt+l”,
“mac”: “cmd+alt+l”,
“when”: “editorTextFocus” // エディタにフォーカスがある時のみ発火
}
]
},
“scripts”: {
“vscode:prepublish”: “npm run compile”,
“compile”: “tsc -p ./”,
“watch”: “tsc -watch -p ./”
},
“devDependencies”: {
“@types/node”: “^16.11.7”,
“@types/vscode”: “^1.75.0”,
“typescript”: “^4.9.4”
}
}
src/extension.ts の実装(ロジックの記述)
次に、実際の処理をTypeScriptで記述します。エディタのカーソル位置へのテキスト挿入や、アクティブなドキュメントの取得方法に注目してください。
import as vscode from ‘vscode’;
// 拡張機能がアクティベートされた時(コマンドが最初に呼び出された時)に一度だけ実行される
export function activate(context: vscode.ExtensionContext) {
console.log(‘拡張機能 “dev-accelerator” が正常に起動しました。’);
// package.jsonで定義したコマンドIDと、実行される関数を紐付ける
const disposable = vscode.commands.registerCommand(‘dev-accelerator.insertAuditLog’, async () => {
// 現在アクティブなテキストエディタを取得
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showWarningMessage(‘アクティブなテキストエディタが存在しません。’);
return;
}
// 現在開いているファイルのワークスペースからの相対パスを取得
const workspaceFolder = vscode.workspace.getWorkspaceFolder(editor.document.uri);
const relativePath = workspaceFolder
? vscode.workspace.asRelativePath(editor.document.uri)
: editor.document.fileName;
// 現在の日時をフォーマット生成
const now = new Date().toISOString();
// 挿入するスニペット文字列の構築
const logSnippet = `\n/ — AUDIT: ${now} | File: ${relativePath} — /\n`;
// エディタの編集操作(テキストの挿入)を実行
await editor.edit(editBuilder => {
// 現在のカーソル位置(複数カーソル対応なら最初のカーソル)にテキストを挿入
const position = editor.selection.active;
editBuilder.insert(position, logSnippet);
});
vscode.window.showInformationMessage(‘監査ログコメントを挿入しました!’);
});
// 拡張機能が破棄されるときにメモリリークを防ぐためクリーンアップ登録
context.subscriptions.push(disposable);
}
// 拡張機能が無効化された時の処理
export void deactivate() {}
—
4. デバッグとローカルテストの極意
コードを書いたら、即座に挙動を確認します。
1. VS Codeでプロジェクトを開いた状態で、`F5` キーを押下します。
2. 「Extension Development Host」という新しいVS Codeウィンドウが立ち上がります(これがデバッグ用のサンドボックス環境です)。
3. その新しいウィンドウ内で適当なファイルを開き、`Ctrl + Alt + L`(Macは `Cmd + Alt + L`)を押す、または `Ctrl + Shift + P` から `Audit: タイムスタンプ付きログを挿入` を実行します。
4. カーソル位置に綺麗にログが挿入されれば成功です!
—
5. チーム開発で爆発的な効果を生む「設定共有化」とベストプラクティス
自作した拡張機能は、自分だけで使っていては勿体ありません。チームメンバー全員に強制、あるいはスムーズに共有するための実務的なテクニックを共有します。
1. `.vscode/extensions.json` による拡張機能の推奨(Recommendation)
レポジトリのルートに `.vscode/extensions.json` を配置し、自作拡張機能(またはチーム必須の拡張機能)を定義します。これにより、メンバーがレポジトリを開いた瞬間に「このプロジェクトに必要な拡張機能がインストールされていません。インストールしますか?」という通知を出せます。
{
“recommendations”: [
“publisher-name.dev-accelerator”, // 自社発行の拡張機能ID
“dbaeumer.vscode-eslint”, // チーム必須のESLint
“esbenp.prettier-vscode” // チーム必須のPrettier
]
}
2. VSIXパッケージとしてのオフライン配布とCI/CDによる自動化
自社製拡張機能をマーケットプレイスに公開したくない(プライベートな)場合、`.vsix` ファイルというパッケージ形式に固めて共有します。
拡張機能のパッケージングツール(vsce)のインストール
npm install -g vsce
.vsix ファイルのビルド
vsce package
生成された `dev-accelerator-1.0.0.vsix` ファイルをチームのチャットツールに貼るか、社内ストレージに置くだけです。インストールは、拡張機能タブの右上の「…」メニューから「VSIX からのインストール…」を選択するだけ完了します。さらにこれをGitHub ActionsなどのCI/CDパイプラインに組み込み、mainブランチへのマージ時に自動でVSIXをビルドしてS3や社内サーバーにアップロードする仕組みを構築すれば、拡張機能のバージョンアップ運用すら自動化できます。
—
テックリードからの総括
今回紹介した拡張機能開発は、ほんの氷山の一角に過ぎません。VS Codeの拡張機能APIを叩けば、外部のREST APIと連携したコードレビュー支援ツールや、社内規約に違反したコードを自動検知して書き換える独自のLint機能まで、自由自在に構築可能です。
「開発のめんどくさい」をテクノロジーでハックし、チーム全体の開発体験(Developer Experience)を最高のものに引き上げてください。あなたのコードが、チームの明日からの生産性を劇的に変える第一歩になるはずです。