盆暗の学習記録

データサイエンス ,エンジニアリング,ビジネスについて日々学んだことの備忘録としていく予定です。初心者であり独学なので内容には誤りが含まれる可能性が大いにあります。

React+TypeScript+ViteでChrome拡張機能を作るときの構成

React + TypeScript + ViteでGoogle Chrome拡張機能を作る方法をメモしておきます。

なお、以下の環境下での話になります。

// 環境
"vite": "^5.2.0",
"typescript": "^5.2.2"

TypeScriptでプロジェクトを作る

まずプロジェクトを作成します(ここはViteのドキュメント通り)

npm create vite@latest myapp -- --template react-ts

@types/chromeを入れる

chrome API(例えばchrome.i18nchrome.tabsなど)を使う場合、chrome オブジェクトの型定義がなくてエラーになるので@typesをインストールします(TSではなくJSで作るなら不要です)。

npm i @types/chrome

manifest.jsonを追加する

viteのデフォルトの設定ではpublic/ディレクトリのファイルはビルド時にトランスパイルされずにdist/に同梱されますので、manifest.jsonpublic/に置きます。

マルチページ構成にする

拡張機能の開発では複数のhtmlを生成したい場合があります。例えばアイコンをクリックしたときに出てくるpopup.htmlやオプションの設定画面options.htmlといった具合です。その場合はviteをマルチページアプリにすると対応できます。

例えばsrcの中にoptionsとpopupという2つのディレクトリをつくり、それぞれにindex.html等を入れるとします。

src
├── options
│   ├── App.tsx       
│   ├── index.html    
│   └── main.tsx      
├── popup
│   ├── App.tsx       
│   ├── index.html    
│   └── main.tsx      
└── vite-env.d.ts 

vitre.config.tsでそれぞれのindex.htmlを参照するように設定を変えます。

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'

const outDir = resolve(__dirname, 'dist')

export default defineConfig({
  plugins: [react()],
  build: {
    outDir: outDir,
    rollupOptions: {
      input: {
        popup: resolve(__dirname, 'src/popup/index.html'),
        option: resolve(__dirname, 'src/options/index.html'),
        background: resolve(__dirname, 'src/background.ts')
      }
    },
  },
})

もしここでCannot find name '__dirname'.ts(2304)のようなエラーが出ている場合はnodeのtypesを入れます。

npm i @types/node

また上記のconfigのもとでは、npm run buildしたときのhtmlファイルは

dist
├── assets
│   ├── background-B9WwJWnc.js
│   ├── client-CYooLA_G.js    
│   ├── option-DptWORB2.js    
│   └── popup-CQLN0kRt.js
└── src
    ├── options
    │   └── index.html
    └── popup
        └── index.html

という感じに生成されるようになります。

そのため、manifest.jsonをdistディレクトリに置いて拡張機能のパッケージにする場合、manifest.json

{
  "manifest_version": 3,
    ...
  "action": {
    "default_popup": "./src/popup/index.html"
  },
  "options_page": "./src/options/index.html"
}

というふうにそれぞれのhtmlを参照するようにしてやればよい、ということになります。

なお、npm run devで起動するdev環境ではそれぞれ

http://localhost:5173/src/options/index.html
http://localhost:5173/src/popup/index.html

というパスで確認できるようになります。

トランスパイル後もファイル名を維持するようにする

もし、バックグラウンドで動かす background.jsのようなものを作りたい場合、デフォルトのviteではビルド時にファイル名が書き換えられてしまうため、src/background.tsbackground-B9WwJWnc.jsのような[name]-[hash].js形式の名前になってしまいます。

そこでvite.config.tsrollupOptions.output.entryFileNames'[name].js'に設定することで名前が維持されるようになります。

rollupOptions: {
  ...
  input: {
    ...
    background: 'src/background.ts' // background.tsをビルドの対象に含める
  }
  output: {
    entryFileNames: '[name].js'  // ビルド後もファイル名を維持するようにする
  }
}

(参考:ビルドオプション | Vite

参考リポジトリ

上記を全部入れたコードを置いておきます

github.com