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 V2 | Manifest 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>` のような広い要求は導入の障壁になります。