📚

生成AIを活用してChrome拡張機能をサクッと作る

2024/09/16に公開

生成AIの助けを借りながら、Chrome拡張機能をはじめて作ってみた時の記録です。

はじめに

私はこれまで「拡張機能」というものの開発に興味を持ったことはあるものの、実際に手をつけたことはありませんでした。大抵の場合、自分が使いたい機能は他の誰かが開発していますし、拡張機能の開発方法を一から覚えるのも面倒だからです。

しかし、今では生成AIの力を借りることで、プロンプトを書けば欲しいプログラムをすぐに出力できるようになりました。

そこで今回は、ChatGPTを活用してChrome拡張機能を開発するまでの流れを作業メモとして記事にしておきたいと思います。Chrome拡張機能の開発の流れを網羅的に説明できているわけではありませんので、あらかじめご了承ください。

生成AIを活用してChrome拡張機能を開発してみたい人の一助になれば幸いです。

作ったもの

今回作成したのは、Amazonの本の販売ページに「図書館でさがす」というボタンを設置し、その本の図書館での貸し出し情報を表示するページへと遷移する拡張機能です。


拡張機能の動作例。「図書館でさがす」をクリックするとカーリルのページに遷移する

ボタンを押すと、「カーリル」というサイトに遷移します。カーリルは、検索した本が全国の図書館で借りられるかどうかを検索してくれる便利なサイトです。

実は、カーリルのAPIを活用した拡張機能がすでに存在します。しかし自分の環境では設定画面をうまく開けませんでした。そこで今回は自分用の拡張機能を開発してみることにしました。

https://sonohon.com/

上記の拡張機能では、図書館での空き状況をAmazonのページ内にインライン表示できます。今回開発する拡張機能では、実装をシンプルにするために、サイトへ遷移するボタンを設置するだけにしています。

拡張機能のソースコード

今回開発した拡張機能のソースコードは以下のリポジトリに公開しています。Chromeウェブストアには公開していませんので、もし利用したい場合はREADMEに記載している方法でインストールしてください。(READMEも生成AIに書いてもらいました。)

https://github.com/tanny-pm/chrome-goto-library

開発環境

開発環境は以下のとおりです。作成したプログラムはChrome上で動作・デバッグできるため、開発環境の構築がほとんど不要なのが手軽で良いですね。

  • Chrome 128.0.6613.138(Official Build)(arm64)
  • ChatGPT無料版(2024.09.15に利用)
  • Visual Studio Code

なお、ChatGPTは無料版の回数制限によって、途中からモデルがGPT-4oからGPT-3.5に切り替わりました。今回の開発であれば、モデルの違いはとくに感じられませんでした。

開発手順

今回の開発は以下のような流れで進めました。ほとんど自分ではコードを書いていません。この記事では実施したことの要点だけ紹介します。

  • 要求仕様を考える
  • ChatGPTに質問する
  • ソースコードをコピペしてChrome上でテストする

Chrome拡張機能の概要を調べる

まず、Chrome拡張機能の開発の流れを大まかに把握しておきます。公式ドキュメントを読んだ方が良いかもしれませんが、ここではChatGPTに聞いてみます。

プロンプト

Chrome拡張機能を開発したいと思います。
まず、Chrome拡張機能開発の手順を、実例を交えながら簡潔に説明してください。

以下にChatGPTからの回答を記載します。開発の大まかな流れがよくわかりました。


ChatGPTの回答

Chrome拡張機能の開発手順は以下の通りです。

  1. 基本ファイルの準備
    manifest.json: Chrome拡張機能の設定ファイル。バージョン、権限、アイコンなどを定義します。
{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0",
  "permissions": ["activeTab"],
  "action": {
    "default_popup": "popup.html"
  }
}
  1. HTMLやJavaScriptファイルの作成
    popup.html: 拡張機能のボタンをクリックした時に表示されるUIを定義。
    popup.js: JavaScriptで動作を制御します。
  2. 機能を実装
    たとえば、特定のページの情報を取得してポップアップに表示する場合、JavaScriptでchrome.tabsAPIを使用します。
document.getElementById("button").addEventListener("click", () => {
  chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
    chrome.scripting.executeScript({
      target: { tabId: tabs[0].id },
      function: () => alert(document.title)
    });
  });
});
  1. 拡張機能をテスト
    Chromeの「拡張機能」ページで「パッケージ化されていない拡張機能を読み込む」を選び、プロジェクトフォルダを指定してテストします。
  2. 配布
    GitHubにソースコードを公開したり、Chrome Web Storeで公開する方法があります。

このように、まず全体的な流れを抑えておくと、この後の開発をスムーズに進められますね。

基本機能を実装する

次に、拡張機能の仕様を考えて、そのソースコードをChatGPTに出力してもらいます。

カーリルではhttps://calil.jp/book/{ISBN}という形式でURLを指定すると本の詳細ページを開けます。その仕組みを利用して画面遷移を実現します。

プロンプト

以下のような仕様のChrome拡張機能の作成方法を順に説明してください。

#概要
・Amazonで本を検索したとき、その本に該当するカーリルのページを開くためのボタンを、Amazonの画面上に表示する。

#仕様
・ユーザーがAmazonで本を検索し、本の詳細画面に遷移すると拡張機能が有効になる。
・その本のISBNをAmazonの画面上から取得する。
・ISBNに応じたURLを開くためのボタンをAmazonの画面上に表示する。
   ・表示する箇所は後で調整するので、今は仮の場所に表示する。
   ・URLはhttps://calil.jp/book/{ISBN}とする。
・ボタンを押すと、カーリルのページが別タブで開く。

拡張機能のためのリポジトリを作成し、ChatGPTの回答にしたがってソースコードをコピペします。


ChatGPTの回答
以下の手順に従って、指定されたChrome拡張機能を作成できます。

  1. 拡張機能の基本ファイル作成
    まず、Chrome拡張機能には、manifest.jsonという設定ファイルが必要です。これにより、Chromeに拡張機能の動作を伝えます。
manifest.json
{
  "manifest_version": 3,
  "name": "Amazon to Calil",
  "version": "1.0",
  "description": "Amazonの本の詳細ページにカーリルのボタンを追加します。",
  "permissions": ["activeTab", "scripting"],
  "action": {
    "default_popup": "popup.html"
  },
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["https://www.amazon.co.jp/*"],
      "js": ["content.js"]
    }
  ]
}

permissions: activeTab と scripting で現在のタブにスクリプトを注入する権限を持たせます。
content_scripts: Amazonのページで動作するスクリプトです。

  1. ボタンの表示処理
    Amazonの本の詳細ページにISBNに基づいてボタンを表示するスクリプトを作成します。
content.js
// ISBNを取得する関数
function getISBN() {
  // ISBNが含まれる要素を取得 (Amazonの構造に依存するため調整が必要)
  let isbnElement = document.querySelector("#detailBullets_feature_div .a-text-bold:contains('ISBN-13')");
  if (isbnElement) {
    return isbnElement.nextElementSibling.textContent.trim();
  }
  return null;
}

// ボタンを追加する関数
function addCalilButton(isbn) {
  let button = document.createElement("button");
  button.textContent = "Calilで確認";
  button.style.position = "fixed"; // 仮の位置設定
  button.style.top = "10px";
  button.style.right = "10px";
  button.onclick = function () {
    window.open(`https://calil.jp/book/${isbn}`, "_blank");
  };
  document.body.appendChild(button);
}

// ISBNを取得し、ボタンを追加
let isbn = getISBN();
if (isbn) {
  addCalilButton(isbn);
}

このスクリプトは、Amazonの本の詳細ページからISBNを取得し、ページ上にボタンを表示します。ボタンを押すと、指定されたISBNに基づいたカーリルのページが別タブで開きます。

  1. 拡張機能をテストする
    Chromeのアドレスバーに chrome://extensions/ と入力し、拡張機能管理ページを開きます。
    右上の「デベロッパーモード」を有効にします。
    「パッケージ化されていない拡張機能を読み込む」をクリックし、拡張機能のフォルダを選択します。
    Amazonの本の詳細ページに移動して、ボタンが表示されるか確認します。

  2. ボタンの位置調整
    ボタンの位置は、button.style のCSSプロパティを編集することで簡単に調整できます。


コピペが完了したら、完成したファイルをChromeに登録しておきます。

テストして改修する

ISBNの取得方法などを細かく指定していないため、このタイミングではまだ動きません。拡張機能をChrome上で実行してデバックします。

拡張機能の実行時に発生したエラーは、拡張機能の詳細画面から確認できます。この内容を参考にして、修正指示をChatGPTに与えます。(エラーはChrome標準のデバッガからも確認できます。)


エラー画面の例。ISBNを取得できていないというエラーが表示されている

まず、ボタンの表示場所とISBNの取得場所を指定します。Chromeの「検証」機能を活用してAmazonの商品ページのソースコードを確認し、該当する箇所を探しました。

プロンプト

ボタンは、以下の要素の下に追加してください。
<div id="quantityRelocate_feature_div" ...(略)

ISBNは以下の要素から取得してください。
<li><span class="a-list-item"> <span class="a-text-bold">ISBN-10</span> <span>4062932121</span> </span></li>

以下のように、挿入箇所を指定するためのコードを書いてくれます。私はJavaScriptの扱いは慣れていないので、このような支援は助かります。

contents.js(一部)
  // ボタンを<div id="quantityRelocate_feature_div">の下に挿入
  let quantityRelocateElement = document.getElementById("quantityRelocate_feature_div");
  if (quantityRelocateElement) {
    quantityRelocateElement.insertAdjacentElement("afterend", button);
  }

この時点でボタンの表示と画面遷移が完成しました。

次に、ボタンのデザインの修正も依頼します。CSSに慣れた人であればすぐに実装できると思いますが、私の場合は自然言語でデザインを指定できた方が楽でした。

ボタンのデザインを以下のように調整してください。

・左右に目一杯広げる
・padddingを上下1px, 左右6pxにする
・文字を中心に配置する
・ボーダーを消す
・背景色を#2ab6e9にする
・マウスオーバーした時に少し暗くする 
・マージンを下に8px
・角を丸める

すべての修正を反映したコードは以下のとおりです。ほとんど自分でコーディングすることなく実装が完了してしまいました。

content.js
// ISBNを取得する関数
function getISBN() {
  // 全てのa-text-boldクラスを持つspan要素を取得
  let isbnElements = document.querySelectorAll("li span.a-text-bold");
  for (let element of isbnElements) {
    // テキストが "ISBN-10" かどうか確認
    if (element.textContent.includes("ISBN-10")) {
      // 次の兄弟要素にISBN番号があるので、それを取得
      return element.nextElementSibling.textContent.trim();
    }
  }
  return null;
}

// ボタンを追加する関数
function addCalilButton(isbn) {
  let button = document.createElement("button");
  button.textContent = "図書館でさがす";

  // ボタンのデザインを指定
  button.style.width = "100%";       // 幅を左右に目一杯広げる
  button.style.height = "29px";      // 高さを29pxに設定
  button.style.padding = "1px 6px";  // 上下1px, 左右6pxのパディング
  button.style.marginTop = "8px";    // 上に8pxのマージンを追加
  button.style.marginBottom = "16px"; // 下に16pxのマージンを追加

  button.style.border = "none";         // ボーダーを消す
  button.style.borderRadius = "100px";  // 角を丸める(100pxの半径)
  button.style.backgroundColor = "#2ab6e9";  // 背景色を#2ab6e9に

  button.style.textAlign = "center";  // 文字を中央に配置
  button.style.color = "white";       // 文字色を白に
  button.style.fontSize = "14px";     // フォントサイズを14pxに設定

  button.style.cursor = "pointer";    // マウスオーバー時のカーソルをポインタに

  // マウスオーバー時の効果を追加
  button.onmouseover = function () {
    button.style.backgroundColor = "#249cc5"; // 少し暗い色に
  };
  button.onmouseout = function () {
    button.style.backgroundColor = "#2ab6e9"; // 元の色に戻す
  };

  // ボタンを<div id="quantityRelocate_feature_div">の下に挿入
  let quantityRelocateElement = document.getElementById("quantityRelocate_feature_div");
  if (quantityRelocateElement) {
    quantityRelocateElement.insertAdjacentElement("afterend", button);
  }

  // ボタンをクリックするとカーリルのページを新しいタブで開く
  button.onclick = function (event) {
    event.preventDefault(); // デフォルトの動作を防ぐ
    event.stopPropagation(); // イベントのバブリングを防ぐ
    window.open(`https://calil.jp/book/${isbn}`, "_blank");
  };
}

// ISBNを取得し、ボタンを追加
let isbn = getISBN();
if (isbn) {
  addCalilButton(isbn);
}

画像生成AIでアイコンを作成する

最後に、拡張機能のアイコンも用意します。まず、アイコンの追加方法を確認します。

プロンプト

この拡張機能にアイコンを追加する方法を教えてください。

アイコンを追加するためには、3つのサイズの画像を用意する必要があるようです。manifest.jsも変更します。


ChatGPTの回答

Chrome拡張機能にアイコンを追加するためには、manifest.jsonファイルにアイコンを指定する必要があります。拡張機能では、ツールバーやメニューに表示されるアイコンや、Chrome拡張管理ページで表示されるアイコンを設定できます。

以下は、アイコンを追加するための手順です。

  1. アイコン画像を用意する
    アイコンとして使用する画像はPNG形式で、以下のサイズが一般的に必要です:

16x16 (ツールバーなどに表示される小さなアイコン)
48x48 (拡張機能管理ページなどに表示されるアイコン)
128x128 (Chrome拡張ストアに表示されるアイコン)
これらの画像を icons フォルダに保存します。 例:

icons/
  icon16.png
  icon48.png
  icon128.png
  1. manifest.jsonにアイコンを追加する
    manifest.json ファイルに以下のように icons フィールドを追加します。
{
  "manifest_version": 3,
  "name": "Amazon to Calil",
  "version": "1.0",
  "description": "Amazonの本の詳細ページに、対応するカーリルのリンクを追加します。",
  "permissions": [
    "activeTab"
  ],
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  },
  "action": {
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    },
    "default_popup": "popup.html",
    "default_title": "Amazon to Calil"
  },
  "content_scripts": [
    {
      "matches": ["https://www.amazon.co.jp/*"],
      "js": ["content.js"]
    }
  ]
}
  1. manifest.jsonの変更内容の説明
    icons: これはChrome拡張管理ページや拡張ストアで表示されるアイコンです。異なるサイズを指定できます。
    action.default_icon: これはChromeのツールバーに表示されるアイコンです。必要に応じて異なるサイズのアイコンを指定します。
  2. アイコンの確認
    拡張機能が正しく動作し、アイコンが表示されるか確認するために、Chromeの拡張機能管理ページに移動し、デベロッパーモードをオンにして拡張機能をリロードします。

今回はアイコン画像も生成AIで作成することにしました。Canvaの生成AI機能を活用して、アイコンの元画像を作成しました。


Canvaの画像作成画面。生成AIで図書館・本に関連するアイコンを作成した

Canvaで作成した画像を512pxで出力した後、Figmaで3つのサイズにリサイズして、iconsディレクトリ内に登録します。

これでアイコンを設定することができました。この手の開発では画像作成が面倒になりやすいですが、画像生成AIを使えばお手軽です。


Chrome拡張機能の管理画面。設定したアイコンが表示されている

まとめ

今回は、生成AIを駆使して自分用のChrome拡張機能を作成しました。はじめてChome拡張機能を開発しましたが、やりたいことを生成AIに質問するだけで、非常にスムーズに実装できました。最初のプロンプトを書いてから1時間以内で実装が完了しています。

生成AIの登場により、新しい分野の開発を始めるまでのハードルがとても下がったと感じています。今回のように、アプリの拡張機能を開発する際は、それぞれのアプリの独自のお作法を知っている必要がありますが、その部分を生成AIが手助けしてくれます。そのため、開発者としては実装したい機能を考えることに集中できます。

VS CodeやFigmaなど、ユーザーが独自の拡張機能を開発できるアプリは数多くあります。何か効率化できそうな作業あがれば、今後は積極的に拡張機能を開発してみたいと思います。

GitHubで編集を提案

Discussion