iimon TECH BLOG

iimonエンジニアが得られた経験や知識を共有して世の中をイイモンにしていくためのブログです

WebpackからViteに移行する

初めに


はじめまして!

株式会社iimonでフロントエンドエンジニアをしている飯田です。

普段は、弊社プロダクトの拡張アプリの開発をしています。

今日はWebpackをViteに移行していきたいと思います!

Viteとは?


1. 概要


フランス語で「速く」という意味の単語から由来するビルドツール。

2022年度のThe State of JavascriptでもランクSとなっており、とても勢いがあるビルドツールとなっています。

2022.stateofjs.com

2. なぜ速いのか


Webpackはアプリケーション全体を隅々までクロールしてビルドする必要があり、取り扱う JavaScriptの量が増えると必然的にビルド時間も増えてしまいます。

一方、ViteはESMを利用し、全体をバンドルするのではなくESMのimportにより、必要な時に必要なファイルだけをコンパイルしてブラウザに送るような仕組みになっています。

また、Vite はesbuild を使用して事前バンドルを行なっています。

esbuild は Go 言語によって開発されており、依存関係の事前バンドルは、従来のビルドツールと比べて10~100倍速くバンドルが可能となっています。

詳しくは下記の公式ドキュメント参照 ja.vitejs.dev

3. 移行に踏み切った理由


これまで弊社の拡張アプリはWebackを用いてモジュール化されたJavascriptをバンドルしていました。

「賃貸版速いもんシリーズ」ではモジュール数も194個になり、取り扱うJavaScript のコード量も増えてきていました。

本プロダクトでは開発サーバーを立てて開発を行なっていませんが、プロダクションビルドでも4分1程度ビルド時間の削減が確認できました。

また、今後の新規プロダクトでは開発サーバーを立てて開発をする予定なのでビルドツールを統一したいという思いからViteの移行に踏み切りました。

Viteへの移行作業


1. 必要なdev dependencyをインストール

npm i vite vite-plugin-checker vite-plugin-static-copy

2. vite.config.tsを作成

vite.config.tsを作成し、ルートディレクトリに配置します。

今回は賃貸版と売買版でバンドルの入力と出力などが違うのでisRentを用いて場合分けを行なっています。

import { defineConfig } from "vite";
import { resolve } from "path";
import { viteStaticCopy } from 'vite-plugin-static-copy';
import checker from 'vite-plugin-checker';

const isDev = process.env.__DEV__ === "true";
const isRent = process.env.__RENT__ === 'true';
const isProduction = !isDev;

const root = resolve(__dirname, "src");
const manifest = resolve(__dirname, "manifest");
const outDir = resolve(__dirname, isRent ? "rent-dist" : "sale-dist");
const publicDir = resolve(__dirname, "public");

export default defineConfig({
  resolve: {
    alias: {
      "@": root
    },
  },
  publicDir,
  plugins: [
    viteStaticCopy({
      targets: [
        {
          src: resolve(manifest, isRent ? "rent-manifest" : 'sale-manifest', "manifest.json"),
          dest: outDir
        }
      ]
    }),
    checker({
      typescript: {
        tsconfigPath: resolve(__dirname, isRent ? "tsconfig.rent.json" : "tsconfig.sale.json"),
      }
    }),
  ],
  build: {
    outDir,
    sourcemap: isDev ? 'inline' : false,
    minify: isProduction,
    reportCompressedSize: isProduction,
    rollupOptions: {
      input: {
        'content_scripts': resolve(root, isRent ? "rent-app" : 'sale-app', "index.ts"),
        'background': resolve(root, "backgrounds", "index.ts"),
      },
      watch: {
        include: ["src/**", "vite.config.ts"],
        exclude: ["node_modules/**"],
      },
      output: {
        entryFileNames: "[name].js",
      },
    },
  },
});

3. package.jsonのscriptコマンドを編集

それぞれのコマンドに賃貸版と売買版を分ける環境変数とdevとprodを分ける環境変数を設定します。

"scripts": {
        .....
    "rent-start": "__DEV__=true __RENT__=true vite build --watch",
    "rent-build": "__RENT__=true vite build",
    "sale-start": "__DEV__=true vite build --watch",
    "sale-build": "vite build"
        .....
  }

4. tsconfig.json編集

ライブラリに型チェックが走るのを防ぐため、"skipLibCheck": trueを追加

{
  "compilerOptions": {
    .....
    "skipLibCheck": true
    .....
  }
}

5. 不要なconfigファイルとdev dependency削除

webpack.config.rent.tswebpack.config.sale.tsを削除

npm uninstall @types/copy-webpack-plugin copy-webpack-plugin webpack webpack-cli

6. .eslintrc.jsonのsettingsを削除

"settings": {
        "import/resolver": "webpack"
 },

7. ビルド

賃貸版速いもんビルドコマンド

npm run rent-build

売買版速いもんビルドコマンド

npm run sale-build

まとめ

  • 20秒程度かかっていたビルド時間を4秒に削減することができた。
  • viteはTSサポートしてはいるが、行うのはトランスパイルだけで型のチェックは行わないため、プラグインを使用する必要がある
  • 静的アセットのコピーが複数ファイルできないため、2ファイル以上コピーする場合はプラグインを使う必要がある

参考資料