技術 約9分で読めます

Vite 8.0、Rolldownでビルドを最大30倍高速化

Vite 8.0がリリースされた。今回の最大の変更は、開発時に使っていたesbuildと本番ビルドで使っていたRollupを廃し、Rust製バンドラーのRolldownに一本化したことだ。「開発環境と本番環境でバンドル結果が微妙に違う」という長年の悩みがアーキテクチャレベルで解消される。

なぜ2バンドラー構成が問題だったか

Viteはこれまで、開発サーバーでesbuild(高速だがRollupの全プラグインに非対応)、vite buildでRollup(豊富なプラグインエコシステム)を使うハイブリッド構成を採っていた。両者の挙動差がバグの温床になっていて、「開発では動くが本番ビルドで壊れる」ケースが後を絶たなかった。

Rolldownはこの問題を解消するために作られたプロジェクトだ。RustとOXC(Oxidation Compiler)をベースに開発され、Rollupの全プラグインAPIとの互換性を保ちながらesbuild並みの速度を実現している。

パフォーマンス改善の実績

ベンチマーク上では最大30倍高速化が報告されているが、実プロジェクトでの実績の方が説得力がある。

プロジェクト変化
Linear46秒 → 6秒(87%削減)
Ramp57%削減
Mercedes-Benz.io最大38%削減
Beehiiv64%削減

これらは実際のユーザーがRolldownへの移行後に報告した数値だ。プロジェクト規模や依存ライブラリの構成で差はあるが、多くの事例で体感できる改善が出ている。

新機能

Vite Devtools統合 devtoolsオプションでデバッグ・分析ツールが使えるようになった。バンドルの構成やモジュールグラフの可視化など、これまでプラグインで補っていた機能が組み込まれる。

TypeScript paths自動解決 tsconfig.jsonpaths設定を自動でViteのresolve.aliasに変換する機能が内蔵された。resolve.tsconfigPaths: trueで有効化できる。デフォルトは無効。

emitDecoratorMetadata対応 NestJSなどexperimentalDecoratorsemitDecoratorMetadataを使うフレームワークでの外部プラグインが不要になった。

WebAssembly SSRサポート .wasm?initインポートがSSR環境(Node.js上)でも動作するようになった。

ブラウザコンソール転送 server.forwardConsole: trueでブラウザのコンソールログをViteの開発サーバーターミナルに転送できる。マルチウィンドウ構成でのデバッグが楽になる。

@vitejs/plugin-react v6

React向けプラグインも同時にv6へメジャーアップデートした。これまでBabelに依存していたJSX変換をOXCベースに切り替えており、Babelを別途インストールする必要がなくなった。Reactコンパイラを使用する場合はreactCompilerPresetヘルパーで対応する。

インストールサイズ

Vite 8はVite 7と比べて約15MB増加している。内訳はlightningcss(〜10MB)とRolldown本体(〜5MB)だ。lightningcssはCSS最小化の精度向上に寄与しており、単純な肥大化ではない。

Node.js要件

Vite 7と変わらず、Node.js 20.19+ または 22.12+ が必要。

移行方法

公式は段階的な移行を推奨している。

  1. 現在Vite 7を使っているプロジェクトで rolldown-vite パッケージへの移行をテストする
  2. 問題がなければVite 8へアップグレードする

互換性レイヤーが用意されているため、多くのプロジェクトは設定変更なしにアップグレードできる。ただしesbuildに依存した独自設定やプラグインは動作確認が必要だ。

npm install vite@8 --save-dev

Rolldownはrollup互換APIを実装しているため、Rollupプラグインはほぼそのまま動作する。esbuildプラグイン(optimizeDeps.esbuildOptions経由など)は代替が必要なケースがある。

今後の展開

次のフェーズとして Full Bundle Mode が計画されている。開発時もバンドルを行うモードで、起動速度の3倍高速化が見込まれている。現在の開発サーバーはファイルをモジュールごとに個別配信するが、大規模プロジェクトではこれが数千リクエストに膨れて遅くなる問題があった。Full Bundle Modeはこれを解決する。

他にも生のASTへのアクセス機能やネイティブMagicString変換も開発中とされており、ツールチェーン全体をRustに引き寄せていく方向性は変わっていない。

Rolldownの内部アーキテクチャ

RolldownはRust製とだけ言われがちだが、中身はかなり作り込まれている。バンドル処理は Scan → Link → Generate の3段パイプラインで構成される。

graph TD
    A[エントリーポイント] --> B[Scan Stage]
    B --> C[oxc_parserでAST生成]
    C --> D[AstScannerで<br/>import/export解析]
    D --> E[プラグインhook実行<br/>resolveId, load, transform]
    E --> F[Link Stage]
    F --> G[シンボル解決<br/>bind_imports_and_exports]
    G --> H[Tree Shaking<br/>include_statements]
    H --> I[CJS互換ラッパー注入<br/>wrap_modules]
    I --> J[Generate Stage]
    J --> K[チャンク生成<br/>generate_chunks]
    K --> L[Scope Hoisting<br/>AST最適化]
    L --> M[出力レンダリング<br/>コンテンツハッシュ付与]

Scan Stageでは、ModuleLoaderがtokioランタイムで並列にモジュールを読み込む。各モジュールはoxc_parserでASTに変換され、AstScannerがimport/exportの依存関係を解析する。プラグインのresolveIdloadtransformフックもこの段階で実行される。

Link Stageでは、Scan Stageで収集したすべてのモジュール間のシンボル参照を解決する。bind_imports_and_exports()がどのexportがどのimportを満たすかを特定し、include_statements()がTree Shakingを実行して到達可能なコードだけをマークする。CommonJSモジュールにはwrap_modules()でランタイムラッパーが注入される。

Generate Stageでは、generate_chunks()でモジュールをチャンクに分割し、ScopeHoistingFinalizerがAST最適化(変数の巻き上げ、シンボルのリネーム、不要なラッパー関数の除去)を行う。最終的にコンテンツハッシュが付与されてファイルに出力される。

並列化もレイヤーごとに使い分けている。モジュールロードはtokio(非同期I/O)、チャンクレンダリングはrayon(CPUバウンド並列)、プラグイン実行はワーカースレッドと、処理特性に応じたランタイムを選択している。

OXCエコシステムとの統合

RolldownはOXC(Oxc v0.115.0)に深く依存している。パーサー、トランスフォーマー、ミニファイア、リゾルバー、ソースマップ生成のすべてがOXCコンポーネントで構成される。

コンポーネント役割
oxc_parserソースコードからAST生成
oxc_transformerコード変換(JSX、TypeScript等)
oxc_minifier出力の圧縮
oxc_resolver v11.17.1モジュール解決(yarn PnP対応)
oxc_sourcemap v6.xソースマップ管理

NAPI-RSバインディング経由でJavaScript側にも公開されており、Rollupプラグインとの互換レイヤーもこの仕組みで実現している。ランタイムヘルパー(__commonJSMin__toESMasyncToGenerator等)は文字列定数として埋め込まれ、モジュールラッピング時に注入される。

破壊的変更の詳細

公式の移行ガイドから、実際にハマりやすいポイントを抜粋する。

設定オプションの変更

esbuildとRollupに関連するオプションは自動変換されるが、非推奨になっている。

旧オプション新オプション備考
optimizeDeps.esbuildOptionsoptimizeDeps.rolldownOptions自動変換あり、将来削除
esbuildoxcJSX設定の書式が異なる
build.rollupOptionsbuild.rolldownOptions自動変換あり、将来削除
build.minify: 'esbuild'build.minify: 'oxc'esbuildも一応使える
build.cssMinifyデフォルトがLightning CSSにesbuildに戻すことも可能

JSX設定は書式が変わっているので注意が必要だ。

// Vite 7
esbuild: {
  jsx: 'automatic',
  define: { 'process.env.NODE_ENV': '"production"' }
}

// Vite 8
oxc: {
  jsx: { runtime: 'automatic' },
  define: { 'process.env.NODE_ENV': '"production"' }
}

削除された機能

  • output.manualChunksのオブジェクト形式 → codeSplittingオプションに移行
  • esbuild.supported → OXCに相当オプションなし
  • resolve.alias[].customResolverresolveIdフックを持つカスタムプラグインで代替
  • SystemJS / AMDの出力フォーマット → サポート終了
  • shouldTransformCachedModule / resolveImportMeta 等のプラグインフック → 削除

CommonJS互換性の変化

最もハマりやすいのがCJS interopの挙動変更だ。Rolldownではdefault importの扱いが開発・本番で統一された結果、既存のCJSモジュールのimportが壊れるケースがある。

// 以前は動いていたがVite 8で壊れる可能性がある
import something from 'cjs-package';
// → somethingがundefinedになる

// 一時的な回避策
// vite.config.ts
export default defineConfig({
  legacy: {
    inconsistentCjsInterop: true  // 非推奨、将来削除
  }
});

根本的にはパッケージ側がESMに対応するのが正しいが、それまでの暫定措置としてlegacy.inconsistentCjsInteropが用意されている。

ブラウザターゲットの引き上げ

最低サポートバージョンが更新された。

ブラウザVite 7Vite 8
Chrome107111
Edge107111
Firefox104114
Safari16.016.4

2026年1月時点のBaseline Widely Availableに合わせた変更で、大半のユーザーには影響ないが、古いブラウザサポートが必要なプロジェクトは確認が必要だ。

プラグイン作者向けの変更

loadtransformフックで非JavaScriptコンテンツをJavaScriptに変換する場合、moduleType: 'js'の明示が必要になった。またbuild()関数のエラーハンドリングが変わり、BundleErrorでラップされたerrors配列が返されるようになっている。

VoidZeroとVite+の文脈

Vite 8のリリースは、より大きな動きの一部だ。

Vite作者のEvan You(Vue.js作者でもある)が設立したVoidZeroは、Accelリードで4.6Mのシード、続いて4.6Mのシード、続いて12.5MのシリーズAを調達している。Vite・Vitest・Rolldown・OXCのコア開発者を集めた企業で、JavaScriptツールチェーンのRust化を事業として推進している。

Vite 8リリースの翌日(3月13日)、VoidZeroは Vite+ をMITライセンスでオープンソース公開した。Vite+は以下のツールを統合した単一のツールチェーンだ。

ツール役割
Vite 8開発サーバー・ビルド
Vitest 4.1テスト
Oxlint 1.52リンター
Oxfmt(ベータ)フォーマッター
Rolldownバンドラー
tsdownライブラリバンドル
Vite Taskタスクランナー

vpというCLIコマンドでvp devvp buildvp testvp checkと統一的に操作できる。Node.jsバージョンとパッケージマネージャーの自動管理も含まれる。

webpack → Vite → Vite+という流れで見ると、フロントエンドのビルドツールチェーンがESLint・Prettier・Jest・webpackといった個別ツールの組み合わせから、Rustベースの統合ツールチェーンへ移行しつつあることがわかる。RomeやBiomeが目指していた方向を、Viteのエコシステム規模(週間6500万DL)で実現しようとしている。

vinextが示すVite 8の実力

このブログでも取り上げたvinext(CloudflareによるNext.jsのVite上への再実装)は、Vite 8の恩恵を直接受けている。

vinextのベンチマークでは、同じ33ルートのApp Routerアプリケーションで以下の結果が出ている。

  • Vite 7(Rollup): 4.64秒
  • Vite 8(Rolldown): 1.67秒(2.8倍速

Vite 7→8の差だけで2.8倍の高速化が得られている。Next.js 16.1.6(Turbopack)の7.38秒と比較すると4.4倍速だ。Rolldownへの一本化が実プロダクションでどれだけ効くかを示す好例と言える。

Astro 6との関係

Vite 8リリースの3日前(3月10日)にAstro 6.0がリリースされている。Astro 6はVite 7ベースで、開発サーバがViteのEnvironment APIを使って完全に作り直された。開発時に本番と同じランタイムでコードを実行できるようになり、Cloudflare WorkersのバインディングにローカルからアクセスできるなどDX面の改善が大きい。

Astro 6はVite 7だが、次のメジャーであるAstro 7でVite 8に移行する可能性が高い。そうなると、Vite 8のRolldown統合に加えてAstro側で実験的に導入されたRustコンパイラ(@astrojs/compiler-rs)が組み合わさることになる。Go製だった.astroコンパイラがRust製に置き換わり、バンドラーもRust製のRolldownになるので、ビルドパイプライン全体がRustに統一される方向だ。

現時点でAstro 6に移行するなら、Vite 7の設定のままで問題ない。ただしViteの設定を直接カスタマイズしている場合、Vite 8でesbuildoxcbuild.rollupOptionsbuild.rolldownOptionsへのオプション変更が入るため、Astro 7への移行時に設定の書き換えが必要になる可能性がある。Astro側で吸収してくれるかどうかは今後のリリースノート次第。