Content Scripts によるウェブページ DOM 操作と注入
「ウェブページ上の全ての価格を台湾ドルに換算する」ツールや、Grammarlyのように入力欄の横にチェックボタンを表示する機能を作りたい場合、Content Scriptsを使用する必要があります。
Content Scriptsは拡張機能の中でユーザーが現在閲覧しているウェブページ(DOM)を直接読み取り・変更できる唯一の部分です。
1. 隔離環境 (Isolated World)
コードを書き始める前に、非常に重要なセキュリティメカニズムである**Isolated World(隔離環境)**を理解する必要があります。
Content Scriptがウェブページ(例: facebook.com)に注入されると、facebook.comのDOMノード(例えば新しいボタンを追加するなど)を読み取ったり変更したりできますが、そのページの元々のJavaScript変数と直接やり取りすることはできません。
つまり、facebook.comがグローバル変数window.currentUserを定義していた場合、あなたのContent Scriptはそれを読み取れません。同様に、Content Scriptで宣言した変数も元のページの環境を汚染しません。これにより高い安全性と安定性が保証されます。
2. Manifest での Content Scripts 登録
Content Scriptsを使用する方法には「静的宣言」と「動的注入」の2種類があります。最も一般的なのは静的宣言です:
manifest.jsonに以下の設定を追加します:
{
"content_scripts": [
{
"matches": ["https://*.github.com/*", "https://github.com/*"],
"css": ["styles/content.css"],
"js": ["scripts/content.js"],
"run_at": "document_end"
}
]
}
解説:
"matches":スクリプトがどのURLで有効になるかを定義する配列。パフォーマンスとセキュリティのため、<all_urls>の使用は避け、可能な限り正確にURLを指定してください。"css"/"js":注入するスタイルシートとスクリプトのパス。"run_at":スクリプトの実行タイミングを決定します。"document_end"はDOMの解析が完了した後に実行されるため、探しているボタンやテキストが画面上に存在していることが保証され、最も安全な選択肢です。
3. 実践:GitHubページにカスタムボタンを注入
GitHubの各リポジトリページに、独自デザインの「Repo URLをクイックコピー」ボタンを追加したいとします。
scripts/content.jsに以下を記述:
// GitHubの"Star"や"Fork"ボタンがある領域を探す
const actionHeader = document.querySelector('.pagehead-actions');
if (actionHeader) {
// 独自のListItemを作成
const li = document.createElement('li');
// ボタンを作成
const myBtn = document.createElement('button');
myBtn.className = 'btn btn-sm my-custom-btn'; // 独自のCSS classを適用、またはGitHubのclassを借用
myBtn.innerText = '⚡️ Repoをコピー';
// クリックイベントをバインド
myBtn.addEventListener('click', () => {
const currentUrl = window.location.href;
navigator.clipboard.writeText(currentUrl).then(() => {
myBtn.innerText = '✅ コピー完了!';
setTimeout(() => { myBtn.innerText = '⚡️ Repoをコピー'; }, 2000);
});
});
li.appendChild(myBtn);
// ボタンをリストの先頭に挿入
actionHeader.insertBefore(li, actionHeader.firstChild);
}
styles/content.cssと組み合わせ:
.my-custom-btn {
background-color: #8b5cf6 !important;
color: white !important;
border-color: #7c3aed !important;
}
.my-custom-btn:hover {
background-color: #7c3aed !important;
}
これだけで簡単に!GitHubの外観と機能を変更することに成功しました。
4. Message Passing:Backgroundとの通信
Content Scriptsには重大な欠点があります:ほとんどのchrome.* APIを呼び出せないことです。
例えば、Content Scriptは直接クロスドメインAPIを呼び出せず(CORSにブロックされます)、高い権限を必要とするChromeコア機能にもアクセスできません。
このような場合、バックグラウンドのService Worker(background.js)に助けを求める必要があります!
Content Script(content.js)からSOS信号を送信:
// content.js
const currentTitle = document.title;
// background.jsにメッセージを送信
chrome.runtime.sendMessage(
{ action: "saveWebPage", title: currentTitle, url: window.location.href },
(response) => {
// background.jsからの返答を受信
console.log("バックグラウンドからの返答:", response.status);
}
);
Service Worker(background.js)で受信して処理:
// background.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "saveWebPage") {
// データを取得
const { title, url } = request;
console.log(`${title} をデータベースに保存中...`);
// クロスドメインAPIリクエストやデータベース書き込みを実行(ここでは省略)
// ...
// 処理完了後、content.jsに返答
sendResponse({ status: "Success! データが保存されました。" });
// 非同期APIリクエストがある場合、sendResponseを後で送信することをChromeに伝えるためtrueを返す必要がある
// return true;
}
});
これが拡張機能の最も典型的なフロントエンドとバックエンドの分離通信パターンです。Content Scriptは「フロントエンド」として画面表示とクリックイベントを処理し、Service Workerは「バックエンド」としてデータアクセスとAPI通信を担当します。
次章では、Popup小ウィンドウとユーザー設定ページ(Options)の設計方法を見ていきましょう!