🧩

ViteベースのChrome拡張開発フレームワーク『WXT』がいい感じ

2024/02/15に公開

はじめに

ブラウザ拡張機能の開発は、通常のWeb開発とは微妙に異なるがゆえの面倒が生じます。
manifest.jsonの記入漏れ、増えるエントリポイント、UI表示のための querySelector MutationObserver、ストア審査と自動デプロイ などなど。
最近『Plasmo』がこれら全てを解決するフレームワークとして広まりましたが、WXTがそれを超えそうだ というお話です。

Plasmoって何?という人は先にこちらをどうぞ。
https://zenn.dev/nado1001/articles/plasmo-browser-extension

WXTとは?

https://wxt.dev

  • ブラウザ拡張機能開発フレームワーク
  • 『拡張機能におけるNuxt.js』を謳う
  • 2023年7月頃からスタートし、現在v1のリリースに向けて開発中
  • ライバルはPlasmo

経緯

作者のaklinker1氏は、CRXJSの上位互換にあたるViteプラグイン vite-plugin-web-extension を2年ほど開発していましたが、プラグインだけでは実現できない機能 (ファイルベースエントリポイント, UIマウント等) のために新たにプロジェクトを立てた、という経緯のようです。

サンプルコード

WXTでUIをもつContent Scriptはこのように書きます。
Plasmoとの大きな違いは以下のところでしょうか。

  1. exportするのはdefineContentScriptのみ (run_at等もここに書く)
  2. 実行されるのはファイル全体ではなくmainメソッド
  3. UIの作成、マウントは自分で書く
entrypoints/example-ui.content/index.tsx
// 1. Import the style
import './style.css';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';

export default defineContentScript({
  matches: ['<all_urls>'],
  // 2. Set cssInjectionMode
  cssInjectionMode: 'ui',

  async main(ctx) {
    // 3. Define your UI
    const ui = await createShadowRootUi(ctx, {
      name: 'example-ui',
      position: 'inline',
      anchor: '#anchor',
      onMount: (container) => {
        // Create a root on the UI container and render a component
        const root = ReactDOM.createRoot(container);
        root.render(<App />);
        return root;
      },
      onRemove: (root) => {
        // Unmount the root when the UI is removed
        root?.unmount();
      },
    });

    // 4. Mount the UI
    ui.mount();
  },
});

既存製品のよくないところ

WXTの何が良いのか?
既存製品であるCRXJS (バンドラープラグイン全般)、Plasmoと比較してみましょう。
いずれとも私がそれぞれで拡張機能を作った上で感じた主観的な評価です。

CRXJSの場合

https://crxjs.dev/vite-plugin

  • (CRXJSは) 古い
  • 主にバンドルと自動再読み込みしかできない
  • manifestは手書き

Plasmoの場合

https://www.plasmo.com/
いいところは山ほどあるけれど…

  • UIライブラリのレンダリング処理をライブラリ側で隠蔽[1]
    • 使えるUIライブラリが制限される
    • 動的要素ではReactインスタンスが増えつづける
  • world: "MAIN" が不安定[2][3]
  • 開発用ブラウザを別途用意する必要がある[4]
  • parcelベース (npm trends)
  • 出力コードにparcelのランタイムが埋め込まれる

WXTのいいところ

  • Viteベース
  • UIライブラリ非依存 (Viteで扱えればなんでも)
  • UIマウントの処理は自分で書く
    • 人によってはよくないかも。汎用と面倒のトレードオフ。
  • 開発用ブラウザ自動起動
  • Firefox審査用のソースコードzip生成
  • 組み込みのブラウザモック
    • chrome, browser APIが絡んだ自動テストが可能
  • その他 Plasmo, CRXJS, vite-plugin-web-extension のいいところ

Plasmoとの星取表:
https://wxt.dev/guide/compare.html

WXTにまだ無いもの

  • 動的要素・複数要素へのマウント
    • MutationObserverを利用して実装可能 (後述)
  • useStorageのようなhooks
  • ブラウザ別マニフェスト
  • ストア提出用 GitHub Actions

まとめ

WXTはPlasmoに追いつけ追い越せと開発が進められているフレームワークです。
基本的な機能はすでに揃っており、Plasmoと比較して開発体験はかなり良いので、乗り換え先として申し分ない選択肢だと思います。
作者曰く「Production-Readyだが完全ではない」[5]とのこと。これからの発展に期待です。
開発はGitHubでIssueやPRを受け付けています。質問もDiscussionに書けばすぐに返信してくれます。
https://github.com/wxt-dev/wxt

おまけ

動的マウントの実装に使ったもの
https://gist.github.com/ookkoouu/7220fad9a86c9e3a0ce015feb9aca22f
https://gist.github.com/ookkoouu/0c979f8008cf491b4ea67bbd49605576

脚注
  1. これらの処理が何故かcliパッケージのtemplateディレクトリにあるなど、貢献しにくいコードベースも問題。 ↩︎

  2. おま環の可能性あり ↩︎

  3. backgroundからscripting.registerContentScriptsするので余計な権限がついてくる。 ↩︎

  4. 例えばGitHub向けのContents-Scriptを編集すると、GitHubを開いている全てのタブを再読み込みするため、普段使いのブラウザに入れると物凄く不便。 ↩︎

  5. https://github.com/wxt-dev/wxt/discussions/439 ↩︎

Discussion