✌️

【拡張機能】Viteを使ってReactで複数のページを作る(ポップアップとオプション用)

2023/11/15に公開

ReactはSPAを構築するのに便利ですが拡張機能を作るときには不便な点があります。ポップアップとオプションページは独立しているので通常どちらか1つのページでしかReactを使ったフロントエンド開発が行えません。そこでViteを使ってReactで2つの独立したページを作って(MPA)、ポップアップとオプションページの両方でReactを使えるようにしましょう。

以下のツールを使って拡張機能を作っていきます

  • Vite
  • TypeScript
  • React
  • CRXJS

1.Viteで初期化

terminal
npm init vite@latest

このとき初期設定をするための質問をされますので次のようにしてください。

  • Project Name: sample-multi (これは任意)
  • Select a framework: React
  • Select a varieant: TypeScript

2.パッケージをインストール

初期設定で用意されているパッケージをインストールする。

terminal
  cd sample-multi
  npm install

3.crxjs をインストール

terminal
npm i -D  @crxjs/vite-plugin@beta

@crxjs/vite-plugin@betaViteユーザーのChrome拡張用プラグイン。Vite3もVite4も対応がまだなので公式サイトでもベータを使うようにとのこと。

4.vite.config.jsファイルを書き換える

vite.config.js
import { defineConfig } from "vite";
import { crx } from "@crxjs/vite-plugin";
import manifest from "./manifest.json";

export default defineConfig({
  plugins: [crx({ manifest })],
  build: {
    rollupOptions: {
      input: {
        popup: 'src/popup/popup.html',
        options: 'src/options/options.html'
      }
    }
  },
  //  WebSocket connection to 'ws://localhost/' failed:  というエラーの対策
  // https://github.com/crxjs/chrome-extension-tools/issues/746#issuecomment-1647484887
  server: {
    port: 5174,
    strictPort: true,
    hmr: {
      port: 5174,
    },
  },
});

MPA に対応するポイント

ReactをMPAに対応するためのポイントはbuildオプションで設定されている項目です。このオプションの中のinputキーの中でエントリーポイントとなる複数のhtmlファイルを指定できます。今回はポップアップとオプションページの2つのページを作りたいので次の2つを設定しています。

vite.config.ts
// (一部抜粋)
  build: {
    rollupOptions: {
      input: {
        popup: 'src/popup/popup.html',
        options: 'src/options/options.html'
      }
    }
  },

5.manifest.jsonを作成する

manifest.json
{
  "manifest_version": 3,
  "name": "MPA sample",
  "version": "1.0.0",
  "action": { "default_popup": "src/popup/popup.html" },
  "options_page": "src/options/options.html"
}

6.ポップアップページ関連のファイルを作成する。

src直下にpopupディレクトリを作成しポップアップに関連するファイルを作成します。Reactのエントリーポイントとなるhtmlファイルと、ReactでDOMを作成するためのtsxファイルの2つです。通常のReact開発と比較するとsrc/popup/popup.htmlindex.htmlに対応し、src/popup/Popup.tsxApp.tsxmain.tsxに対応しています。
index.htmlに対応するsrc/popup/popup.htmlvite.config.tsで設定しているパスに対応しています。

src/popup/popup.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Popup</title>
</head>
<body>
  <div id="root"></div>
  <script type="module" src="/src/popup/Popup.tsx"></script>
</body>
</html>
src/popup/Popup.tsx
import { createRoot } from "react-dom/client";

function Popup() {
  return (
    <div>
      <h1>Popup Page</h1>
    </div>
  );
}

const rootElement = document.getElementById("root") as HTMLElement;
const root = createRoot(rootElement);
root.render(<Popup />);

7.オプションページ関連のファイルを作成する

ポップアップと同様にsrc直下にoptionsディレクトリを作成しオプションページに関連するファイルを作成します。

src/options/options.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Option</title>
</head>
<body>
  <div id="root"></div>
  <script type="module" src="/src/options/Options.tsx"></script>
</body>
</html>
src/options/Options.tsx
import { createRoot } from "react-dom/client";

function Options() {
  return (
    <div>
      <h1>Options Page</h1>
    </div>
  );
}

const rootElement = document.getElementById("root") as HTMLElement;
const root = createRoot(rootElement);
root.render(<Options />);

8.実行

terminal
npm run dev

このコマンドを実行すると distというフォルダが作成されている。

9.拡張機能を読み込む

  1. chrome://extensions/ に移動
  2. デベロッパーモードがONになっていることを確認
  3. 「パッケージ化されていない拡張機能を読み込む」をクリック
  4. 作成したディレクトリに新しくできたdistディレクトリを選択

10.ピン留めしておく

  1. パズルのピースのアイコンをクリック
  2. 開発している拡張機能名のピンのアイコンをON

開発中は何度もクリックするので常に表示されるようにしておく。

11.起動できたか確認

ここまでの手順がうまくいくとポップアップとオプションページのそれぞれに次のようなページが表示されます。


ポップアップを開いたとき


オプションページを開いたとき

12.不要なファイルを削除する

デフォルトで作成される不要なファイルを削除します。

  • index.html
  • publicディレクトリ
  • src/assetsディレクトリ
  • src/App.css
  • src/App.tsx
  • src/index.css
  • src/main.tsx

@types/chrome

拡張機能開発に必要なAPIのオートコンプリートや型情報が入ったパッケージ。必須。

npm install --save @types/chrome

Discussion