WXTとSvelteでChrome拡張機能の開発
Chrome拡張機能の開発でフレームワークWXTを使ったので備忘録です。今回は拡張機能のフロントエンドではあまり例のないSvelteを選びました。
WXTってこんなもの
WXTの特徴をざっと書いていきます。
要約:素で作るよりも書きやすい&ビルド時の辛みが解消できる。
- TypeScriptに対応
- React、Vue 3、Svelte、SolidJSに対応
- HMRあり
- エントリーポイントは指定のディレクトリ以下に配置(後述)
- どこに何の機能を書くのかはっきりしている
- 多くのブラウザをサポート
- ChromeやEdge、Firefox、Safariも!
- もちろんChromium系のブラウザ(=VivaldiやArc Browserなど)も対応
- ビルドツールはVite
- zip化やデプロイも可能
- GitHub Actionの例も載っている
対応しているフロントエンドフレームワークが多く、無料です。開発も活発なようで安心です。
WXTのインストール
公式ドキュメントでは、ご丁寧にpnpm、npm、bunの3つからテンプレートを作成できる例があります。筆者はpnpmで作りました。
pnpm dlx wxt@latest init wxt-sample
実行するといくつか質問されるので選定に合わせて回答し、指示どおりインストールします。
ℹ Initalizing new project✔ Choose a template › svelte✔ Package Manager › pnpm✔ Downloading template
✨ WXT project created with the svelte template.
Next steps: 1. cd wxt-sample 2. pnpm install
素のTypeScript、Vue 3、React、SolidJS、Svelteのテンプレートから選べます。

パッケージマネージャーも選べます。ここ数年で選択肢が増えてきたのでありがたいですね。

scripts
package.json
にscriptsが用意されています。
"scripts": { "dev": "wxt", "dev:firefox": "wxt -b firefox", "build": "wxt build", "build:firefox": "wxt build -b firefox", "zip": "wxt zip", "zip:firefox": "wxt zip -b firefox", "check": "svelte-check --tsconfig ./tsconfig.json", "postinstall": "wxt prepare" },
開発時はdev
、ビルドはbuild
といった具合です。zip化もコマンドで一発なのはうれしいですね。
たとえばpnpmで開発するなら次のコマンドです。
pnpm run dev
いちいち入力するのが面倒な人向けに、fzfを使った効率化の記事を書きました。よければどうぞ。
fzfでpackage.jsonのscriptsを選んで実行
ディレクトリ構成
初期のディレクトリ構成を見てみましょう。特徴的な部分をハイライトしています。
|-- .gitignore|-- .vscode| `-- extensions.json|-- .wxt| `-- ...|-- README.md|-- package.json|-- pnpm-lock.yaml|-- src| |-- assets| | `-- ...| |-- entrypoints| | `-- ...| |-- lib| | `-- ...| `-- public| | `-- ...|-- tsconfig.json|-- wxt-env.d.ts`-- wxt.config.ts
次の項目から、省略している箇所も含めて個別に解説します。
wxt.config.ts
WXTでは設定をwxt.config.ts
に書きます。Svelteの場合、最初は次のようになっています。
import { defineConfig } from 'wxt';
// See https://wxt.dev/api/config.htmlexport default defineConfig({ srcDir: 'src', modules: ['@wxt-dev/module-svelte'],});
vite
vite.config.ts
に書く内容はwxt.config.ts
のvite
に書きます。
たとえばimportのエイリアスを使いたいなら次のように設定します。
export default defineConfig({ // ... vite: () => ({ resolve: { alias: { $lib: path.resolve("./src/lib"), }, }, // ... }),});
ただし、.wxt/tsconfig.json
を覗くとすでに@
や~
のエイリアスは設定されているため、そちらを見てから書くのがよいでしょう。
manifest
manifest.json
の中身はwxt.config.ts
に書きます。型が効いているので書きやすいです。
export default defineConfig({ manifest: { name: "拡張機能の名前~", description: "拡張機能の説明~", permissions: ["tabs"], }, srcDir: 'src', // ...});
tabs
とscripting
を使う人は注意です。
開発中はリロードの都合上permissions
のtabs
とscripting
が自動で追加されます。
自動で追加されるがゆえに書き忘れると、ビルド時に「動かないぞ!」となります。tabs
とscripting
が必要なら明示的に指定するのを忘れないようにしましょう。
src
メインとなるのがentrypoints
、assets
、public
といったディレクトリです。
Svelteのテンプレートではこれらの親のディレクトリとしてsrc
が作られます。
一方、Svelte以外(React、Vueなど)のフレームワークでは、src
ディレクトリを挟まずにルート直下に配置されます。
この挙動はwxt.config.ts
のsrcDir
で変更できます。
|-- src| |-- assets| | `-- svelte.svg| |-- entrypoints| | |-- background.ts| | |-- content.ts| | `-- popup| | |-- App.svelte| | |-- app.css| | |-- index.html| | `-- main.ts| |-- lib| | `-- Counter.svelte| `-- public| |-- icon| | |-- 128.png| | |-- 16.png| | |-- 32.png| | |-- 48.png| | `-- 96.png| `-- wxt.svg
entrypoints
WXTでは、Popup、Background、Content Scriptsのような機能ごとにエントリーポイントを分けます。
エントリーポイントは次のようにディレクトリを切っても切らなくてもよいです。
entrypoints/background/index.ts
entrypoints/background.ts
テンプレートにはよく使われるPopup、Background、Content Scriptsが用意されています。もちろんブックマークやオプション画面のほか、サイドパネルなど一通り用意されています。
publicとassets
画像などは基本assets
ディレクトリ、次のような条件を満たすのであればpublic
ディレクトリに入れます。
- ソースコードから参照されない
- 例:拡張機能のアイコン
- ファイル名を変更されたくない(ハッシュ化されたくない)
public
に入れたファイルはビルドするとそのままコピーされます。それ以外のファイルはViteを通してバンドルされる、ということですね。
.wxt
.wxt
はWXTで用意した型情報などがあります。基本的に開発者が触ることはないと思うのでスルーで問題ありません。.gitignore
にも指定されています。
.output
ビルドすると.output
の下にchrome-mv3
のようなディレクトリが作成されます。デフォルトはChromeですが、その他のブラウザにも対応しています。
|-- .output| `-- chrome-mv3| |-- background.js| |-- chunks| | `-- popup-Cx96etly.js| |-- content-scripts| | `-- content.js| |-- icon| | |-- 128.png| | |-- 16.png| | |-- 32.png| | |-- 48.png| | `-- 96.png| |-- manifest.json| |-- popup.html| `-- wxt.svg
WXTは開発中に専用のブラウザが立ち上がるようですが、筆者の環境は未対応のWSLなので未確認です。便利そうだなぁ。
そんなわけで開発用のブラウザが立ち上がらない諸君は.output/chrome-mv3
のようなディレクトリを手動で読み込みましょう。
Svelteを使うなら
拡張機能には関係ありませんが、デフォルトのままだとテキストエディタのLSPで次のようなエラーがログファイルに残りました。
No svelte.config.js found.
これはViteでのSvelteの設定を@wxt-dev/module-svelte内で次のように書いているためです。
// ... plugins: [ svelte({ // Using a svelte.config.js file causes a segmentation fault when importing the file configFile: false, preprocess: [vitePreprocess()], }), ],
コメントのようにsegmentation fault対策のようです。LSPのエラーは出ますがそのままでも支障はないようです。支障が出たら追記します。
Content ScriptでSvelteを使う例も公式ドキュメントにいろいろ書いてあります。実用的な書き方は後日記事にしようかなと考えてます。
2024年7月1日追記:WXTでのContent Scriptの書き方の例を記事にしました。よければぜひ。
WXTのcontent scriptsの書き方 | eiji.page
WXTって何の略だろう。Web Extensionの略っぽいです。公式ドキュメントやREADMEを見ると、Nuxtベースだよ、Nuxtみたいに~と書いてあるのでそこと引っ掛けた部分もあるかもしれませんね。
WXT is based of Nuxt,
“It’s like Nuxt, but for Chrome Extensions”
他の拡張機能のフレームワークはSvelteに対応していなかったり部分的に有料であるため、WXTに感謝です。