LoginSignup
13
5

More than 1 year has passed since last update.

typescript + vite + reactを使ったChrome拡張機能の土台を作って検証してみた

Posted at

Chrome拡張機能をtypeScript + webpack + create react appで開発していますが、ビルドが遅いので、開発でストレスになっていた。

一方、viteがビルド速度が早いと巷で話題になっているので、まずは土台を作成し、本当に早いのか検証してみました。

使用環境

会社で使用しているMacなので、かなりハイエンドのものを使用していますが、ここまでのスペックじゃなくても問題なく利用はできると思います。

  • MacBook Pro (16-inch, 2019)
    • OS: MacOSX 10.15.7
    • CPU: 2.4 GHz 8コアIntel Core i9
    • メモリ:64 GB 2667 MHz DDR4
  • node v12.13.1

ベースで使用したもの

react-tsというテンプレートから作成しています。

yarn create @vitejs/app --template react-ts .

やったことまとめ

作成したものは、以下においてありますが、やった内容をまとめておきます。

package.jsonの変更

以下の変更を行っています

  • yarn build時に、tsc--noEmitオプションを追加(型検査のみで十分なので)
  • パッケージを追加
    • chrome関係のものをtypescriptで利用するのに必要
    • @types/chrome
    • ビルドで必要
    • rollup-plugin-copy
    • @types/node
{
  "name": "vite_for_chrome_extension",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview"
  },
  "dependencies": {
    "react": "^17.0.0",
    "react-dom": "^17.0.0"
  },
  "devDependencies": {
    "rollup-plugin-copy": "3.4.0",
    "@types/node": "16.4.0",
    "@types/chrome": "0.0.148",
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "@vitejs/plugin-react-refresh": "^1.3.1",
    "typescript": "^4.3.2",
    "vite": "^2.4.3"
  }
}

vite.config.tsを変更

主に、やっていることは以下の通り

  • main.jsやbackgroundスクリプトであるbackground.jsをビルドし、dist直下へ出力
  • publicファイルをdist/publicへコピー
  • manifest.jsondistへコピー
  • index.htmlなどchrome拡張機能で利用するhtmlファイルをdistへコピー
import { defineConfig } from 'vite'
import reactRefresh from '@vitejs/plugin-react-refresh'
import copy from 'rollup-plugin-copy'

const { resolve } = require('path')

// https://vitejs.dev/config/
export default defineConfig({
  build: {
    // src上にあるts, tsxファイルを一つのjsにまとめて、dist配下へ配置
    // ポップアップスクリプト本体であるmain.jsと、バックアップスクリプトbackground.jsのビルド設定を含めている
    // コンテンツスクリプトは含めていないが、必要であればここに追加していけばよい
    rollupOptions: {
      input: {
        main: resolve(__dirname, 'src/main/main.tsx'),
        background: resolve(__dirname, 'src/background/background.ts'),
      },
      output: {
        entryFileNames: '[name].js',
      },
    },
  },

  plugins: [
    reactRefresh(),
    copy({
      verbose: true,
      hook: 'writeBundle',
      targets: [
        // publicファイル(アイコンなど) を dist/public へコピー
        {
          src: 'public/*',
          dest: 'dist/public'
        },
        // manifest.json を distへコピー
        {
          src: 'manifest.json',
          dest: 'dist',
        },
        // index.htmlなどchrome extensionで使用するhtmlファイルをdistへコピー
        {
          src: '*.html',
          dest: 'dist'
        }
      ],
    }),
  ]
})

src配下にあるコンポーネントファイルをsrc/mainへ移動

vite-env.d.tsを除くすべてのファイルをsrc/mainへ移動させた。コンポーネント関係なので、分離してわかりやすくしたかっただけに過ぎません。

background.tsを作成

background scriptを作成しておきます。とりあえず土台を作成したかったので、何もいれていません。

export {}

publicフォルダを作成

ここにはとりあえず、拡張機能で利用するファビコンやロゴなどを入れています

index.htmlを作成

拡張機能アイコンを押したときに、呼び出すindex.htmlをルート直下で作成しています。
ここでmain.jsを呼び出すようにしています。
なお、main.jsのパスはビルド時にルート直下で作成されることを想定しているので、以下のようにしています。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="favicon.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="main.js"></script>
  </body>
</html>

manifest.jsonを作成

chrome 拡張機能で必須なファイル manifest.json を作成しておきます。ロゴやバックグラウンドスクリプトbackground.js、ポップアップで表示させるファイルindex.htmlを指定しています。
コンテンツスクリプトは今回含まれていませんが、vite.config.jsでビルドできるようにすればすぐに対応できるようにしています。

{
  "manifest_version": 3,
  "name": "vite_for_chrome_extension",
  "version": "0.0.0.0",
  "action": {
    "name": "test",
    "default_popup":"index.html"
  },
  "web_accessible_resources" : [{
    "resources": [
      "index.html", "main.js"
    ],
    "matches": ["http://*/*", "https://*/*", "*://*/*"],
    "extension_ids": []
  }],
  "icons": {
    "32": "public/logo192.png",
    "64": "public/logo192.png",
    "128": "public/logo192.png",
    "512": "public/logo192.png"
  },
  "background" : {
    "service_worker" : "./background.js"
  },
  "content_scripts" : [],
  "permissions": [
    "tabs",
    "webNavigation",
    "clipboardWrite",
    "clipboardRead",
    "storage",
    "unlimitedStorage",
    "alarms",
    "scripting"
  ],
  "host_permissions" : [
    "http://*/*",
    "https://*/*",
    "*://*/*"
  ]
}

ここまで作成すれば、あとは、yarn buildで拡張機能がビルドできるようになります。

結局早くビルドできるのか?

従来のものと比較して、本当に早くビルドできるのか試してみました。

従来のプロジェクトについては、比較のためにこちらを拝借しました

実際にビルドしてみてかかった時間は以下のとおりです。

  • vite: 平均 6.46s (6.81s, 6.37s, 6.21s)
  • create-react-app: 平均 5.32s (7.22s, 4.35s, 4.38s)

なんと、viteのほうが遅いという残念な結果に。。。

なぜ遅いのか調べてみたところ、vite buildの前にtscを実行していてこれがビルド時間に足かせになっているようです(実際これを省略してみたところ、平均 2.56s (2.82s, 2.46s, 2.40s)で済み、問題なくビルドできているようです)。

ではなぜtscをいれているのかというと、公式マニュアルによると、viteもといビルドに使っているesbuildでは、あくまでトランスパイルしか行わず、型チェックは行っていないからだそうです。なので、型チェックはtscでカバーしているようです。

一方、拡張機能では毎回ビルドすることになるので、当然型チェックは必要です。なので、tscは外せられないと考えています。

規模が大きくなるとどうなるかも検証

何も入れていない状態だと、あまり意味がないのかなと思い、規模が大きくなったら本領が発揮されるという話もあるので、検証してみました。

たとえば、React Material UI ( https://material-ui.com/ ) という比較的重いモジュールを含めてみることにしました。バージョンは4.12.2とします。

その結果がこちらです。

  • vite: 平均 10.64s (10.66s, 10.53s, 10.74s)
  • vite(tscを除外): 平均 4.46s (4.60s, 4.36s, 4.43s)
  • create-react-app: 平均 6.82s (6.77s, 6.87s, 6.81s)

これでもviteのほうが遅い結果に。。。tscを除外したら早いので、ここでもtscが足かせになっているようでした。

他にモジュールをいれてみたら結果は変わるかもしれませんが、キリがなさそうなので、ここで打ち切ることにしました。

まとめ

viteで土台を作ってみたら早くなるのかなと検証していましたが、従来のものと比較して早くビルドされるわけではありませんでした

tscがビルド時間の足かせになっていることはわかったものの、型チェックは必要なので外せません。なので、chrome拡張機能で採用するにはまだまだ課題がある印象でした。

今後改善してもっと早くなることがわかれば、またトライしてみたいです。

13
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
5