- 王紹宇
- Programming
- 約 6,000 文字
- 2,100 View
前書き
VSCode は、多くの IT 従事者に愛用されています。開発、コンパイル、テストに限らず、コードレビューや障害調査、ドキュメント整理など、さまざまな場面で活躍します。さらに、拡張機能を活用すれば、日常の繰り返し作業を自動化もできます。
普段は VSCode の恩恵を受けてばかりですが、自分でも何か貢献したいと思い、少しでも重複作業から解放できる拡張機能を作ることにしました。
TL;DR
この VSCode 拡張機能を作りました。
https://marketplace.visualstudio.com/items?itemName=wsysuper.vscode-pipe-run-notebook
調査
VSCode の拡張機能は、マーケットプレイスで集中管理されています。現時点は 64000 以上の拡張機能が作られています。
OSS のおかげで、言語のパックだけではなく、スニペット、配色テーマ、フォーマッター、テストツール、AI/ML、データサイエンスに関わるツールなど、多彩な拡張機能が満載ですね。
今回は、まだ数がそこまで多くない Notebooks の拡張機能を作りたいと思います。
機能イメージ
日常で発生する煩雑な繰り返し作業は、基本的に「決まったコマンドや API を実行して情報を取得し、その情報をフィルタリング・変形し、結果をどこかに保存する」という流れに抽象化できると思います。
そこで、このプロセスをサポートするために、以下の機能を持つツールを考えました。
- Input
- RestAPI の GET をイメージしています。
- 有名な Axios を使用して、JSON 形式の Config を書けば HTTP リクエストを送信できるようにします。
- また、テストでダミーデータが必要な場合も多いので、数年前に作った json-creator を使って、テスト用の JSON 形式のダミーデータを生成も可能です。
- Extract
- 例えば、JSON 形式のデータから必要な項目を抽出・変形します。
- この部分には、AWS CLI でも採用されている JMESPath を活用します。
- Output
- RestAPI の POST や PUT の操作を想定しています。(Axios)
- Text の結果はクリップボード経由に他の作業と連携もできる想定です。
さらに、ローカル作業をメインとするため、シェルコマンドもサポートします。たとえば、Input 系は cat/curl/find など、Extract 系は grep/sed/jq など、Output 系はファイルにパイプする形での対応ができるようにし、自由な組み合わせで機能強化できるようにします。
通常、ローカルツールを開発するときに悩ましいのが UI の部分ですが、VSCode の拡張機能として作成することで、既存のインターフェースを利用でき、純粋に機能開発に集中できるのも大きな利点です。
さらに、ユーザーとしても慣れ親しんだ VSCode の環境でツールを使用できるため、導入のハードルも低くなります。
このツールでは、Notebook のセルのようにタスクを自然に分けて、1 ステップずつ開発・デバッグを行い、最後に全体を一連の流れで実行できるような機能を実装します。
最終的には、これらのツール群をそれぞれのタイプに応じたセルで実行し、前のセルで生成した出力を次のセルの入力として利用する、パイプライン型のワークフローツールPipe Run Notebookを作成したいと考えています。
実現手順
初回ですので、全部公式の推奨のやり方で一通り実施したいと思います。
Step 1 Extension プロジェクトの大枠を作成する
オフィシャルのサイト「初めての拡張機能」を参考して、手順通りに実施すれば「Hello World」のサンプルが作られます。
Step 1-1 ツールのインストール
まずは、自分環境の Node バージョンを確認します。
Node のバージョンを切り替えたりしたい場合は、バージョン管理ツール nvm がおすすめです。今回の本題ではないため割愛します。
一旦現時点の最新を利用する。
➜ vscode-ext node --version |
最初は Yeoman と VS Code Extension Generator のインストールです。
今回以外使う予定がないため、一時的コマンド実行用の npx を使う。以降も使いたい場合は npm install --global yo generator-code のやり方も記載してありますが、 npx で実行する場合でもローカルキャッシュが効くと思うので、開発ツールぐらいは npx を利用して最新版を使うのが無難でしょう。
※ 自分は oh-my-zsh を使って、 vscode-ext というパスの配下で作業していますので、以降、のプロンプトは ➜ vscode-ext になります。
➜ vscode-ext npx --package yo --package generator-code -- yo code |
依存ライブラリのバージョンが古くなっている警告は一旦無視し、スタイルが良いキャラクタの絵文字が出ました。
Step 1-2 Hello World のデモプロジェクト作成
その続きで、いくつかの質問を回答すると、Hello World 拡張の大枠(scaffold 形式)が作られます。
? What type of extension do you want to create? (Use arrow keys) |
最初の質問は作る拡張機能のタイプを決めます。おすすめの TypeScript の新拡張機能を選びます。
? What type of extension do you want to create? New Extension (TypeScript) |
上記通りに、拡張機能名や識別子など、いくつかの質問を回答することによって、VSCode の拡張開発プロジェクトが作られました。
生成されたディレクトリ構造は以下。(他の bundler を選んだ場合は生成したファイルに差異があるはず。)
➜ vscode-ext tree -I 'node_modules' vscode-pipe-run-notebooks |
生成された package.json の中身を覗けば、以下のことが分かります。
- 入口は
extension.jsである - いくつかコンパイル用、テスト用、リリース前のパッケージ用のスクリプトが作られている
- 普段のライブラリやアプリではあまり見慣れていない
contributesの部が作られている
{ |
Step 1-3 Hello World の拡張機能の動作確認
この時点で、もう F5 を押してデバッグすれば、新しい VSCode ウィンドウが自動的に開かれ、プラグイン動作確認ができる状態になっています。
新しい VSCode ウィンドウのコマンドパレット(F1 もしくは Ctrl/Cmd + Shift + P)で、Helloを打つと、今回自動生成で作られたHello Worldコマンドの存在が確認できます。
下記スクショのように、Hello Worldコマンドを実行すると、右下のメッセージ欄でメッセージがポップアップされる。
上記の挙動は、package.json に contributes.commands の記載と src/extension.ts の下記ロジックで実現されています。
vscode.window.showInformationMessageのような VS Code 拡張機能を開発する際に使える便利な API は、それ以外も数多くありますので、詳細はレファレンスページを参考してください。
Step 2 マイ拡張機能の作成
Notebook 形式の拡張を作るので、ガイドページのその他を一旦飛ばし、いきなり Notebook の紹介ページに進みます。
ファイルの読み書きを担当する Serializer、セル内のコードの実行ロジックを担当する Controller (Kernel)そして結果の表示を担当する Renderer という構成になっており、MVC 的な疎結合の構成になっています。
今回は、文字列や JSON オブジェクトの出力になる想定で、カスタマイズの Renderer を一旦実装しないことにします。(デフォルト流用)
具体的なソースコードは下記の Github で参照してください。
ここでは、簡単な説明だけします。
https://github.com/forsleeping/vscode-pipe-run-notebook/tree/0.0.1
Step 2-1 package.json の編集
サポートする言語の ID の追加、notebook type の追加、notebook ファイルのパターンを *.piperun にします。
"contributes": { |
そして、必要な外部ライブラリを npm install します。
npm install axios jmespath json-creator |
Step 2-2 ファイルの読み書き、Serializer の作成
このファイルを参照してください。
https://github.com/forsleeping/vscode-pipe-run-notebook/blob/0.0.1/src/notebookSerializer.ts
deserializeNotebook は、ファイルから bytes を読み取り、内部の Object に変換します。ほぼバイナリを Decode してから JSON.parse するだけです。
serializeNotebook は逆で、内部表示の Object をファイルのバイナリへ変換します。ここでは、一部永続化したい情報のみ抽出しています。
セルの実行 Output はUint8Arrayで表示する部分があり、そのまま JSON.stringify や JSON.parse だと、Object の形が保持できないことを注意してください。
今回の実装は、方便上 Output をシリアライズする時に排除していますので上記の問題をさけています。つまり、セルの実行結果を notebook ファイルに保持しない方針にします。
Step 2-3 セル内のコードの実行、Controller の作成
この 4 種類の言語 ID を定義し、この言語と Controller をバインドします。(つまり、これ以外の言語はこのコントローラーはハンドリングしないです。)
enum SupportedLanguages { |
それぞれセルの実行時、languageId によって挙動がそれぞれ定義しています。
詳細はこのファイルを参照してください。
https://github.com/forsleeping/vscode-pipe-run-notebook/blob/0.0.1/src/notebookKernel.ts
将来サポートの言語の種類を増やしやすいように、共通機能を抽出しており、各言語の独自実装の部分を_xxxHandler メソッドで分離しています。
Step 2-4 example を作って動作確認
exampleディレクトリを作り、その中にtest.piperunを作ります。
F5 を押してデバグして、ポップアップした新ウィンドウでexampleディレクトリを開きます。
test.piperun をクリックしたら、notebook の形式で開かれることが確認できます。package.json で "filenamePattern": "*.piperun" という selector の定義が効いているからです。
図のように、各セルの右下に Axios や JEMSPath など言語の表記があります。
それをクリックすると、言語の切り替えはできます。Markdown 以外は、controller の supportedLanguages で定義したものになります。
セル左側の三角の Play ボタンで単独実行したら、一番上のRun Allで一括実行したりして、動作確認します。
親の開発画面(F5 を押す側)で Breakpoint を入れてデバグしたりもできます。ソース上の console.log()のメッセージも開発画面側の DEBUG CONSOLE ウィンドウで確認できます。
Run Allの実行結果イメージは以下です。
Step 3 作成した拡張機能をマーケットプレイスでリリース
作成した拡張機能を VSIX 形式のにパックすれば、他人に共有できます。
より多くの人に便利に利用させるために、VSCode 拡張マーケットプレイスに公開するのが一般的です。
その方法は、オフィシャルドキュメントにも書かれています。
Step 3-1 拡張機能を公開するツールのインストール
VSCode 拡張機能専用のパッケージ化、公開、管理ツール vsce (Visual Studio Code Extensions の略) を手に入れます。
npm install -g @vscode/vsce |
使い方は簡単で、よく使うコマンドは以下のようです。
vsce lsパッケージ化、公開する対象ファイルを確認するvsce loginPublisher としてログインするvsce package対象ファイルをパッケージ化するvsce publish対象ファイルをマーケットプレイスで公開する
ちなみに、今回の公開する対象ファイルのリストアップは以下になります。
➜ vscode-pipe-run-notebook git:(main) vsce ls |
Step 3-2 公開前、最終的な準備
README はもちろん、LICENSE ファイルも追加したほうが良いでしょう。(なければパッケージ化する際に警告文が出ます。)
また、せっかく作ったものなので、以下のような meta 情報を package.json に入れましょう。
- 簡潔で正確な説明文
description - カテゴリ
categories - バージョン情報
version - パブリッシャー ID
publisher - ソースのリポジトリ
repository.url
初めてなので、publisher を登録する手続きも必要です。
- 最初は、Azure DevOps で、自分の組織を作る必要があります。参考
- そして、個人アクセストークン(Personal access tokens) を作成します(
vsce login時に必要です) - VSCode Publisher 管理画面で Publisher を作ります
Step 3-3 Publish
拡張機能のプロジェクトディレクトリ配下で、vsce login, vsce package, vsce publish を実行します。
vsce login wsysuper |
まだバグと改善点があったりすると思いますので、今回は pre-release 版を公開します。command に --pre-release のオプションをつけます。
➜ vscode-pipe-run-notebook git:(main) vsce package --pre-release |
パッケージ化後のディレクトリ構成の結果は以下になります。vscode-pipe-run-notebook-0.0.1.vsix が作られています。
➜ vscode-ext tree -I 'node_modules' vscode-pipe-run-notebook |
さて、いよいよ公開のコマンドを打ちます!
vsce publish --pre-release |
しばらくすると、通知メールも届きました。
管理画面でも確認できます。
最後に、マーケットプレイスでPipe Run Notebookを検索したら、出てきました!
まだアイコンもなくて寂しいですね。継続的にメンテナンスしていきたいと思います。
まとめ
VSCode 拡張機能の開発からマーケットプレイスでリリースするまでの流れを実践しました。
初めての VSCode 拡張機能開発でしたが、スムーズな開発体験だったと思います。
ハンズオンや API のリファレンスドキュメントは英語のみで書かれていますが、だいぶ分かりやすく、支障なく進められたと思います。また、ほとんどの拡張機能は Github 上でオープンソースになっていますので、参考になれる類似のプロジェクトも簡単に手に入れます。
最後に、現時点にまだ pre-release 版ですが、ぜひ、今回公開した Pipe Run Notebook を VSCode にインストールしてお試しください。追加の機能開発やバグ修正を継続的に実施するつもりです。