Chrome 拡張 Manifest V3 での Content Script + Side Panel 連携#
Chrome 拡張 Manifest V3 で、Content Script(ページに注入するスクリプト)と Side Panel(ブラウザ右側のパネル UI)を連携させる際に遭遇した実装上の落とし穴と対処。
アーキテクチャ#
flowchart LR
subgraph ウェブページ
CS[Content Script<br/>DOM 操作]
end
subgraph ブラウザ拡張
SP[Side Panel<br/>UI]
BG[Service Worker<br/>背景処理]
end
CS <-->|chrome.runtime<br/>.sendMessage| BG
SP <-->|chrome.runtime<br/>.sendMessage| BG
BG <-->|chrome.storage<br/>.local| ST[(Storage)]
観察された問題と対処#
1. Service Worker は頻繁に寝る
MV3 では Service Worker がアイドル時に停止する。永続的な状態を持てないため、状態管理は chrome.storage に逃がす。
- 対策: メモリ上の状態は一時的なものに限定し、永続化が必要なデータは
chrome.storage.localに書き出す - 落とし穴:
setIntervalのような時間ベースの処理は Service Worker 再起動で消える。chrome.alarmsを使う
2. Side Panel と Content Script の直接通信はできない
両者は互いを直接呼び出せない。必ず Service Worker を経由する。
sequenceDiagram
participant CS as Content Script
participant BG as Service Worker
participant SP as Side Panel
CS->>BG: sendMessage({type: 'page-data', ...})
BG->>SP: sendMessage(Side Panel にブロードキャスト)
SP->>BG: sendMessage({type: 'action', ...})
BG->>CS: sendMessage(特定のタブに転送)
- 対策: Service Worker にメッセージルーターを実装。
tabIdを添えて転送先を制御する
3. Side Panel のタブごとの状態管理
Side Panel は全タブで共有される UI。タブごとに別の状態を見せたい場合、Side Panel 側でアクティブタブを監視する。
- 対策:
chrome.tabs.onActivatedで切り替えを検知し、現在のタブ ID に紐付いた状態をchrome.storageから引く
4. Content Script の CSP 制約
注入先のサイトの Content Security Policy によっては、特定のスクリプト読み込みがブロックされる。
- 対策: 外部 CDN 依存を減らし、依存を拡張内にバンドルする。ビルド時にインライン化する
まとめ#
Service Worker は「寝る前提で設計する」。状態は Storage に、タイマーは chrome.alarms に、通信はルーター越しに、依存はバンドル内に。この 4 点を押さえると MV3 特有の落とし穴の大半は回避できる。