数回前にWordPressの更新に便利なVS Codeの拡張機能WordPress Postを紹介しました。
この拡張機能を試してみて、VS Codeでの拡張機能の作り方に興味がでてきたので、基本的な作り方を調べてみたいと思います。
VS Codeの拡張機能
Visual Studio Code (VS Code)には非常に多くの拡張機能が公開されています。
このブログでもいくつか拡張機能を紹介してきました。
VS Codeの魅力の1つがこれらの拡張機能によって、使い勝手や機能を拡張できることだと思います。
その拡張機能ですが当然ながら自分で作成することもできます。オフィシャルなガイドは英語となりますが、下記になります。
今回はこのオフィシャルドキュメントの「GET STARTED」を試してみたいと思います。
ちなみに利用する環境はWindows上のVS Codeですが、Remote-WSL拡張機能を導入して、WSL2 (ディストリビューションはUbuntu 20.04LTS)上で開発を行います。
Remote-WSL拡張機能については下記を参照してください。
準備
まずVS Codeの拡張機能を開発するために必要な環境を整えます。
今回はRemote-WSL拡張機能を使ってWSL2(Ubuntu 20.04LTS)上で開発するので、環境の整備はWSL2上で行っていきます。
VS Codeの拡張を機能を開発するためにはまずNode.jsが必要となります。
私がWSL2で利用しているUbuntu 20.04LTSにもNode.jsのパッケージがあるのですが、こちらのバージョンは「v10.19.0」となっており、かなり古めです。そのため、後述のYeomanというツールが動きません。
ここはNodeSourceで提供されているパッケージを利用しましょう。利用するバージョンはこの記事の作成時点(2022年6月)にアクティブLTSであるv16です。
まずNodeSourceの提供するパッケージ情報を取り込みます。
$ curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
つづいてNode.jsをインストールします。
$ sudo apt-get install nodejs
私が試したときにはインストールされたNode.jsのバージョンはV16.15.1でした。
$ node --version v16.15.1
次にYeomanというツールとVS Code Extension Generatorを次のコマンドで導入します。
$ sudo npm install -g yo generator-code
これでとりあえず準備完了です。
私が試したときには次のようなメッセージが表示されました。
added 899 packages, and audited 900 packages in 25s 64 packages are looking for funding run `npm fund` for details 7 high severity vulnerabilities To address issues that do not require attention, run: npm audit fix To address all issues (including breaking changes), run: npm audit fix --force Run `npm audit` for details. npm notice npm notice New minor version of npm available! 8.11.0 -> 8.12.1 npm notice Changelog: https://github.com/npm/cli/releases/tag/v8.12.1 npm notice Run npm install -g npm@8.12.1 to update! npm notice
脆弱性(vulnerabilities)は気になるところですが、とりあえず新しいパッケージがあるというものだけは更新しておきました。
$ sudo npm install -g npm@8.12.1
サンプルプロジェクトの準備
環境が用意できたら、適当なフォルダを作成して、シンプルな拡張機能のコードを生成します。
$ mkdir -p ~/projects/first-extension $ cd ~/projects/first-extension $ yo code
しばらくすると次のようなメニューが表示されます。
上下のカーソルキーでメニュー項目を選べるので「New Extension (TypeScript)」を選択します。選択はリターンキーです。
続いて拡張機能の名前を要求されます。
今回は「HelloWorld」と入力します。
次は拡張機能の識別子の入力ですが、拡張機能の名前を元に自動設定されているので、そのままリターンキーを押せばOKです。
次は拡張機能の説明文です。これは空欄でも問題ないので、そのままリターンキーを押します。
次はGitレポジトリして初期化するかどうかなので「Y」を入力します。
その次はwebpackを利用するかどうかですが「N」として良いようです。
次は利用するパッケージマネージャの選択なので「npm」を選択します。
これでファイルが生成され、また、必要なパッケージが導入されます。
私の場合は、途中でgit initのエラーが出ましたが、とりあえず無視します。
最後にVS Codeを起動するかどうかを聞かれます。
WSL2上でWindowsのVS Codeを起動できる状態であれば、ここは「Open with `code`」を選んでOKです。
VS Codeが立ち上がると、フォルダを信用するかどうかを聞かれるので「はい、作成者を信頼します」を選択します。
また、オススメの拡張機能が表示されたらインストールしておきます。
最終的にはVS Codeのエクスプローラは次のような状態になるはずです。
これで拡張機能の作成するためのプロジェクトが作成できました。
ついでにこのプロジェクトを実行してみましょう。VS Codeのメニューで「実行」→「デバッグの開始」を選択するかF5キーを押してみます。
すると新しいVS Codeのウィンドウが立ち上がります。このウィンドウの名称部分には「開発環境開発ホスト」と表示されており、開発環境を試すための特別なウィンドウであることがわかります。
先ほどコード生成をしたHello World拡張機能は、この新しく生成されたウィンドウで有効になっています。
そこでこのウィンドウのコマンドパレットで「hello」と売ってみると、「Hello World」というコマンドが表示されます。
そしてこの「Hello World」を選択して実行してみると、画面の右下に「Hello World from HelloWorld!」と表示されます。
このメッセージはコード生成で作成された拡張機能により表示されたものになります。
ちなみに「開発環境開発ホスト」のウィンドウを閉じるか、元のVS Codeのウィンドウで表示されるデバッグ用にツールバーで停止を選択すると、拡張機能の実行(デバッグ)は終了します。
今回はVS CodeをWSL2と連携させていますが、問題なく生成した拡張機能をVS Code上から実行できることがわかります。
コードを理解する
自動生成されたコードが動作することを確認したので、これがどんなソースコードから実現されているのかを確認してみます。
この拡張機能のソースコードはsrcフォルダ内のextension.tsです。
内容は次のようになります。
// 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" 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 from HelloWorld!'); }); context.subscriptions.push(disposable); } // this method is called when your extension is deactivated export function deactivate() {}
英語ですがコメントでいろいろ説明されているので、なんとなくやっていることが見えてきます。
このソースコードでは「activate」と「deactivate」という2つの関数が定義されており、それぞれ拡張機能が有効化されたときと無効化されたときに呼ばれます。
今回作成したHelloWorldの拡張機能では、コマンドパレットでこ「Hello World」を実行したときにactivate関数が実行されます。
activateが実行されるタイミングは拡張機能の種類によって違うのだと思いますが、詳しく調査はしていません。
そしてこのactivate関数の中でvscode.commands.registerCommandというAPIを使って、「helloworld.helloWorld」というIDで実行する処理を登録しています。
ここで実行する処理というのは、波括弧で囲まれた範囲で記述された処理で、具体的には「vscode.window.showInofrmationMessage」というAPIを使って「Hello World from HelloWorld!」というメッセージを表示することです。
つまり、これがコマンドパレットで「Hello World」を実行したときに行われる内容になります。
ちなみに後述のブレークポイント等を使って細かく動きを見ると、
- コマンドパレットでの1回目の「Hello World」の実行
activate関数が実行された後に、helloworld.helloWorldというIDで登録した処理の実行 - コマンドパレットでの2回目の「Hello World」の実行
helloworld.helloWorldというIDで登録した処理の実行
となり、activate関数が実行されるのは初回の実行時のみになります。
ここで疑問となるのは、
- なぜコマンドパレットで「Hello World」を入力したときに、helloworld.helloWorldというIDで登録した処理が実行されるのか
- そもそもactivateが実行される前に、なぜコマンドパレットに「Hello World」が現われるのか
だと思います。
その答えはpackage.jsonというファイルにあります。このファイルの「contributes」というキーは次のようになっています。
"contributes": { "commands": [ { "command": "helloworld.helloWorld", "title": "Hello World" } ] },
ここで「command」と「title」というペアで、「helloworld.helloWorld」というIDが「Hello World」という名前と結びつけられていることがわかります。
このためコマンドパレットで「Hello World」を入力すると、「helloworld.helloWorld」というIDで登録された処理が実行されるようです。
activate前にコマンドパレットに「Hello World」が現われるのもこのpackage.jsonのおかげとなります。
これらの仕組みがわかれば、新たなコマンドの追加などもできそうな気がしてきます。
デバッグをする
拡張機能は通常のプログラムと同様にデバッグすることができます。
一番わかりやすいのはブレークポイントとステップ実行だと思います。
まずextension.tsを開き、行番号の左側を左クリックしてみましょう。赤い○が表示されたらその行にブレークポイントが設定されていることになります。
この画面の例では11行目と19行目にブレークポイントが設定されています。
この状態で「実行」→「デバッグの開始」を選択(あるいはF5キー)してみましょう。
そして新たに表示されたVS Codeのウィンドウのコマンドパレットで「Hello World」を実行してみましょう。
すると元のextension.tsを開いていたVS Codeのウィンドウがアクティブになり、11行目がハイライトされます。
コマンドパレットで「Hello World」を実行したことから、extension.tsで定義しているactivate関すが実行され、11行目に設定していたブレークポイントで処理が一時停止しているという状態です。
このとき次のようなツールバーが表示されます。
このツールバーには6個のボタンが用意されており、ボタンの役割は左から
- 続行
- ステップオーバー
- ステップイン
- ステップアウト
- 再起動
- 停止
となります。
ここで「ステップオーバー」を2回実行してみます。すると19行目のブレークポイントで停止をせずに、22行目に到達します。
これはactivate関数が実行された段階では、19行目の処理は「helloworld.helloWorld」というIDの処理として登録されただけで実行されていないからです。
ここで「実行」をすると次は19行目で停止します。
今度はコマンドパレットで「Hello World」が入力されたので、それに対応したIDであるhelloworld.helloWorldの処理が実行されたからです。
左側のコールスタックをみると「_executeControbutedCommand」という関数から、この処理が呼び出されていることがわかります。
また、ここでは有効な情報が表示されていませんが、左側の変数のエリアを使うと、プログラム中の変数の値を確認することができます。
そして「実行」をすると、ShowInformationMessageのAPIが実行され、新たに表示されたVS Codeの方にメッセージが表示されます。
このようにVS Code上から拡張機能を実行することで、ブレークポイント等を活用したデバッグができることがわかります。
VS Codeへのインストール
拡張機能が問題ないことを確認したら次は拡張機能をパッケージングして、VS Codeにインストールできるようにしてみましょう。
拡張機能はVS Codeマーケットプレースに公開して、そこからインストールすることもできます。
今回はあくまでもテスト用の拡張機能なので、マーケットプレースは使用せず、ローカルにインストールする方法を採用します。
パッケージング
拡張機能をパッケージングするには「vsce (Visual Studio Code Extensions)」というツールを利用します。
このツールはnpmで導入可能です。今回はWSL2を利用しているので、WSL2側で下記のコマンドを実行します。
$ sudo npm install -g vsce
以降のパッケージングする際にエラーが出るので、拡張機能のディレクトリにあるREADME.mdは変更しておきましょう。
私は生成されたREADME.mdの中身をごっそり削って、次のような内容にしておきました。
# helloworld拡張機能 この拡張機能はテスト用の拡張機能です。
vsceのインストールに成功したら、続いて作成した拡張機能のディレクトリに移動してvsceコマンドを実行します。
$ cd ~/projects/first-extension/helloworld $ vsce package
途中で
- 「A ‘repository’ field is missing from the ‘package.json’ manifest file.」
- 「LICENSE.md, LICENSE.txt or LICENSE not found」
という警告が出ますが、それぞれ「y」を入力して継続してしまってください。
最終的にhelloworld-0.0.1.vsixというファイルが生成されればパッケージング成功です。
インストール
次は作成されたパッケージ(vsixファイル)をインストールしていきましょう。
VS Codeのサイドパネルで拡張機能を選び、スリードットメニューから「VSIXからのインストール」を選択します。
ファイルを選べるようになるので、先ほどパッケージングしたVSIXファイルを選択します。
Remote-WSL拡張機能でWSL2と連携していれば、WSL2内のVSIXファイルも選択できます。
インストールに成功すると次のようなメッセージが右下に表示されるので「今すぐ再度読み込む」を選択します。
これでインストール済みの拡張機能を確認すると「HelloWorld」という拡張機能がでてインストールに成功していることがわかります。
もちろんインストール完了後はコマンドパレットからこの拡張機能が提供する「hello worldコマンド」を実行可能です。
また、不要になればこの拡張機能画面からアンインストールすることができます。
まとめ
今回はVS CodeとWSL2の組み合わせでVS Codeの拡張機能が作成できるか試してみました。
Remote WSL拡張機能で連携できていれば、WSL2側にNode.jsを導入することで、拡張機能の開発ができることがわかりました。ステップ実行等のデバッグも可能です。
Linuxに慣れている方にはWindows上で環境を構築するより楽かもしれません。
コメント