WXT(ブラウザ拡張/Manifest V3)

何を解決する道具か

[[ブラウザ拡張機能]] は、manifest.json と複数のスクリプトを決まった構成で配置したZIPです。素で作ると次が手作業になります。

  • manifest とスクリプトの対応を手で維持する(ファイルを増やすたびに書き足す)
  • Chrome と Firefox でmanifest の書式が違うため、2種類を別々に管理する
  • 開発中の再読み込みを毎回ブラウザの拡張管理画面から行う

WXT は [[Vite]] を土台に、これらをビルド時に吸収する枠組みです。ファイルの置き場所から manifest を生成し、ブラウザごとの差分を出し分け、変更時に拡張を自動で再読み込みします。

// entrypoints/content.ts — 置き場所が役割を決める
export default defineContentScript({
  matches: ['https://example.com/*'],
  main() {
    document.title = `[拡張] ${document.title}`
  },
})

Manifest V3の制約

拡張の仕様は Manifest V2 から V3 へ移行しました。V3を前提に設計しないと後から作り直しになるため、制約を先に押さえます。

Manifest V2Manifest V3
常駐スクリプトバックグラウンドページ(常駐)Service Worker(使われないと停止する)
外部コードの実行eval や外部スクリプトが可能禁止(同梱したコードのみ)
通信の書き換えリクエストを都度JSで加工宣言的なルールで指定

最大の落とし穴が Service Worker です。いつ止まってもよい前提で書く必要があり、変数に持った状態は消えます。保持したい値は [[WebストレージとCookie]] や拡張のストレージAPIへ書き出します。「開発中は動いていたのに、しばらく放置すると壊れる」という症状はほぼこれが原因です。

3つの実行文脈

拡張のコードは、権限も寿命も違う場所で動きます。ここを混同すると動かない理由が分かりません。

  • content script — 閲覧中のページに注入される。[[DOM]] は触れるが、そのページのJS変数とは隔離されている
  • background(Service Worker) — 拡張全体の中枢。拡張APIを広く使えるが、UIもDOMも持たない
  • popup / options — ツールバーのアイコンや設定画面。開いている間だけ生きる

この3つはメッセージでやり取りします。content script から拡張APIの大半は呼べません — 必要な処理は background へ依頼します。Electron のレンダラーとメインプロセスの関係と同じ構図です。

初学者向けポイント

  • 権限(permissions)は要求するほど審査もユーザーの警告表示も重くなります。<all_urls> を安易に要求せず、必要なドメインに絞ります
  • content script のスタイルはページ側のCSSと衝突します。閲覧中のページの見た目を壊さないよう、影響範囲を限定する仕組み(Shadow DOM など)を使います
  • [[TypeScript]] を入れると拡張APIの型が効きます。文脈ごとに使えるAPIが違うため、型の支援があると誤りに早く気づけます
  • ストアの審査では難読化されたコードが弾かれます。ビルド設定は読み取れる形の出力にしておきます

関連技術とのつながり

  • [[ブラウザ拡張機能]] — 拡張そのものの仕組み。WXT はその開発を支える側
  • [[Vite]] — ビルドと開発サーバーの土台
  • [[TypeScript]] — 文脈ごとに異なる拡張APIの型を効かせる
  • [[WebストレージとCookie]] — Service Worker が止まっても消えない置き場
  • [[JavaScript]] — content script はページのJSとは隔離された文脈で動く
Q: Manifest V3で常駐スクリプトがService Workerに変わったことによる注意点はどれ?
- [ ] DOMを直接操作できるようになった
- [x] 使われないと停止するため、変数に持った状態は消える前提で書く必要がある
- [ ] 拡張APIが使えなくなった
解説: 保持したい値はストレージへ書き出します。放置後に壊れる症状の多くはこれが原因です。

Q: content scriptについて正しい説明はどれ?
- [x] 閲覧中のページのDOMは触れるが、そのページのJS変数とは隔離されている
- [ ] 拡張APIをすべて自由に呼べる
- [ ] ポップアップを開いている間だけ動く
解説: 拡張APIの大半はbackgroundへメッセージで依頼します。権限を分けることで被害範囲を限定しています。

Q: 拡張の `permissions` を必要最小限にすべき理由はどれ?
- [ ] ビルドサイズが小さくなるため
- [x] 要求するほど審査が重くなり、ユーザーへの警告表示も強くなるため
- [ ] Service Workerの寿命が延びるため
解説: 権限は利用者に提示されます。`<all_urls>` のような広い要求は導入の障壁になります。