vite-mastery

7.1 · difficulty 2/4 · 16 min read

Rolldown's Role in the Vite 8 Build

How Vite build uses Rolldown, how to configure rolldownOptions, how rollupOptions migration works, and how minification, manifests, and chunk caching fit together.

Vite 8.1Stable

vite build Is Still a Vite Command

Vite 8 uses Rolldown for production bundling, but vite build is not just raw Rolldown. Vite still:

  1. loads and merges vite.config.ts
  2. loads mode and .env files
  3. creates the plugin container and Vite core plugins
  4. turns HTML, CSS, assets, workers, and WASM into bundler inputs
  5. calls Rolldown to emit chunks and assets
  6. emits Vite-level outputs such as manifests and license files

Think in two layers:

LayerConfig entryExamples
Vite build semanticsbuild.*outDir, target, manifest, minify
Bundler optionsbuild.rolldownOptionsinput, external, output, Rolldown plugins

Use Vite's high-level options first. Drop into build.rolldownOptions only when controlling bundler behavior directly.

rolldownOptions Is the Vite 8 Path

ts
import { resolve } from "node:path"
import { defineConfig } from "vite"

export default defineConfig({
  build: {
    sourcemap: true,
    manifest: true,
    rolldownOptions: {
      input: {
        index: resolve("index.html"),
        admin: resolve("admin/index.html"),
      },
      external: ["some-cdn-lib"],
      output: {
        entryFileNames: "assets/[name]-[hash].js",
        chunkFileNames: "assets/[name]-[hash].js",
        assetFileNames: "assets/[name]-[hash][extname]",
      },
    },
  },
})

build.rollupOptions still exists as an alias, but it is deprecated in current Vite 8 config docs. New code should use build.rolldownOptions.

Key Build Options

OptionDefault / meaningChange it when
build.outDir"dist"deployment expects another directory
build.assetsDir"assets"static paths are constrained
build.targetbaseline-widely-availablelower browser target required
build.sourcemapfalseproduction debugging or error tracking
build.manifestfalsebackend templates need asset mapping
build.ssrManifestfalseSSR needs preload/style info
build.minifyOxc for client, false for SSRdebugging or terser compatibility
build.cssMinifyLightning CSSCSS minification target differs
build.chunkImportMapexperimental, falseoptimizing chunk cache invalidation

Target

The default production target is baseline-widely-available. Lowering the target performs syntax transforms; it does not automatically polyfill every runtime API.

ts
export default defineConfig({
  build: {
    target: "es2020",
  },
})

Minification

Vite 8 client builds default to Oxc minifier; SSR builds default to no minification:

ts
export default defineConfig({
  build: {
    minify: "oxc",
  },
})

build.minify: "esbuild" is deprecated and should only be used as a temporary migration choice when you have verified a specific need.

For debugging:

ts
export default defineConfig({
  build: {
    minify: false,
    sourcemap: true,
  },
})

CSS minification is separate:

ts
export default defineConfig({
  build: {
    cssMinify: "lightningcss",
  },
})

Disable JS and CSS minification separately when diagnosing output bugs.

Multi-Page Builds

ts
import { resolve } from "node:path"
import { defineConfig } from "vite"

export default defineConfig({
  build: {
    rolldownOptions: {
      input: {
        index: resolve("index.html"),
        dashboard: resolve("dashboard.html"),
        settings: resolve("settings.html"),
      },
    },
  },
})

Output:

text
dist/
  index.html
  dashboard.html
  settings.html
  assets/
    index-HASH.js
    dashboard-HASH.js
    settings-HASH.js
    shared-HASH.js

Validate every entry with pnpm preview or a real static server, especially when deploying under a sub-path.

Backend Entry Builds

When HTML is rendered by a backend, build JS/TS entries and enable a manifest:

ts
export default defineConfig({
  build: {
    manifest: true,
    rolldownOptions: {
      input: {
        app: "src/main.ts",
        admin: "src/admin.ts",
      },
    },
  },
})

If modulepreload polyfill is needed, import it in the custom entry:

ts
import "vite/modulepreload-polyfill"

See 7.8 · Backend Integration.

Chunk Import Map

build.chunkImportMap is experimental and optimizes chunk cache invalidation:

ts
export default defineConfig({
  build: {
    chunkImportMap: true,
  },
})

It solves cache cascading caused by hashed chunk URLs. It is not a code splitting strategy.

Migration Checklist

  1. Write new config under build.rolldownOptions; keep rollupOptions only temporarily.
  2. Review build.minify: "esbuild" and remove it unless required.
  3. Enable build.manifest if a backend reads build output.
  4. Open every multi-page entry after build.
  5. Align base with the deployment path.
  6. Clearly mark experimental build options in project docs.

Check Yourself

  1. Why is vite build not simply raw Rolldown?
  2. How should build.rollupOptions be migrated in Vite 8?
  3. What do build.minify: false and build.cssMinify: false help debug?
  4. Why do backend integrations usually need build.manifest?
ts
// Configure a multi-entry build:
// - index.html, dashboard.html, settings.html
// - sourcemap enabled
// - manifest enabled
// - output JS as assets/[name]-[hash].js
// - do not use deprecated rollupOptions