うちでChrome拡張機能を作ろう

この記事は[NTTコミュニケーションズアドベントカレンダー](https://qiita.com/advent-calendar/2020/nttcom)の8日目の記事です。

昨日は、@suzusuzu さんの　「[Rustで実装するNetflow Collector](https://qiita.com/suzusuzu/items/891a0b9bafee6f5f0850)」でした。

# はじめに
どうもこんにちは
昨年は[こんな記事](https://qiita.com/tetrapod117/items/131541319256c6f4d3e9)を書いたtetrapod117です。

今年はおうち時間が長かったので、いろいろ仕事以外でも趣味の開発をやったりしていました。
その中でChrome拡張を作ったりもしたので、今回は2020年っぽいChrome拡張を作って、Chrome拡張の開発について学ぶ記事を書いていこうと思います。
（お）うちでChrome拡張機能を作（るのに役立てばいいだ）ろう
という感じで書いていきます

ちなみに、Chrome拡張はお仕事ではなくプライベートな趣味で作ってます。

# まず、Chrome拡張って？
Chromeの機能を拡張できるプログラムのことです。

拡張機能はChromeウェブストアから追加することができます。
https://chrome.google.com/webstore/category/extensions?hl=ja&


## オススメ拡張
ついでに僕がオススメの拡張機能を紹介します。

### OneTab
まずは、OneTabです。
https://chrome.google.com/webstore/detail/onetab/chphlpgkkbolifaimnlloiipkdnihall?hl=ja

仕事で調べものとかしてるとタブを大量に開いてしまって整理するのが大変。
そんな時にOneTabは大活躍します。
ワンクリックでタブをリスト化して、すっきりさせてかつメモリの消費も抑えることができます。

### Peek-a-tab
次はPeek-a-tabです。こいつはこりゃまたTab管理の拡張です。
僕はTabをたくさん開きますし、ウィンドウもたくさん開きます。なので、あのページどこやったかなとなる時が多々あるので、そんな時は`Peek-a-tab`でページを検索して見つけてます。
https://chrome.google.com/webstore/detail/peek-a-tab-tabs-manager-f/nnpdamdaknpnohmlbnmgphiodghbohop


# Chrome拡張機能を作ろう
という感じで
これらのChrome拡張機能はHTML,CSS,JavaScriptを使って自分で作ることもできます。
では、早速作っていきましょう


それでは、張り切ってどうぞ〜

# 密回避拡張
今年は3密という言葉が流行りましたね〜
こうQiitaの記事を見ているとなんか文字が密な感じがしてきますね

ということで、Qiitaの文字間隔を開ける拡張を作っていきましょう。

## manifest.jsonの用意
まずChromeの拡張機能を作るにはmanifest.jsonを用意する必要があります。
ざっくりいうと設定ファイルです。
https://developer.chrome.com/extensions/manifest
作業用のディレクトリを作成し、manifest.jsonファイルを作成します。


以下のような感じで書きます

```json
{
    "manifest_version": 2,
    "name": "Mitsu Qiita",
    "version": "1.0.0",
    "description": "Qiitaの文章を密回避する拡張です",
    "content_scripts": [
      {
        "matches": ["https://qiita.com/*"],
        "css": ["style.css"]
      }
    ]
}
```

ここで重要なのはcontent_scriptsの記載内容です
content_scriptsはブラウザ上に表示されているページに対して、スクリプトを挿入してDOM操作を行えるようにします。
https://developer.chrome.com/extensions/content_scripts
今回は`https://qiita.com/*`にマッチするWebページにstyle.cssを読み込ませます。

## style.cssの用意
ということでstyle.cssを用意します
こんな感じです

```css
* {letter-spacing: 1em}
```

`letter-spacing`で文字間隔を変えてます

## 動作確認
それでは密回避拡張の動作確認をしてみましょう。

現在、ディレクトリにはmanifest.jsonとstyle.cssがあると思います。

chromeブラウザで以下のリンクを開いてみてください。

`chrome://extensions/`

開いたら右上のデベロッパーモードをONにします
![拡張機能.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/8dcb145b-1585-5622-7c4a-40413940c2ac.png)

デベロッパーモードをONにすると3つのボタンが出てくるので、そこから`パッケージ化されていない拡張機能を読み込む`を選択します

![拡張機能.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/0529176a-b4f7-c23c-6333-8f9cff2f4911.png)

ファイル選択で先ほどの作業ファイルを選択します。
拡張一覧にMitsuQiitaがあれば成功です。

![拡張機能.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/ae8ee962-95eb-5bf4-8f47-7dfc900ffe7a.png)


このままQiitaを開いてみましょう

めっちゃ読みづらくなってますね！
ただ、ちゃんと密は回避できています


![Cloud_RunでSlackの分報をちょっとだけ楽しくしてくれるBotを作ってみた_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/f3854d2d-ac8c-bfcd-870a-b4935f03543d.png)

こんな感じでcontent_scriptを使うとJSやCSSでWebページを気軽に切り替えることができます。

次はJavaScriptとかを使ってもっと動きのある拡張を作ってみましょう


# 鬼滅の刃を別の文字に変えてみよう
ということで次はBroser Actionを使った拡張機能を作ってみましょう。
今年は鬼滅の刃の映画が国内の興行収入歴代1位に迫ってきていて、凄まじいくらいに大ヒットしてますね。
ということで、鬼滅の刃を別の文字に変換する拡張機能を作ってみましょう。

## Browser Actionとは？
追加するとURLのバーの横にアイコンが追加され、それでいろいろ機能が使えるタイプの拡張機能です。

ここらへんのやつです。
Chrome拡張と言えば真っ先に思いつくタイプのものかなと思います。
![「うちでChrome拡張機能を作ろう」を編集_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/776fa5ec-55e0-9e64-5460-850368f63e4a.png)

似たようなものでPage Actionというのもあります
違いはPageActionは特定のページに使い、Browser Actionはページに依存せず拡張機能を使うことができます。

## manifest.jsonの作成
まずは、先ほどと同様拡張機能の設定などを記載するmanifest.jsonを用意します

```json
{
  "manifest_version": 2,
  "name": "kimetsu2bo-bobo",
  "description": "鬼滅の刃の文字をボボボーボ・ボーボボに置換する",
  "version": "1.0",
  "permissions": ["http://*/*", "https://*/*"],
  "browser_action": {
    "default_icon": {
      "16": "/icon16.png",
    }
    "default_popup": "popup.html"
  }
}
```
ディスクリプションにも書いてますが、今回は鬼滅の刃の文字をボボボーボ・ボーボボに変換します。

今回重要なのは`permissions`と`browser_action`の項目です。

### permissionsについて
`permissions`は権限の設定です。
`chrome.* API`を使う時に適切な権限を渡さないといけないです。
設定については以下のURL参照
https://developer.chrome.com/extensions/declare_permissions

今回はChrome.tabのAPIを使うのですが、こちらのページのManifestに書いてある通り、一部のAPIを使う時のみにpermissionsの設定が必要になりますが、今回使うものには必要ないので設定していません。
https://developer.chrome.com/extensions/tabs

permissionsについてですが、もし作った拡張機能をリリースしたい場合に、不必要な権限を要求していたら審査の際に弾かれてしまうので気をつけてください。

### browser_actionについて
こちらは右上の拡張機能で使うアイコンとアイコンをクリックした時に出てくるポップアップを設定しています。

![「うちでChrome拡張機能を作ろう」を編集_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/4ff17b54-e22f-c568-afb8-efea6ccb6f50.png)

アイコンは16x16のファイルを適当に用意して配置します。
アイコンについては自分の環境で試す時は別に入れる必要はないですが、リリースをする時は必要になるのでリリースを考えてる時は作成する必要があると覚えておきましょう。

ポップアップはHTMLファイルを用意する必要があるので早速作っていきましょう。

## popup.htmlの作成
ということで、default_popupに設定しているpopup.htmlを作りましょう

```html
<!DOCTYPE html>
<head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" type="text/css" href="popup.css">
</head>

<body>
    <div>
        <h3>鬼滅の刃をボボボーボ・ボーボボに変換します</h3>
        <button type="button">変換</button>
    </div>
    <script src="popup.js"></script>
</body>

</html>
```

popup.cssはこんな感じです

```css
body {
    min-width: 300px;
}
```

今回は簡単にボタンだけ設置してみました。
CSSではポップアップの横幅を設定しています。

![拡張機能.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/25cad698-15b4-521a-3237-d015922e2d0f.png)

読み込んでみるとこんな感じになります

## JSの記述
次にページにアクションを起こすJSを書いていきます
popup.jsになります

```javascript

let buttonElement = document.getElementById('button');

buttonElement.addEventListener('click', (event) => {
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        chrome.tabs.executeScript(
            tabs[0].id,
            {code: `document.body.innerHTML=document.body.innerHTML.replace(/鬼滅の刃/g, 'ボボボーボ・ボーボボ');`}
        );
    }); 
});
```

buttonのクリックをトリガーにtab.queryでページ情報を取得して、executeScriptで文字列を変更するJSを実行しています。
https://developer.chrome.com/extensions/tabs#method-query

文字列を変換しているのはこちらのコードです
`document.body.innerHTML=document.body.innerHTML.replace(/鬼滅の刃/g, 'ボボボーボ・ボーボボ');`
ちなみに、この1行だけをChromeのデベロッパーツールのconsoleに入れて実行しても同じような動作をします。


## 動作確認
では、
読み込んでみて動作確認してみましょう。
chrome://extensions/



![鬼滅の刃_-_Google_検索.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/45bc6913-06aa-2673-72ef-6b2e5680e3fe.png)

これが拡張を使うと

![鬼滅の刃_-_Google_検索.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/3f321df7-6f8a-128c-4a76-ee1eb0711a6a.png)

![鬼滅の刃_-_Google_検索.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/afcd7106-aed6-7c80-023d-ce5e171eb16f.png)


こうすることができます

ちなみに劇場版「ボボボーボ・ボーボボ」無限列車編はかなりパワーワードですね

![鬼滅の刃_-_Google_検索.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/6f59b61d-01fc-3995-1304-d1a754ac3c56.png)

開発については以上です

こんな感じでBrowser Actionを使うとポップアップを使えて、ユーザーのアクションを起点にした拡張の開発を行えます。

# その他Chrome拡張Tips
次は作ってる時のTipsをおもむろに書いていきます。

## リリース方法について
自分の作った拡張機能をリリースする際はデベロッパーダッシュボードを使います
デベロッパー登録には5ドル必要です。
https://chrome.google.com/webstore/developer/dashboard

manifest.jsonを含んだディレクトリをzipで固め、新しいアイテムを追加からzipをアップロードして、説明やスクショなどを追加して、審査してもらう感じになります。

この時の注意ですが、パーミッションが `["http://*/*", "https://*/*"]`のようにほぼ全てのWebサイトに適用できる場合は審査にすごく時間がかかります。
僕も先月審査に出したのですが、1回目の返信に２週間近くかかり、余計なパーミッションを追加していたため拒否されたので、削除して出し直してまだ返信はありません。
急いではないのであまり気にしてないですが、急いでリリースしたい！みたいなことがあれば特定のサイトでしか使えないようにするなど、パーミッションを見直す必要があります。

## Background Pagesについて
今回は使わないでしたが、拡張機能にはBackground Pagesというものもあります。
こちらは拡張機能がインストールされてからページが常駐し続けます。

Background PagesではChromeのJavaScriptAPIが全て使えるようになります。
これまで紹介した、Browser Actionなどでは一部のAPIが使えないようなので、使いたいものがある場合はBackground Pagesを使うことも視野に入れておくといいでしょう。

Background Scriptsでしか使えないものの一例ですが、右クリックのメニューを拡張する
chrome.contextMenusなどがあります。

こんなやつ
![スクリーンショット_2020-12-08_12_25_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150295/bf3905a9-22f4-4d8f-1c79-7569e7bd2a8e.png)

参考
https://developer.chrome.com/extensions/background_pages （Background Pagesについて）

https://developer.chrome.com/extensions/contextMenus (contexMenusについて）

# 最後に
という感じで、いくつかChrome拡張機能の作り方を書いていきました。
Chrome拡張であれば、今回のようなちょっとしたネタ拡張ならさっと作ることができますし、他のアプリケーションストアなどに比べてリリースの敷居もそこまで高くないので、軽くアウトプットも出せると思います（といいつつ、僕の拡張まだリリースされてないですが...）

今年は暗いニュースが多かったので、こういうネタ拡張を作ってちょっと笑ってみるのもいいかもしれないですね！


明日は @y-i さんの記事になります。