【VSCode】拡張機能を作ってみる

# はじめに

Dockerを使ってVSCodeの拡張機能を作ってみます。

:::note alert
この記事はメモ書きのようなもので、**かなり雑**です。

なので、VSCodeの拡張機能の開発について何も知らないという方は、この記事ではなく**下のような非常に分かりやすい解説を読むことを強くお勧めします。**
* [VSCode Extensions(拡張機能) 自作入門 〜VSCodeにおみくじ機能を追加する〜 | Qiita](https://qiita.com/HelloRusk/items/073b58c1605de224e67e)
* [かんたん！VS Code拡張機能開発 | DevlopersIO](https://dev.classmethod.jp/articles/easy-vs-code-extension-development/)

他の記事やサイトの手順に従ったのにエラーが出まくって進めない、という方の少しの助けになればいいなと思って書いています。

いつか私がVSCodeの拡張機能について習熟した時に、また書き直そうと思っています。
:::


## 環境

* MacOS Sonoma 14.1
* VSCode 1.86.1
* Node.jsなどはローカルにはインストールされていない
* Docker Desktopインストール済み


## 参考

https://qiita.com/HelloRusk/items/073b58c1605de224e67e

https://qiita.com/quotto/items/a672e8b3b45865832577


# Dockerコンテナの起動

ここではVSCodeの既存の拡張機能を活用してコンテナを起動しようと思います。
使う拡張機能は、[Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker)と[Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)です。

まずは新しくフォルダを作成します。
名前はとりあえず`my-extension`としておきます。


## Dockerfileを作る

そしたらさっそくdockerfileを作ります。

```dockerfile:dockerfile
FROM --platform=linux/x86_64 node:20.5.0

RUN apt update && \
    apt install -y locales git
RUN locale-gen ja_JP.UTF-8
RUN localedef -f UTF-8 -i ja_JP ja_JP
ENV LANG=ja_JP.UTF-8
ENV TZ=Asia/Tokyo
WORKDIR /project 
```

上のdockerfileは、Node.js 20.5.0をベースとしたDockerイメージを作るものです。
また、コンテナの`/root/project`にマウントされることを想定しています。


## devcontaienr.jsonを作る

こちらはDev Containersという拡張機能が読み取るファイルです。

まずは`.devcontainer`フォルダを作り、その配下に`devcontainer.json`を作っていきます。

```devcontainer.json
{
	"name": "Existing Dockerfile",
	"build": {
		"context": "..",
		"dockerfile": "../dockerfile"
	},

	"workspaceFolder": "/project",
	"workspaceMount": "source=${localWorkspaceFolder},target=/project,type=bind,consistency=cached",
	"mounts": [
		"target=/project/node_modules"
   	]
}
```

ここではコンテナの`/project`フォルダをワークスペースとする設定を書いています。
また、`/project/node_modules`をマウントし、`node_modules`の中身がローカルに共有されないようにします。

以下の記事を参考にしました。

https://qiita.com/quotto/items/a672e8b3b45865832577


## コンテナを起動する

ウィンドウを再読み込みすると右下にダイアログが表示されると思います。
そこのボタンを押すとコンテナが起動し、VSCodeがアタッチされます。


# 雛形を作る

Yoというのを使うと雛形が作れるらしいです。


## yoのインストール

まずはインストールします。
VSCodeのターミナルに、以下のコマンドを打ち込んでください。

```sh
yarn global add yo generator-code
# or
npm install -g yo generator-code
```

これだけでいいらしいです。便利ですね。


## yoを使って雛形を作る

では、いよいよ雛形を作っていきます。
ターミナルに以下のように入力してください。

```shell
yo code

# 何を作るか聞かれる
What type of extension do you want to create?
    > New Extension (TypeScript) 

# 拡張機能の名前を聞かれる
What’s the name of your extension?
    > my-extension

# 識別子をどうするか聞かれる、そのままEnterを押せばOK
What’s the identifier of your extension?
    > Enter

# 拡張機能の概要を聞かれる
What’s the description of your extension?
    > よくわからないなにか

# git initするか聞かれる、どっちでもいいけどここではy
Initialize a git repository? 
    > y

# Webpackを使うか聞かれる、多分yのほうがいいけどここではnにした
Bundle the source code with webpack?
    > n

# パッケージマネージャに何を使うか聞かれる
Which package manager to use? 
    > yarn
```

...さて、これで雛形生成が始まります。
これで無事に雛形ができれば良かったのですが、何やらよくわからないエラーが出ました。
どうやら`yarn install`が失敗したみたいです。
よくわからないですが、それっぽいファイルは生成されていたので、ここでは無視することにします。


## 雛形の場所を移動する

今のままだと雛形は`/project/my-extension`の中にあります。
ですが、雛形は`/project`にあって欲しいです。
ということで手動で移動します。

`mv`コマンドを使う方法もあるでしょうが、私はVSCodeのエクスプローラーを使って移動しました。
移動し終わって空になった`my-extension`フォルダは削除します。

そしたら、先ほど失敗した`yarn install`を実行します。
今度は無事にできたと思います。

* * *

<details><summary>おまけ：サンプルをクローンする方法</summary>

yoのエラーが解決できない場合は、[Microsoftが用意したサンプル](https://github.com/microsoft/vscode-extension-samples)をクローンするのもありかもしれません。

1. 上のリポジトリを先ほど作成した`my-extension`フォルダの中にクローンする
1. `helloworld-sample`以外のファイルやフォルダを削除する
1. `helloworld-sample`の中に入っているものを`my-extension`の中に全て移動する
1. 空になった`helloworld-sample`は削除する

こんな感じの手順を踏むと、`my-extension`フォルダの中に雛形が出来上がります。
ただ、ぶっちゃけ試してないので、これで開発ができるかは分かりません。

`yo code`で作った雛形には`.vscodeignore`なんかのファイルもあったけど、microsoftのサンプルにはないし...
</details>


# 実行してみる

今作った雛形の状態で、拡張機能はすでに動くはずです。
ということでさっそく実行してみます。

`F5`キーを押すと、VSCodeの別ウィンドウが立ち上がります。
ここで`command + P`を押してコマンドパレットを起動し、`Hello World`コマンドを実行してみてください。

すると、画面右下に「Hello World from my-extension!」というようなポップアップが出ると思います。
これができたら開発の準備はOKです。

:::note info
**コマンドが見つからない場合**

少し試してみたところ、
* `package.json`の記述が間違っていると、コマンドパレットに`Hello World`が表示されなくなる

とコマンドパレットに`HelloWorld`コマンドが見つからなくなり、

* コード（`extension.ts`）がミスっている
* コンパイル先がミスっている or コンパイルができていない？

と「not found」のようなエラーが出るみたいです。

まずは`/project/package.json`がどうなっているのかを確認します。
```jsonc:package.json
{
    "activationEvents": [], // ここは空でよし
    "main": "./out/extension.js", // 読み込まれるファイル
    "contributes": {
        "commands": [
            {
                "command": "my-extension.helloWorld", // コマンドID
                "title": "Hello World" // コマンド名
            }
        ]
    },
}
```

まず、私の環境だと`activationEvents`は空でも動いたので、ここをいろいろ変えるのは効果が薄そうです。

次に`main`ですが、どうやら`./out/ectension.js`がエントリーポイントみたいです。

つまり、以下のことが原因でコマンドが見つからないかもしれません。
* そもそもコンパイルがされていない
* `tsconfig.json`の`outDir`や、`webpack.config.json`の`output.path`の設定が`out`になっていない

最後に`contributes.commands`ですが、どうやらここにはコマンドIDとコマンド名を登録するみたいです。
このうちコマンドIDは`extension.ts`にも書くため、ここが`package.json`と`extension.ts`とで違うと「not found」と言われます。
:::


### テストについて

私の環境だと「vscode-linux」とやらがインストールできずに、デフォルトで`src/test`に入っているテストが実行できませんでした。

`lib`から始まるパッケージが足りないって7回ぐらい言われ、そのパッケージを全てインストールしたら、今度は`dbus`のフォルダ？ファイル？がないって言われて諦めました。

テストやってるところあんまりないし、まあいっか...という心境です。


# 配布&公開する

どうやら拡張機能を`.vsix`という形式のファイルまとめることができるらしいです。
そしてこの`.vsix`ファイルを配布すれば拡張機能を配ることもできます。


## vsceのインストール

拡張機能を`.vsix`ファイルにまとめるにも、そのまとめた拡張機能を[VSCode marketplace](https://marketplace.visualstudio.com/vscode)に公開するにも、`vsce`というパッケージが必要です。

私がやった感じだと`yo code`しても入ってなかったので、インストールします。
```shell:vsceをインストールする
yarn global add vsce
```


## `.vsix`ファイルを生成する

:::note warn
絶対[私が参考にした記事](https://qiita.com/HelloRusk/items/073b58c1605de224e67e#%E8%87%AA%E4%BD%9C%E3%81%97%E3%81%9F%E6%8B%A1%E5%BC%B5%E6%A9%9F%E8%83%BD%E3%82%92-vsix-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AB%E3%81%97%E3%81%A6%E9%85%8D%E5%B8%83%E3%81%99%E3%82%8B)のほうがわかりやすいです。
:::


`vsce`のインストールが済んだら、さっそくコマンドを実行...といきたいところですが、先にやることがあります。
それは`README.md`の編集です。

これを編集しないと怒られるので、デフォルトのものから書き換えてください。

```diff_markdown:README.md
+ # my-extension
+
+ よくわからない何か
```

`README.md`の編集が終わったら、あとはコマンド一つでファイルを生成できます。
以下のコマンドを実行してください。

```shell:.vsixファイルを生成する
vsce package
```

少し待つと、`/project`にそれらしきファイルが生成されると思います。

ちなみに、`.vsix`ファイルを拡張機能としてVSCodeに読み込むには、サイドバーの「拡張機能」タブにある「...」アイコンをクリックして、「VSIXからのインストール」を選びます。

![vsix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233069/ef4dd0e2-fa1b-36d2-052c-10afbf582f33.png)
※画像は[参考記事](https://qiita.com/HelloRusk/items/073b58c1605de224e67e)からの引用


## マーケットプレイスで公開する

...っていうこともできるらしいです。
詳しくは下のサイトが参考になると思います。

https://code.visualstudio.com/api/working-with-extensions/publishing-extension

https://ysss.hateblo.jp/entry/20200710/1594307803