Vite 8 でビルドエラー・プラグインが動かない時の5つの原因と対策【v7からの移行 / Rolldown / Oxc / CJS interop】
公開日:2026-10-15/カテゴリ:Vite・JavaScript・フロントエンド・ビルドツール/AnchorUp 技術ブログ
Vite 8 にアップグレードしたら起きる典型的な症状
Vite 8.0.0 は 2026-03-12 にリリースされた。最大の変更は Rolldown と Oxc の統合 で、従来の Rollup + esbuild の組み合わせが置き換えられている。この変更によりビルド速度は大幅に向上するが、移行時に次のような症状が出やすい。
npm run buildが突然TypeErrorで落ちる- 開発サーバーは動くがプロダクションビルドだけ壊れる
- TypeScript のデコレータ(
@Injectable()・@Controller()など)が実行時エラーになる optimizeDeps.esbuildOptions is deprecatedという警告が大量に出るvite.config.tsでrollupOptionsを使うと型エラーになる
結論から言うと: これらはほぼすべて、Rolldown への移行・Oxc への移行・CJS インポートの仕様変更のいずれかが原因だ。以下で原因と対策を順番に説明する。
なお Vite 5→6 の移行で詰まった点は Vite 6 でビルドエラー・プラグインが動かない時の5つの原因と対策 を参照。
なぜ Vite 8 はこれほど変更が大きいのか
答え:Vite 8 は内部バンドラーを Rollup から Rolldown に、JS トランスフォーマーを esbuild から Oxc に全面切り替えしたからだ。
Vite 公式のリリースで “the epic rolldown-vite merge” と表現されたように、Rolldown の統合は Vite 史上最大級の内部変更だった。Rolldown は Rust 製で Rollup API との互換性を持つが、いくつかの挙動が変わっている。
Vite 8 の移行ガイドには「Vite 8 uses Rolldown and Oxc based tools instead of esbuild and Rollup」と明記されており、設定ファイルや依存プラグインへの影響は避けられない。移行は段階的に行う設計になっており、Vite 7 で rolldown-vite プレビューパッケージを先に試す方法も案内されている。
原因1: build.rollupOptions を使っていると設定が効かない・型エラーになる
答え:build.rollupOptions は build.rolldownOptions にリネームされたので書き換える。
Vite 8 では Rollup の代わりに Rolldown がバンドラーになったため、vite.config.ts の build.rollupOptions は build.rolldownOptions にリネームされた。旧名は非推奨として残っているが将来削除される。
// vite.config.ts
import { defineConfig } from 'vite'
export default defineConfig({
build: {
// ❌ Vite 8 では非推奨(将来削除予定)
rollupOptions: {
output: { manualChunks: { vendor: ['react', 'react-dom'] } },
},
// ✅ Vite 8 以降の書き方
rolldownOptions: {
output: { manualChunks: { vendor: ['react', 'react-dom'] } },
},
},
})
worker.rollupOptions も同様に worker.rolldownOptions へ書き換える。
Rolldown の API は Rollup と高い互換性があるため、多くのオプションはそのまま動く。ただし system・amd 出力フォーマットなど一部の機能は Rolldown 非対応なので、移行ガイドを確認すること。
原因2: CJS モジュールの default インポートが TypeError になる
答え:Rolldown 移行により CJS モジュールの default インポート解決ロジックが変わった。一時的に legacy.inconsistentCjsInterop: true で旧動作に戻せる。
Vite 8 に上げてから TypeError: xxx is not a function や TypeError: xxx is not a constructor が突然発生する場合、CJS モジュールの default インポートの変更が原因の可能性が高い。
移行ガイドでは、Rolldown の仕様として「default インポートが module.exports 全体になる条件」が次のように整理されている。
| 条件 | default インポートの解決先 |
|---|---|
インポート元が .mjs または .mts |
module.exports 全体 |
最近の package.json に "type": "module" |
module.exports 全体 |
module.exports.__esModule が true でない |
module.exports 全体 |
| 上記以外 | module.exports.default |
これらの条件に合わない場合は module.exports.default が返るため、__esModule: true を設定していないレガシーな CJS パッケージをインポートしているコードで挙動が変わりうる。
一時的な回避策として次のオプションを追加できる。
// vite.config.ts
export default defineConfig({
legacy: {
inconsistentCjsInterop: true, // ← 旧動作(非推奨・将来削除)
},
})
根本的な修正は当該 CJS パッケージの利用を ESM に切り替えることだ。
原因3: TypeScript デコレータ(@Decorator)がビルドで動かない
答え:Oxc は現時点でネイティブデコレータの変換(lowering)に対応していない。NestJS・TypeORM など DI フレームワークを使う場合は Babel か SWC を追加する。
Vite 8 では esbuild の代わりに Oxc が TypeScript/JavaScript の変換を担当するが、@Injectable() や @Controller() などのデコレータの「変換」は現時点で未対応だ。
移行ガイドには「Currently, the Oxc transformer does not support lowering native decorators as we are waiting for the specification to progress」と明記されており、回避策として Babel と @rolldown/plugin-babel を使う方法が案内されている。
NestJS・TypeORM・tsyringe などデコレータを使うプロジェクトでは次の手順で対処する。
npm install -D @rolldown/plugin-babel @babel/plugin-proposal-decorators
// vite.config.ts
import babel from '@rolldown/plugin-babel'
import { defineConfig } from 'vite'
function decoratorPreset(options: Record<string, unknown>) {
return {
preset: () => ({
plugins: [['@babel/plugin-proposal-decorators', options]],
}),
rolldown: {
filter: { code: '@' }, // @ を含むファイルだけ変換(パフォーマンス最適化)
},
}
}
export default defineConfig({
plugins: [babel({ presets: [decoratorPreset({ version: '2023-11' })] })],
})
SWC を使う場合は移行ガイドに @rollup/plugin-swc + @swc/core を使う例が記載されている。
原因4: esbuild 設定オプションが廃止(optimizeDeps.rolldownOptions に移行)
答え:optimizeDeps.esbuildOptions と esbuild オプションは非推奨になった。それぞれ optimizeDeps.rolldownOptions と oxc オプションに移行する。
Vite 8 では依存関係の最適化(dep optimization)にも Rolldown が使われるようになり、optimizeDeps.esbuildOptions は非推奨になった。現時点では後方互換として自動変換される。主な対応表は次のとおりだ。
| 廃止オプション | 移行先 |
|---|---|
optimizeDeps.esbuildOptions.minify |
optimizeDeps.rolldownOptions.output.minify |
optimizeDeps.esbuildOptions.define |
optimizeDeps.rolldownOptions.transform.define |
optimizeDeps.esbuildOptions.loader |
optimizeDeps.rolldownOptions.moduleTypes |
esbuild.jsxFactory |
oxc.jsx.pragma |
esbuild.jsxFragment |
oxc.jsx.pragmaFrag |
esbuild.jsxImportSource |
oxc.jsx.importSource |
移行の例を示す。
// vite.config.ts
export default defineConfig({
// 廃止(非推奨・将来削除予定)
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
// Vite 8 以降の書き方
oxc: {
jsx: { runtime: 'classic', pragma: 'h', pragmaFrag: 'Fragment' },
},
})
なお esbuild.supported や esbuild.mangleProps などの一部オプションは Oxc に対応する機能がなく、削除されている。これらを使っていた場合は代替手段を検討する必要がある。
原因5: build.target のデフォルトが上がり古いブラウザで動かない
答え:Vite 8 では build.target の 'baseline-widely-available' のデフォルトターゲットが引き上げられた。古いブラウザに対応する場合は明示的にターゲットを指定する。
Vite 8 の移行ガイドには、build.target と 'baseline-widely-available' のデフォルトブラウザが次のように更新されたと明記されている。これは「2026-01-01 時点の Baseline Widely Available フィーチャーセット」に対応する値だ。
| ブラウザ | Vite 7 のデフォルト | Vite 8 のデフォルト |
|---|---|---|
| Chrome | 107 | 111 |
| Edge | 107 | 111 |
| Firefox | 104 | 114 |
| Safari | 16.0 | 16.4 |
ターゲットが引き上がることで生成コードの変換が減り、バンドルサイズが小さくなる利点がある。一方、社内ツールや企業向けシステムで古いブラウザをサポートしている場合はプロダクションビルドが動かなくなることがある。
export default defineConfig({
build: {
// 古いブラウザをサポートする場合は明示的に指定する
target: ['chrome80', 'firefox78', 'safari14'],
},
})
また同一ブラウザの複数バージョンを指定した場合(例: ['chrome80', 'chrome90'])、Vite 8 ではエラーになる。最新バージョンのみに絞って指定すること。
まとめ
Vite 8 で起きるビルドエラー・動作不良の主な原因と対処をまとめる。
| 症状 | 原因 | 対策 |
|---|---|---|
build.rollupOptions が型エラー・効かない |
rollupOptions が rolldownOptions にリネーム |
build.rolldownOptions に書き換える |
CJS モジュールで TypeError |
default インポート解決ロジックの変更 | legacy.inconsistentCjsInterop: true で一時回避 |
| デコレータが動かない(NestJS 等) | Oxc がデコレータ変換を非対応 | @rolldown/plugin-babel を追加 |
esbuildOptions deprecated 警告 |
esbuild オプションが非推奨化 | rolldownOptions / oxc オプションへ移行 |
| 古いブラウザで動かない | build.target デフォルトが引き上げ |
ターゲットを明示的に指定 |
Vite 8 は Rolldown・Oxc の恩恵でビルド時間の大幅短縮が期待できる。一方、CJS 互換の処理やデコレータ周りはまだ成熟途中の部分もあるため、特に NestJS や TypeORM を使うプロジェクトでは移行前に十分な検証時間を確保することを勧める。