こんにちは。テックリードの私だ。
日々のフロントエンド開発において、Viteの爆速なHMR(Hot Module Replacement)やESMベースのビルドスピードには、誰もが恩恵を受けていることだろう。だが、プロジェクトが成長し、KubernetesやECSといったコンテナオーケストレーション環境でのデプロイパイプラインを構築するフェーズに突入した瞬間、誰もがこの「呪い」に直面する。
「`import.meta.env` は、ビルド時にコードへハードコードされる」
この仕様の何が問題か。CI/CDパイプラインにおいて、ステージング環境用と本番環境用のビルド成果物(`dist`ディレクトリ)を別々にビルドしていればまだいい。しかし、クラウドネイティブの鉄則は「Build Once, Deploy Anywhere(一度ビルドしたコンテナを、全環境で使い回す)」だ。
環境変数を変えるたびに数分をかけてDockerイメージを再ビルドし、レジストリにプッシュし直す――そんな非効率なワークフローに開発チームの時間をドブに捨てさせていないか?
今回は、Viteのビルド機構の裏をかき、「ビルド後の成果物に対して、コンテナ起動時(Runtime)に環境変数を動的インジェクションする」という、実務で即座に使えるアーキテクチャの裏技を完全解説しよう。
—
1. なぜ「ビルド時環境変数」のままだと破綻するのか
通常のViteアプリケーションでは、`.env.production`などに記述した変数は、`vite build`の実行瞬間にコード内のプレースホルダーへ直接埋め込まれる(あるいは文字列置換される)。
// ビルド後のJSファイル内(イメージ)
console.log(“https://api.staging.example.com”); // ← ここが固定されてしまう
これでは、同じDockerイメージを `staging` クラスターから `production` クラスターへプロモーションした際、APIの向き先を切り替えることができない。環境変数ごとにイメージを作るということは、ビルドのたびにトランスパイルとバンドル処理のコストが発生し、CIのランニングコストを圧迫するだけでなく、「本当に同じバイナリ(成果物)が本番にいるのか」というトレーサビリティの担保すら危うくなる。
この制約を突破するには、「ビルド時はプレースホルダーを置いておき、コンテナの起動スクリプト(エントリーポイント)で実際の環境変数に書き換える」というランタイム・インジェクションの思想が必要不可欠となる。
—
2. アーキテクチャの全体像:Runtime Injectionの仕組み
今回構築する仕組みの流れはこうだ。
1. Viteの設定: ビルド時に変数領域を空っぽ、あるいはグローバル変数への参照にしておく。
2. HTMLインジェクション: `index.html` の `