Vite で複数モードのビルドを JavaScript から実行する

Vite の JavaScript API を使用して複数モードで連続ビルドする方法のメモです。

やりたいこと

マルチテナントアプリでリポジトリは単一なのですが、フロントリソースがテナント毎に分けてホスティングする必要があり、かつ各テナント毎の設定を .env ファイルで定義している場合、テナント毎にビルドとデプロイを実施する必要があります。

このようなアプリを AWS CodePipeline で単一パイプラインでビルド & デプロイする場合、buildspec.yml にシェルスクリプトでビルド内容を記載していくことになりますがシェルスクリプトで書くのがつらかったので JavaScript で書いて npm run build で実行できるようにできないかと考えました。

アプリは Vite ベースで開発していたので、JavaScript API | Vite を調べていたら build API があったので出来そうだなと思い、試してみました。

環境

OS
Microsoft Windows 11 22H2
Node.js:
16.14.0
vite
4.3.9

準備

新規 Vite プロジェクト作成

  1. シンプルにするため、はじめに | Vite に沿って Vanilla な Vite プロジェクトを新規で作成します。

    npm create vite@latest
    √ Project name: ... vitebuild
    √ Select a framework: » Vanilla
    √ Select a variant: » JavaScript
    
    Scaffolding project in C:\Users\xxxxxx\vitebuild...
    
    Done. Now run:
    
      cd vitebuild
      npm install
      npm run dev
  2. 依存関係のインストール

cd vitebuild
npm install

環境変数の設定

Vite の環境変数については こちらの記事 で詳しく説明していますのでよかったらご覧ください。

  1. .env ファイルを複数使用するのでプロジェクトルートではなく、個別フォルダに配置したいため、.env ファイルの配置場所を vite.config.js に定義します。

    import { defineConfig } from 'vite'
    
    export default defineConfig({
      envDir: './env',
    });
  2. ./env/.env.mode1 ファイルを作成し、以下の通り環境変数を定義します。

    VITE_MODE=mode1
  3. ./env/.env.mode2 ファイルを作成し、以下の通り環境変数を定義します。

    VITE_MODE=mode2

アプリケーションにテスト用環境依存コードを追加

main.js に以下の通り環境変数 VITE_MODE を出力する箇所を追加します。

document.querySelector('#app').innerHTML = `
  <h1>This is ${ import.meta.env.VITE_MODE }</h1> <!--追加-->
  <div>
    :
  </div>
`

以上で準備は完了です。

ビルドスクリプトの作成

JavaScript API | Vite に沿ってビルドスクリプトを build.js として書いていきます。

build メソッドの引数ですが、上記公式ドキュメント上は InlineConfig という型で定義されています。InlineConfig 自体は同ページに定義されていますが、

InlineConfig インタフェイスは、追加のプロパティで UserConfig を拡張します ― JavaScript API | Vite

とあるものの、肝心の UserConfig の定義がわかりません。ただ実際のソース ./node_modules/vite/dist/node/cli.js を見たところ、Vite の設定 | Vite と同一のように見えたので、こちらに沿ってオプションを簡単に設定しています。

  • mode : ビルドモードの指定です。ここで指定したモードに一致する .env ファイルが適用されます。
  • build.outDir : ビルドされたファイルの出力先です。モード毎にそれぞれ出力されるようにしています。
import { build } from "vite";

await Promise.all(["mode1", "mode2"].map((mode) => build({
  mode: mode,
  build: {
    outDir: `./${mode}`,
  }
})));

実行

以下のように実行します。

node ./build.js

また、package.jsonscripts に以下のように定義して、npm run build で実行することも可能です。

"scripts": {
  "dev": "vite",
  "build": "node ./build.js",
  "preview": "vite preview"
}

実行するとプロジェクトルートに mode1mode2 のディレクトリが出来ていて、それぞれビルド後のコードが出力されています。

以下のように outDir オプションに ./mode1 あるいは ./mode2 を渡して preview を実行し、ブラウザでアクセスしてみます。

npm run preview -- --outDir ./mode1

./mode1 の場合は、mode1 とページ上に表示されており、 mode1 の preview 表示

./mode2 の場合は、mode2 とページ上に表示され、モード毎にビルドされていることがわかります。 mode2 の preview 表示

なお、vite previewoutDir オプションでホストするディレクトリを指定できますが、npm run 経由でオプションを渡す場合は -- で区切る必要があります。

Any positional arguments are passed to the specified script. Use – to pass –prefixed flags and options which would otherwise be parsed by npm. ― npm-run-script | npm Docs

あとがき

Vite の JavaScript API を使用して、使用する環境変数を変えながらビルドできました。あまりユースケースは多くないかもしれませんが、便利でした。本番利用時はビルドエラー発生時にどのビルドでエラーが発生したか等のトレース可能なロギング等必要だと思いますが、ミニマムな実装の紹介でした。