初めてChromeExtension（Chrome拡張機能）を作ってみた

# はじめに
今回、初めてChrome拡張機能を作ってみて、Chromeウェブストアへ公開するというところまでやってみたので、
ログとして残しておきたいと思います。

# 今回作ったもの
https://github.com/nomunomu0504/smart-pull-request

無事、Chromeウェブストアへ公開されました！

https://chrome.google.com/webstore/detail/smartpullrequest/goojodnccenoinjjpfiajflilecakcbp

# 何を作ったか
Githubでプロジェクトを進めて行くと、必ずコードレビューが発生してきます。

このとき、1PRで修正されたファイルが少なければ特に問題ないのですが、自動生成ファイルなどが含まれる、大量差分のPRを見るときに大変なのがこちら。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110131/51d33ce4-2d40-4155-56c1-85e8afaf1254.png)
そう。Filesタブにある大量のファイルリストです。

Diff表示の方は個別表示/非表示や、一括表示/非表示を行うことができますが、サイドメニューにあるリストはできないのです。

:::note info
Diff表示の一括表示/非表示は 「alt（macならoption）+diff表示/非表示ボタン」でできます。
:::

そこで、サイドメニューのファイルリスト + Diff表示部分の一括表示/非表示を行う専用ボタンを表示させる、拡張機能を作ってみました。

# 実装紹介
拡張機能用のディレクトリ構成とかは、特になさそうだったので、自分は以下のようにしておきました。
```.
├── src
│   ├── assets
│   │   ├── icon-128.png
│   │   ├── icon-48.png
│   │   ├── icon-16.png
│   │   ├── jquery-3.6.0.min.js
│   │   └── usage.gif
│   ├── templates
│   │   ├── buttons.css
│   │   └── buttons.html
│   └── index.js
└── manifest.json
```

重要なのは `manifest.json` と実際に処理を書く `index.js` です。

今回の拡張機能では、拡張機能を実装する上で使える機能のごくごく一部分しか使えていないので、もっと詳しいことを知りたい方は、公式サイトをご覧ください。

https://developer.chrome.com/docs/extensions/mv3/getstarted/

manifest.jsonの中身はこんな感じ。正しいか正しくないかは分からないですが、テストして拡張機能自体は動いてたから問題ないのかなと...
```
{
  "name": "SmartPullRequest",
  "version": "1.0.0",
  "manifest_version": 3,
  "description": "PullRequestのFilesタブの操作性を改善します。",
  "icons": {
    "16": "src/assets/icon-16.png",
    "48": "src/assets/icon-48.png",
    "128": "src/assets/icon-128.png"
  },
  "permissions": [],
  "content_scripts": [
    {
      "matches": ["https://github.com/*"],
      "js": ["src/assets/jquery-3.6.0.min.js"],
      "run_at": "document_start"
    },
    {
      "matches": ["https://github.com/*"],
      "js": ["src/index.js"],
      "css": ["src/templates/buttons.css"],
      "run_at": "document_end",
      "all_frames": true
    }
  ],
  "web_accessible_resources": [
    {
      "resources": ["src/templates/buttons.html"],
      "matches": ["https://github.com/*"]
    }
  ]
}
```
`manifest_version` は `v3` を使うと、審査時間も短縮されるみたいです。公式がそう言ってるので間違いないはず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110131/6da63788-0680-e86a-7cde-affc9c72c954.png)

ざっと重要な項目だけ触れておくと

* permissions
* content_scripts
* web_accessible_resources

は抑えておきたいところですね。

## permissions
これはその名の通り、拡張機能に付与する権限を指定します。権限を要求できるリストは以下にまとまっています。

https://developer.chrome.com/docs/extensions/reference/permissions/

今回の拡張機能では、特にユーザーから権限を貰う必要がなかったため、空配列となっています。

## content_scripts
このセクションでは、どのファイルに記述された機能（処理）をどのサイト・どのタイミングで実行するか。などの、拡張機能根幹の設定を行います。

https://developer.chrome.com/docs/extensions/mv3/content_scripts/

私の場合はjQueryを使いたかったので、documentの読み込みが始まった時点で先にloadしておき、documentの読み込みが終わった時点で、拡張機能本体を読み込ませるようにしました。

## web_accessible_resources
そう。一番こいつに時間を取られました。このセクションでは、拡張機能側から自前のhtmlやimgなどのリソースを読み込むために、設定を記述するセクションです。

https://developer.chrome.com/docs/extensions/mv3/manifest/web_accessible_resources/

`index.js` で画面にinjectしたいhtmlが書かれているファイルをloadしてきて、突っ込むという処理です。

なんの設定もしなくても、普通に読み込めるだろうと思ってたら全く読み込めず、こいつの存在を知るまで時間を溶かしてました。気をつけましょう。
```
$.get(chrome.runtime.getURL("src/templates/buttons.html"), function (data) {
  console.log(data);
  const parentNode = $(".subnav-search");
  console.log(parentNode);
  $(parentNode).after(data);
});
```

で、なんやかんやありましたが、無事申請中です。こうやってみんな作ってるんだなと知ることができました。

# Tips
開発中の拡張機能をどうテストするかですが、まずはじめにChromeの拡張機能画面を開いて、デベロッパーモードを「ON」にする必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110131/7a4e170f-b1bf-d534-8383-59c15c719b8d.png)

ONにすると、上からにゅっとメニューバーが表示されるので、「パッケージ化されていない拡張機能を読み込む」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110131/2512094e-2d8c-f4cc-243b-64a49588a6df.png)

そうすると、フォルダ選択するウィンドウが開くので、`manifest.json` が置かれているフォルダを選択します。

:::note warn
実際にテストする際には、manifest.jsonが必要なので、先に作成しておきましょう。
:::

すると、拡張機能のところに今作ってる拡張機能が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110131/c9e618ee-c97b-d958-658b-25d6b4b5645f.png)

パッケージ化されていない拡張機能を読み込むメリットは、わざわざ更新したものをパッケージ化して、再読み込みさせる必要がないというところです。

参照しているフォルダの処理を書き換え保存したら、読み込んだ拡張機能カードに表示されている、ローディングボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110131/1ed7d5e6-9d07-b8ab-6dd0-005a5ec31e59.png)

そうすると、参照しているフォルダの最新情報で拡張機能が更新されます。これを繰り返すことで開発を簡単に行うことができます。

# おわり
簡単な拡張機能を試しで作ってみて、ぜひGithubに公開してみましょう！