Chrome拡張を作ってみた

# はじめに
Qiitaでも多数の記事が公開されているChrome拡張の作り方。遅ればせながら自身でも作ってみたので記事にしました。

本稿は、最小限のChrome拡張を作成することを目的とし、Qiitaのトップページに表示される記事リストから「いいね数301以上の記事」をハイライトする仕組みを題材にしています。

なお今後の展開を見越して、この機能実現には必ずしも必要ではないjQueryを取り込んでいます。

# 環境

|||
|---|--:|
|本拡張の確認日|2023/11/08|
|ChromeのManifest Version|3|
|利用したjQuery Version|3.7.1|

# 登場人物
本稿で必要なファイルは二つ(＋jQuery.js）のみです。

①manifest.json
②content.js
（③jquery-3.7,1.min.js）

jQueryは以下から入手し、ローカルへ保存しています。
https://code.jquery.com/jquery-3.7.1.min.js

# 配置
まずはローカルに本拡張の保存ディレクトリを作成します。
今回は「sample」と名付けました。

sample直下に「manifest.json」を配置し、scriptsディレクトリ下に「jquery-3.7.1.min.js」および「content.js」を配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/4179de17-3aa8-f694-6970-32b2b0828fa4.png)

# manifest.json
manifest.jsonも可能な限りシンプルに作成します。

``` json:manifest.json
{
  "manifest_version": 3,
  "name": "Qiita投稿用サンプル",
  "description": "Qiitaトップページのいいね数301以上をハイライトします。",
  "version": "0.1",
  "content_scripts": [
    {
      "js": [
        "scripts/jquery-3.7.1.min.js",
        "scripts/content.js"
      ],
      "matches": [
        "https://qiita.com/"
      ]
    }
  ]
}
```

:::note info
manifestバージョンにより制約や挙動が変わる処理もあります。
今回はページ内のDOMに色付けをするだけなので大きな差はありませんが、Version 3を用いています。

また、icon定義は省略しています。
:::

:::note warn
manifest.jsonの、文字コードはUTF-8にしましょう。
Chrome拡張取り込み時にUTF-8以外でマルチバイトを含む場合エラーが発生します。
:::

manifest.jsonの定義は公式を参照ください。
https://developer.chrome.com/docs/extensions/mv3/manifest/

### アプリケーション情報
本稿で使用している各定義は以下の通りです。
|属性|値|
|---|---|
|name|拡張ツールの名称を定義します|
|description|同、概要を定義します|
|version|同、バージョンを定義します|

これらの設定はChrome拡張を取り込んだ後の以下の部分に表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/b6971ae5-9479-30ef-d735-b04b0447758e.png)


### content_scripts
content_scriptsでは、ページ読み込み時に展開するJavaScriptを定義します。

#### js
今回はQiitaのトップページを読み込んだ際に、「scripts/jquery-3.7.1.min.js」と「scripts/content.js」を読み込むよう定義しています。

:::note warn
jsで定義するスクリプトは順序を意識する必要があります。
本稿の定義を逆順にした場合、content.jsからjquery処理を呼び出すよう記載しているとエラーが発生します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/73270ca5-0ea5-1ccc-31b3-665a788d3dd3.png)

:::

#### matches
matches要素ではChrome拡張が動作ターゲットとするサイトをURLで記載します。
ワイルドカードなどを用いた定義を行うことが多いですが、今回はQiitaのトップページのみをターゲットとするためトップページのURLを指定しています。

# 実装の前に確認
content.jsの実装を始める前に、Qiitaのトップページを確認します。

2023/11/08 11:00のQiitaトップページは以下のようなものでした。
※いいね部分以外はマスクしています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/0dd8adc5-3968-a093-b2e0-c525044c9366.png)



メイン部分に表示されている「いいね数」が300以上の記事をハイライトするChrome拡張を作成していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/ee737d2f-8d1d-9117-f0ae-baf82cffd9de.png)


Chromeのdeveloper toolsでDOMを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/68bbec17-0b7d-2191-073c-0a7ce643546f.png)

mainタグ配下に、sectionが切られており、articleで一つ一つの記事が紹介されています。残念ながら いいね数を意味するclassなどは付与されていません。

今回は、article下のfooter⇒div⇒div⇒spanの二つ目 というDOM構成に頼った指定とすることにします。


# content.js
manifest内のcontent_scriptで定義したJavaScriptファイルは当該ページがロードされた際にあたかもそのサイト上のScriptとして動作してくれます。

つまり、サイト上に表示されているDOMにそのままアクセスが可能です。

ということで、、、

``` javascript:content.js
// main配下のarticleを取得
var articles = $("main article");

for(var i=0; i<articles.length; i++) {
  // いいね数の場所をarticle内のfooter->div->div->spanの二つ目と想定してしまう
  var good_cnt = $(articles[i]).find("footer div div span")[1];

  // いいね数が300より多ければ
  if(parseInt($(good_cnt).text(), 10) > 300) {
    // articleの背景を薄い青色にする
    $(articles[i]).css("background-color", "#ccf");
  }
}
```

だいぶ強引な実装感は否めませんが、今回はこれで良しとします。

# Chrome拡張への読み込み
出来上がったChrome拡張を取り込みます。
Chromeメニュー⇒拡張機能⇒拡張機能を管理
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/8af8d812-5ab1-524b-9246-08d31877c3c6.png)


パッケージ化されていない拡張機能を読み込む
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/dd91eaba-79e1-0179-d02e-479206da2739.png)


保存先のディレクトリを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/661bb07b-13e5-feac-e289-f36583504a0e.png)


取り込めました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/e652ba91-ccc4-6798-fa76-2b867bc6f57f.png)



# Qiitaのトップ画面を開いてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/3b1d9af8-78f9-cfa3-c256-3c34ee7342e5.png)
意図した通り、いいね数503の記事がハイライトされ、154や296の記事はそのまま表示されました。


# おわりに
今回はサイト内の情報だけを使い、同サイト内の色を変えるというシンプルなChrome拡張を実装しました。
このように、当該サイトのDOM改変を行うだけであれば、manifest.jsonの定義とcontent.jsの用意だけで実現できます。便利！


# おまけ
### content.jsの動作確認
console.logを使ってコンソールにログを出すことが出来ます。

また、Chromeのdeveloper toolsのSourceタブから、Content scriptsを選択してデバッグを行うことも出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/e7c39c16-92a0-d52e-c040-1b653cf91a8d.png)



### エラー発生時
content.js内でエラーが発生した場合、Chrome拡張の一覧にエラーログが記録されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/f1571e0a-57c3-8633-afc0-4f9d1d8819a9.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/588f9022-a6e6-e1ce-9a4a-ff938d36ceae.png)