CI/CDで「なぜかビルドが失敗する」を根絶する。Vite × GitHub Actionsの鉄壁アーキテクチャ
現場のテックリードとして多くのプロジェクトを見てきたが、CI/CDパイプラインにおける「ビルドの揺らぎ」ほど開発者のモチベーションを削ぐものはない。ローカルでは完璧に動くのに、GitHub Actions上では謎のエラーで落ちる。この「再現性の欠如」を解決し、ビルド時間を最短化するための戦略を、アーキテクトの視点から紐解く。
—
1. Node.jsバージョン:暗黙の了解を破壊する
多くのプロジェクトで `actions/setup-node` のバージョン指定を適当に済ませているが、これがトラブルの温床だ。
落とし穴: `.nvmrc` や `package.json` の `engines` フィールドを無視し、CI側で最新バージョンを固定せずに実行すると、依存ライブラリ(特にネイティブモジュール)のコンパイルで確実に死ぬ。
ベストプラクティス:`.nvmrc` による一元管理
GitHub Actionsのワークフローをハードコードするのではなく、プロジェクトルートの `.nvmrc` を参照させる。
.github/workflows/build.yml
steps:
- uses: actions/checkout@v4
- name: Setup Node.js from .nvmrc
uses: actions/setup-node@v4
with:
# 自動で .nvmrc を読み込み、ローカルとCIの実行環境を完全に一致させる
node-version-file: ‘.nvmrc’
cache: ‘npm’ # 後述するキャッシュ戦略の要
—
2. キャッシュ戦略の極意:`node_modules` は「使い捨て」ではない
単にキャッシュするだけでは不十分だ。`npm install` の時間が短縮できなければ、それはCIではない。
隠された真実
GitHub Actionsのキャッシュは「キー」が一致しないと再生成される。`package-lock.json` が更新されるたびに全ダウンロードが走るのを防ぐには、キャッシュのヒット率を最大化するハッシュ戦略が必要だ。
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ~/.npm
# package-lock.jsonのハッシュをキーにするのが鉄則
key: ${{ runner.os }}-node-${{ hashFiles(‘/package-lock.json’) }}
restore-keys: |
${{ runner.os }}-node-
プロの視点: これに加え、`npm ci –prefer-offline –no-audit` を使うこと。`–no-audit` を入れるだけで、大規模プロジェクトではCI時間が数分短縮される。セキュリティは別フローの `snyk` 等で担保すればいい。
—
3. 環境変数の罠:`VITE_` プレフィックスの正体
Viteの最大の特徴であり、最大の混乱の元が「`VITE_` で始まる環境変数以外はクライアントサイドに露出しない」という仕様だ。
実践的解決策:`.env` ファイルのCI注入
CI/CDで環境変数を注入する際、`env` キーに直接書くのはアンチパターン。機密漏洩のリスクが高く、管理も煩雑になる。GitHub Secretsから実行時に生成するスクリプトを挟むのが最も堅牢だ。
ワークフロー内での実行コマンド
- name: Create .env.production
run: |
echo “VITE_API_URL=${{ secrets.API_URL }}” >> .env.production
echo “VITE_BUILD_TIME=$(date)” >> .env.production
—
4. チームの生産性を底上げする「神プラグイン」と設定
Viteのビルド速度をさらに高め、チーム開発のクオリティを均質化するためのツール群を紹介する。
1. `vite-plugin-checker`
ビルド時に型チェックを強制するプラグイン。
- なぜ必要か: TypeScriptのビルドエラーをCIまで持ち込ませないため。`tsc` を別タスクで走らせるより、Viteのビルドプロセスに統合する方がオーバーヘッドが小さい。
2. `vite-plugin-pwa`
オフライン対応やService Workerの管理を自動化する。設定を `vite.config.ts` に集約し、CIで自動的にマニフェストが生成されるようにする。
3. VS Code設定の共有 (`.vscode/settings.json`)
チーム全員が同じフォーマットで開発できるよう、以下の設定をGit管理する。
{
“editor.codeActionsOnSave”: {
“source.fixAll.eslint”: “explicit”
},
“editor.formatOnSave”: true,
“typescript.tsdk”: “node_modules/typescript/lib”
}
※ `typescript.tsdk` をプロジェクト内のnode_modulesに固定することで、IDEの型チェックの揺らぎを完全に排除する。
—
5. アーキテクトからの提言:CI/CDは「静的解析」の入り口に過ぎない
CIでViteビルドが通ったからといって、安心してはいけない。最後に、以下のコマンドをパイプラインの最後尾に必ず追加してほしい。
ビルドサイズが肥大化していないか監視する(重要)
npx vite-bundle-visualizer –output stats.html
`stats.html` をアーティファクトとして保存することで、どのライブラリがビルドサイズを圧迫しているかをチームで可視化できる。
最後に
Viteは速い。しかし、その速さを活かすも殺すもCI/CDの設計次第だ。
「ローカルでは動く」という甘えを捨て、環境をコード化(Infrastructure as Code)し、依存関係のハッシュを管理する。この泥臭い積み重ねこそが、チームの開発スピードを加速させ、エンジニアが「本来の創造的な仕事」に集中するための唯一の道である。
さあ、今すぐあなたのリポジトリの `.github/workflows` を開き、この設定を適用してほしい。ビルドが通る瞬間の、あの静寂な達成感が待っているはずだ。