VisualStudioCode

【VSCode】アクティビティーバーで外部コマンドを実行する拡張機能を作成した

更新日:2025/04/10

VSCodeで開発中にNode.jsで自作したコマンドを実行することがあるのだけど、毎回手打ちするのが面倒になってきました。

そこで、画面左側にあるアクティビティーバーにボタンを設置して、自作コマンドを実行することにしました。

それには拡張機能開発が必要なので、作成することにしました。

 

開発環境の構築

まずは、次のVSCode拡張機能を解説したページに従って拡張機能の開発環境を構築します。

Node.jsがインストールされていない場合は、インストールしておきます。

Node.jsがインストールできたら、VSCodeの拡張機能開発に必要なモジュールをグローバルインストールします。
VSCodeのターミナルではなくて、コマンドプロンプト等で実行した方が後々後悔しないと思う。

npm install -g yo generator-code

これは一回だけでOK。

次に、拡張機能のひな型を作成したいディレクトリに移動して次のコマンドを実行。

yo code

ひな型は、ディレクトリも作成されます。自分でディレクトリ作成して、その中で実行するとムダな階層が増えるので注意。

コマンドを実行すると、いくつか質問が表示されます。

? What type of extension do you want to create? New Extension (TypeScript)

New Extension (TypeScript) か New Extension (JavaScript) のどちらかを選択。
今回はNew Extension (TypeScript)を選択しました。

? What's the name of your extension? my-extension

拡張機能の名前を入力。

? What's the identifier of your extension? my-extension

拡張機能の識別子を入力。この名前でディレクトリが作成される

? What's the description of your extension? 自作拡張機能

拡張機能の説明を入力。

? Initialize a git repository? No

Gitのリポジトリを初期化するかどうか。とりあえず NO。

? Which bundler to use? webpack

バンドラーは、とりあえずwebpackを選択。

? Which package manager to use? npm

パッケージマネージャは、とりあえずnpmを選択。

すると、ひな型の作成が始まる。

最後に、次のメッセージが表示される。

? Do you want to open the new folder with Visual Studio Code? (Use arrow keys)

Open with `code` を選択すると、作成したひな型のディレクトリをVSCodeで開いてくれます。

ひな型作成中に次のようなメッセージが表示されたら、該当するVSCodeの拡張機能をインストールします。

To run the extension you need to install the recommended extension 'amodio.tsl-problem-matcher'.

右下に推奨拡張機能として通知されるので、クリックすればOK。
もし表示されなかったら、アクティビティーバーの拡張機能を開いて検索窓にamodio.tsl-problem-matcherと入力すればインストールできます。

 

ひな型のテスト

アクティビティーバーの実行とデバッグで『Run Extension』を実行すると、新規でVSCodeが起動します。
起動したVSCode側で、Ctrl + Shift + P でコマンドパレットを開いてHello World を実行すると、『Hello World from HelloWorld!』と通知されます。

ちなみに、『Run Extension』の前にブレークポイントを設置すると、うまく動作しないことがあります。詳しくは次の関連ページを読んでみてください。

 

アイコンの用意

SVGファイルを用意します。自作したり、無料SVGダウンロードサイト等で取得してください。

プロジェクトにmediaディレクトリを作成して、icon.svgという名前で保存します。

プロジェクトディレクトリ
  ┣ media
  ┃ ┗ icon.svg
  ┣ ・・・・

 

アクティビティーバーの設定

アクティビティーバーの追加とバーの中身の設定は、package.json の "contributes" で行います。

初期値では、次のようになっています。

  "contributes": {
    "commands": [
      {
        "command": "extension.helloWorld",
        "title": "Hello World"
      }
    ]
  },

これを次のように変更。

 "contributes": {
    "viewsContainers": {
        "activitybar": [
          {
            "id": "myExtSidebar",
            "title": "自作ツール",
            "icon": "media/icon.svg"
          }
        ]
      },
      "views": {
        "myExtSidebar": [
          {
            "id": "myExtSidebarView",
            "name": "コマンド",
            "icon": "media/icon.svg"
          }
        ]
      },
      "commands": [
        {
          "command": "myExt.cmd1",
          "title": "コマンド1"
        },
        {
          "command": "myExt.cmd2",
          "title": "コマンド2"
        },
        {
          "command": "myExt.cmd3",
          "title": "コマンド3"
        }
      ],
      "viewsWelcome": [
      {
        "view": "myExtSidebarView",
        "contents": "[コマンド1](command:myExt.cmd1)"
      },
      {
        "view": "myExtSidebarView",
        "contents": "[コマンド2](command:myExt.cmd2)"
      },
      {
        "view": "myExtSidebarView",
        "contents": "[コマンド3](command:myExt.cmd3)"
      }
    ]
  },

"viewsContainers"の"activitybar"にアクティビティーバーの情報を記述します。

    "viewsContainers": {
        "activitybar": [
          {
            "id": "myExtSidebar",
            "title": "自作ツール",
            "icon": "media/icon.svg"
          }
        ]
      },

"views"の下層に、アクティビティーバーのidを記述して、その中にビューの情報を記述します。

      "views": {
        "myExtSidebar": [
          {
            "id": "myExtSidebarView",
            "name": "コマンド",
            "icon": "media/icon.svg"
          }
        ]
      },

"commands"で、拡張機能が使用するコマンドを設定します。
コマンドの処理内容は、プログラムコードで記述する必要があります。

      "commands": [
        {
          "command": "myExt.cmd1",
          "title": "コマンド1"
        },
        {
          "command": "myExt.cmd2",
          "title": "コマンド2"
        },
        {
          "command": "myExt.cmd3",
          "title": "コマンド3"
        }
      ],

"viewsWelcome"でビュー内の表示内容を設定します。
ここでは三つのボタンを表示しています。

      "viewsWelcome": [
      {
        "view": "myExtSidebarView",
        "contents": "[コマンド1](command:myExt.cmd1)"
      },
      {
        "view": "myExtSidebarView",
        "contents": "[コマンド2](command:myExt.cmd2)"
      },
      {
        "view": "myExtSidebarView",
        "contents": "[コマンド3](command:myExt.cmd3)"
      }
    ]

"view"は、ビューのidを指定します。
"contents"は、[]内がボタンの文字、(command: xxx )でボタンが押された時に実行するコマンドを指定します。

『Run Extension』を実行すると、アクティビティーバーにタブが追加されます。

作成したアクティビティバー

 

外部コマンドを用意

追加したアクティビティーバーで実行する外部コマンドを用意します。

今回はプロジェクト内に command ディレクトリを作成して、jsファイルを二つ作成しました。

プロジェクトディレクトリ
  ┣ command
  ┃ ┣ cmd1.js
  ┃ ┗ cmd2.js
  ┣ ・・・・
  ┣ media
  ┃ ┗ icon.svg
  ┣ ・・・・

jsファイルの中身は、console.log()で文字列を出力するだけです。

cmd1.js:

console.log( "コマンド1を実行" );

cmd2.js:

console.error( "コマンド1を実行" );

cmd3.jsは、ファイルが存在しないためエラーになる予定です。

 

コマンド処理を記述

src/extension.ts を次のように編集します。

import * as vscode from 'vscode';
import { exec } from 'child_process';
import * as path from 'path';

export function activate(context: vscode.ExtensionContext) {

	context.subscriptions.push(
		vscode.commands.registerCommand("myExt.cmd1", function () {
			execCall( context , "cmd1" );
		})
	);
	context.subscriptions.push(
		vscode.commands.registerCommand("myExt.cmd2", function () {
			execCall( context , "cmd2" );
		})
	);
	context.subscriptions.push(
		vscode.commands.registerCommand("myExt.cmd3", function () {
			execCall( context , "cmd3" );
		})
	);
}

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

const execCall = (context: vscode.ExtensionContext,cmd:string) =>{
	const jsPath = path.join(context.extensionPath,"command",cmd + ".js" );
	const command = `node ${jsPath}`;
        
        cosole.log("コマンドを実行");

	exec(command, (err, stdout, stderr) => {
			if (err) { vscode.window.showErrorMessage(err.message); }
			if( stdout ) {vscode.window.showInformationMessage(stdout);}
			if( stderr ) {vscode.window.showErrorMessage(stderr);}
		});
};

vscode.commands.registerCommand()で、コマンドの処理内容を登録します。
その結果を、context.subscriptionsにpush()で追加します。

	context.subscriptions.push(
		vscode.commands.registerCommand("myExt.cmd1", function () {
			execCall( context , "cmd1" );
		})
	);

今回は処理がわかりやすいようにほぼ同じ内容を3回コピペしていますが、コマンド名を配列にセットしてforEach()で繰り返し処理するなどに変更するのも良さそうですね。

変更後に上書き保存して『Run Extension』を実行してアクティビティーバーのコマンドボタンを押すと、通知が表示されます。

ソースコード側のデバッグコンソールにjsが出力した内容が表示されます。

なお、cosole.log("コマンドを実行");は、ソースコード側のデバッグコンソールに出力されます。

 

拡張機能を個人用で使用する

今回作成した拡張機能を個人用としてVSCodeに組み込みます。

必要なモジュールをインストール

最初にVSIX packageを作成するために必要なモジュールをグローバルにインストールします。

npm install -g @vscode/vsce

拡張機能をコンパイル

次に、作成した拡張機能をコンパイルします。

npm install
npm run compile

JavaScriptで開発している場合、コンパイルは必要ないと思いますが、念のため実行してみてください。

パッケージ化

次にパッケージ化します。

vsce package

次のようなエラーが表示されたら、README.mdの中身を削除します。

ERROR  It seems the README.md still contains template text. Make sure to edit the README.md file before you package or publish your extension.

『エラー:README.md にテンプレートテキストがまだ含まれているようです。拡張機能をパッケージ化または公開する前に、必ず README.md ファイルを編集してください。』

公開するときは内容を確認しながら編集する必要がありますが、今回は個人用なので中身を全部削除です。

もう一度、コマンドを実行します。

vsce package

今度はワーニングが出ました。

WARNING  A 'repository' field is missing from the 'package.json' manifest file.
Use --allow-missing-repository to bypass.
Do you want to continue? [y/N] y

『警告 'package.json' マニフェスト ファイルに 'repository' フィールドがありません。』

ひな型作成時に『Initialize a git repository?』をnoにしたため、'repository' フィールドが作成されなかったようです。
気にせず続行します。

WARNING  LICENSE, LICENSE.md, or LICENSE.txt not found
Do you want to continue? [y/N] y

『警告 LICENSE、LICENSE.md、または LICENSE.txt が見つかりません』

他者にライセンスする気が無いので、続行します。

拡張子が .vsixのファイルが作成されたらパッケージ化完了です。

VSCodeにインストール

Ctrl + Shift + Pで、VSCodeのコマンドパレットを開きます。

『Install from VSIX』を検索して実行します。

ファイル選択ダイアログが表示されるので、作成したvsixファイルを指定します。

これで、VSCodeに拡張機能がインストールされます。

更新日:2025/04/10

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。