はじめに
ブラウザ拡張機能を作ったことがある人なら分かると思うんですけど、あの開発体験って正直なところ結構しんどいんですよね。manifest.jsonの設定が面倒だったり、ChromeとFirefoxで微妙に仕様が違ったり、開発中に毎回拡張機能をリロードしなきゃいけなかったり。
そんな悩みを一発で解決してくれるのが、今回紹介するWXTというフレームワークです。
WXTは、Next.jsやNuxtのような「開発者体験を最優先に考えた」ブラウザ拡張機能開発フレームワークで、GitHubで8.7k以上のスターを獲得しています。個人的には、これを使い始めてから拡張機能開発のハードルがかなり下がったなと感じています。
特徴・メリット
マルチブラウザ対応が神
WXTの一番の魅力は、同じコードベースでChrome、Firefox、Edge、Safari、その他Chromiumベースのブラウザすべてに対応できる点です。しかも、Manifest V2とV3の両方に対応しているので、既存の拡張機能の移行も楽になります。
これ、意外と大きいんですよ。普通にやると各ブラウザ向けにmanifest.jsonを微調整したりする必要があるんですけど、WXTならビルド時にオプション指定するだけで済みます。
HMR対応で開発効率が爆上がり
開発中に変更を加えるたびに拡張機能をリロードする必要がなくなります。UI部分の変更はHot Module Replacement(HMR)でリアルタイム反映、コンテンツスクリプトやバックグラウンドスクリプトも高速リロードしてくれます。
30代になって思うのは、こういう「開発の待ち時間」を削減してくれるツールの価値って本当に大きいということ。時短は正義です。
ファイルベースのエントリーポイント
Next.jsのApp Routerみたいに、ファイルを配置するだけでmanifest.jsonが自動生成されます。entrypoints/ディレクトリにファイルを置くだけで、popupやcontent script、background scriptが自動的に認識されるんですよね。
設定ファイルをゴリゴリ書く必要がないので、QOL上がります。
TypeScript・フレームワーク対応
TypeScriptがデフォルトで使えるのはもちろん、Vue、React、Svelteなど好きなフロントエンドフレームワークを組み合わせられます。Viteベースなので、Viteプラグインもそのまま使えるのが便利です。
インストール方法
新規プロジェクトの作成は、以下のコマンド一発で完了します。
# npmの場合
npx wxt@latest init my-extension
# pnpmの場合
pnpm dlx wxt@latest init my-extension
# bunの場合
bunx wxt@latest init my-extension
対話形式でテンプレートを選べるので、使いたいフレームワーク(Vanilla、Vue、React、Svelteなど)を選択すればOKです。
既存プロジェクトに追加する場合は:
npm install wxt
基本的な使い方
プロジェクト構造
WXTプロジェクトの基本構造はこんな感じです。
my-extension/
├── entrypoints/
│ ├── popup/
│ │ ├── index.html
│ │ └── main.ts
│ ├── background.ts
│ └── content.ts
├── public/
│ └── icon.png
├── wxt.config.ts
└── package.json
popupの作成
entrypoints/popup/ディレクトリにファイルを配置するだけで、popupページが作成されます。
<!-- entrypoints/popup/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Extension</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./main.ts"></script>
</body>
</html>
// entrypoints/popup/main.ts
import './style.css';
document.querySelector('#app')!.innerHTML = `
<h1>Hello WXT!</h1>
<button id="btn">Click me</button>
`;
document.querySelector('#btn')?.addEventListener('click', () => {
alert('Clicked!');
});
Background Scriptの作成
バックグラウンドスクリプトも同様にシンプルです。
// entrypoints/background.ts
export default defineBackground(() => {
console.log('Background script loaded!');
// 拡張機能インストール時の処理
browser.runtime.onInstalled.addListener(() => {
console.log('Extension installed');
});
});
defineBackground関数でラップするだけで、適切な設定が自動的に適用されます。
Content Scriptの作成
Webページに注入するContent Scriptもファイルベースで定義できます。
// entrypoints/content.ts
export default defineContentScript({
matches: ['*://*.example.com/*'],
main() {
console.log('Content script injected!');
// DOMを操作
const div = document.createElement('div');
div.textContent = 'Injected by WXT!';
div.style.cssText = 'position: fixed; top: 10px; right: 10px; background: #333; color: #fff; padding: 10px; z-index: 9999;';
document.body.appendChild(div);
},
});
開発サーバーの起動
# 開発モード(Chrome向け)
npm run dev
# Firefox向け
npm run dev:firefox
これでブラウザが自動的に起動し、拡張機能がロードされます。コードを変更すると自動的にリロードされるので、開発がサクサク進みます。
ビルド
# Chrome向けビルド
npm run build
# Firefox向けビルド
npm run build:firefox
# 全ブラウザ向けビルド
npm run build -- --browser chrome,firefox,edge
実践的なユースケース
ユースケース1: Webページの情報を収集する拡張機能
例えば、ECサイトの価格を監視する拡張機能を作る場合:
// entrypoints/content.ts
export default defineContentScript({
matches: ['*://*.amazon.co.jp/*'],
main() {
const priceElement = document.querySelector('.a-price-whole');
if (priceElement) {
const price = priceElement.textContent;
// バックグラウンドに価格情報を送信
browser.runtime.sendMessage({
type: 'PRICE_DETECTED',
price: price,
url: window.location.href
});
}
},
});
ユースケース2: ストレージを使った設定管理
// lib/storage.ts
import { storage } from 'wxt/storage';
// 型安全なストレージ定義
export const settings = storage.defineItem<{
darkMode: boolean;
notifications: boolean;
}>('local:settings', {
fallback: {
darkMode: false,
notifications: true,
},
});
// 使用例
const currentSettings = await settings.getValue();
await settings.setValue({ ...currentSettings, darkMode: true });
ユースケース3: 複数拡張機能でのコード共有
WXTにはモジュールシステムがあるので、複数の拡張機能間でコードを再利用できます。社内ツールを複数作る場合なんかに便利ですね。
まとめ
WXTは、ブラウザ拡張機能開発の面倒な部分をほぼ全部解決してくれるフレームワークです。
個人的に推しポイントをまとめると:
- マルチブラウザ対応が一つのコードベースで完結
- HMR対応で開発効率が劇的に向上
- ファイルベース設定でmanifest.jsonを手書きする必要なし
- TypeScript + 好きなフレームワークの組み合わせ自由
ブラウザ拡張機能を作りたいけど面倒そうと思っていた人、既存の拡張機能をManifest V3に移行しなきゃいけない人には特におすすめです。
正直なところ、2025年にブラウザ拡張機能を新規開発するならWXT一択ですね。公式ドキュメントも充実しているので、まずは触ってみてください。
公式サイト: https://wxt.dev/ GitHub: https://github.com/wxt-dev/wxt