Software

Vite 8 upgrade: one build error and one silent console leak

By · Sun Oct 18 2026 · 10 min read · 0 views

View as a Web Story

Software#javascript#migration#vite#vite 8#rolldown

Vite logo with the warning that console.log ships after the Vite 8 upgrade

Upgrading from Vite 7 to Vite 8 can end in a loud failure or a quiet one. The loud one is a build that stops with TypeError: manualChunks is not a function. The quiet one is worse: esbuild: { drop: ['console'] } stops working, the build succeeds, and every console.log ships to your users. We upgraded a real project from Vite 7.3.7 to 8.3.4 and tested each config key one at a time. This guide lists what happens to each key, the exact fix, and a three-line check that catches the silent leak in CI.

What changed in Vite 8?

Vite 8 is the release of the Vite build tool that replaces esbuild and Rollup with Rolldown and Oxc. The Vite 8 migration guide says it "uses Rolldown and Oxc based tools instead of esbuild and Rollup." Rolldown is a bundler written in Rust that replaces Rollup. Oxc is a Rust toolchain that now handles JavaScript transforms and minification. Vite is a front-end build tool that serves code during development and bundles it for production.

That swap explains every config change in this post. Options that targeted esbuild or Rollup now target Rolldown or Oxc. Some keep working through a compatibility layer, some warn, and a few do nothing.

The latest release on npm is Vite 8.3.4, and its engines field requires Node ^20.19.0 || >=22.12.0. Check that first. On Node 20.18 or older the install itself is the problem, not your config.

What breaks first when I upgrade?

The object form of manualChunks breaks the build. The migration guide states it directly: "The object form output.manualChunks option is not supported anymore. The function form output.manualChunks is deprecated."

Our test setup was a small React app on Vite 7.3.7 with @vitejs/plugin-react 5.2.0 and Node 22.23.3. We upgraded with npm i -D vite@8.3.4 and ran vite build with the unchanged config. The relevant lines were:

build: {
  rollupOptions: {
    output: { manualChunks: { react: ["react", "react-dom"] } },
  },
},

Vite 8.3.4 printed "Build failed" and stopped with the message below.

Warning: Invalid output options (1 issue found)
- For the "manualChunks". Invalid type: Expected Function but received Object.
TypeError: manualChunks is not a function

The fix that worked in our lab is the function form:

build: {
  rollupOptions: {
    output: {
      manualChunks(id) {
        if (id.includes("node_modules/react")) return "react";
      },
    },
  },
},

The build then produced a separate react chunk of 220 kB, as before. The guide calls the function form deprecated, so treat it as a bridge. The longer-term replacement is Rolldown's codeSplitting option, which the guide links to.

What is the silent console leak?

The silent leak is esbuild.drop doing nothing. On Vite 7, esbuild: { drop: ['console'] } removed console.log calls from production bundles. On Vite 8.3.4 the option is ignored, because esbuild no longer minifies your code.

Advertisement

We tested it with a marker. A source file called console.log("DEBUG-MARKER"), and we counted the marker in the built bundle.

Chart showing the DEBUG-MARKER console.log removed on Vite 7, shipped on Vite 8 with the old key, and removed with the rolldown minify option

Config Vite Marker found in bundle Warning printed
esbuild: { drop: ['console'] } 7.3.7 0 none
esbuild: { drop: ['console'] }, no plugins 8.3.4 1 none
esbuild: { drop: ['console'] } with @vitejs/plugin-react 8.3.4 1 "Both esbuild and oxc options were set"
build.rolldownOptions.output.minify.compress.dropConsole: true 8.3.4 0 none

The bottom line: with no framework plugin, Vite 8.3.4 built the project without a single warning and kept the log call. A clean CI log proves nothing here. With the React plugin you get one line, Both esbuild and oxc options were set. oxc options will be used and esbuild options will be ignored, which is easy to miss in a long build.

The migration guide documents the replacement: if you used esbuild.drop, "you can now use build.rolldownOptions.output.minify.compress.drop* options." The working form in our lab was:

export default defineConfig({
  build: {
    rolldownOptions: {
      output: { minify: { compress: { dropConsole: true } } },
    },
  },
});

One more trap sits right next to it. We first tried the snake_case spelling drop_console: true, which is how many minifiers name it. Vite 8.3.4 printed Invalid output options ... Expected (boolean | Object) but received Object and the marker stayed in the bundle. Use dropConsole.

How do I catch the leak in CI?

Add a post-build assertion. It takes three lines and does not depend on any warning appearing. Pick a string that only your debug logging contains, or search for console.log( if you want a strict rule.

vite build
if grep -rq "console.log" dist; then echo "console.log shipped"; exit 1; fi

Third-party libraries often contain their own console.log strings, so a strict grep can fail on code you do not own. For a real project, log a marker such as [debug] in your own code and grep for that. The check then fails only when your own logging leaks.

What happens to each Vite 7 config key?

We upgraded one project and ran seven keys through Vite 8.3.4. The table shows the result for each, and the chart below summarizes the same data.

Chart of seven Vite 7 config keys and what Vite 8.3.4 did with each

Vite 7 config Result on Vite 8.3.4 Replacement
build.rollupOptions still works, no warning in our run build.rolldownOptions
manualChunks: { ... } object build fails function form, then codeSplitting
optimizeDeps.esbuildOptions deprecation warning, converted automatically optimizeDeps.rolldownOptions
esbuild: { jsx: 'automatic' } ignored when oxc options are set oxc: { jsx: { runtime: 'automatic' } }
esbuild: { drop: ['console'] } ignored, no error rolldownOptions.output.minify.compress.dropConsole
transformWithEsbuild() deprecation warning transformWithOxc()
build.minify: 'esbuild' still builds the Oxc minifier is the default

Three notes on the table. First, rollupOptions is listed as deprecated in the migration guide, which says it was "renamed to build.rolldownOptions." We saw it work without a warning, so rename it on your schedule, not in a panic. Second, the guide says transformWithEsbuild users "need to install esbuild as a devDependency," because esbuild is now an optional dependency. Third, build.minify: 'esbuild' is a deprecated switch back. It needs esbuild installed and will be removed.

Which other changes could hurt a production site?

Three changes are not config renames, so a build can pass while behavior shifts. All three come from the migration guide.

  1. Browser targets moved up. The default build.target of baseline-widely-available now means Chrome 111, Edge 111, Firefox 114 and Safari 16.4. The old values were Chrome 107, Edge 107, Firefox 104 and Safari 16.0. Output may use newer syntax, so check your analytics for Safari 16.0 to 16.3 traffic before you upgrade.
  2. CommonJS interop is now consistent. The default import from a CommonJS module resolves the same way in dev and build, using module.exports in specific cases. A package that worked by accident under the old rules can now return undefined. Test every page that imports older packages.
  3. require calls stay require. Calls for externalized modules are preserved instead of rewritten to import. The guide points to esmExternalRequirePlugin if you want the old conversion.

None of these printed a warning in our lab, because our small app did not touch them. Larger apps with legacy dependencies are the ones at risk, so run the full browser test suite once, not just a build.

Which plugins still work with Vite 8?

Most popular plugins already accept Vite 8, and some of the newest releases accept nothing else. We read the peerDependencies.vite field from the npm registry for twelve plugins on October 18, 2026. A range is a promise, not a test, but it tells you where npm install will refuse.

Package Latest version Declared Vite range
@vitejs/plugin-react 6.1.2 ^8.0.0 only
@vitejs/plugin-legacy 8.2.3 ^8.0.0 only
@sveltejs/vite-plugin-svelte 7.3.1 ^8.0.0
@vitejs/plugin-vue 6.0.10 ^5 through ^8
@tailwindcss/vite 4.3.3 ^5.2 through ^8
vite-plugin-pwa 2.0.0 ^3.1 through ^8
@vitejs/plugin-react-swc 4.3.3 ^4 through ^8
vitest 5.0.5 ^6.4 through ^8
vite-plugin-svgr 5.2.0 >=3.0.0
vite-tsconfig-paths 6.1.1 any
vite-plugin-dts 5.1.2 >=3

The practical consequence is a trap for teams that stay on Vite 7. Running npm update pulls @vitejs/plugin-react 6.1.2, whose peer range is ^8.0.0. On Vite 7 that produces a peer dependency conflict, even though you did not ask for a Vite upgrade. Pin the plugin to the 5.x line while you stay on Vite 7, or upgrade both together.

The @vitejs/plugin-react 5.2.0 we used in the lab lists Vite 4 through 8, which is why our upgrade installed cleanly. The bottom line is that the plugin ecosystem has already moved. Staying on Vite 7 now costs you plugin updates.

What does a full config look like before and after?

A typical Vite 7 config needs five edits. The first block is the config we upgraded. The second is the version that built cleanly on Vite 8.3.4 with the console check passing.

// vite.config.js on Vite 7
export default defineConfig({
  plugins: [react()],
  esbuild: { jsx: "automatic", drop: ["console"] },
  optimizeDeps: { esbuildOptions: { target: "es2020" } },
  build: {
    minify: "esbuild",
    rollupOptions: {
      output: { manualChunks: { react: ["react", "react-dom"] } },
    },
  },
});
// vite.config.js on Vite 8
export default defineConfig({
  plugins: [react()],
  oxc: { jsx: { runtime: "automatic" } },
  optimizeDeps: { rolldownOptions: { transform: { target: "es2020" } } },
  build: {
    rolldownOptions: {
      output: {
        manualChunks(id) {
          if (id.includes("node_modules/react")) return "react";
        },
        minify: { compress: { dropConsole: true } },
      },
    },
  },
});

The five changes are: esbuild becomes oxc for JSX, optimizeDeps.esbuildOptions becomes rolldownOptions, rollupOptions becomes rolldownOptions, the chunk object becomes a function, and drop moves into the minifier. We removed minify: "esbuild" because the Oxc minifier is the default. We built this exact config and it finished in 68 ms with a 219 kB react chunk, no warnings, and zero marker strings in the bundle.

One caution on the oxc block: our lab used the React plugin, which handles JSX itself. If you set jsx options manually, confirm them against the Vite announcement post and the migration guide before you ship.

How much faster is Vite 8?

About twice as fast on our synthetic app, though the real gain depends on module count. We generated 1,504 small modules and ran vite build six times on each version, using the middle two results.

Bar chart of production build time: Vite 7.3.7 took 0.74 seconds and Vite 8.3.4 took 0.37 seconds

Version Wall time, 1,504 modules
Vite 7.3.7 0.74 s
Vite 8.3.4 0.37 s

These timings include Node startup, so the bundler itself is faster than the ratio suggests. A real app with heavy plugins will show a different gap. Do not promise your team a number from our app. Measure your own vite build before and after, and keep the old number in the pull request.

What is the safest upgrade path?

Use the stepping stone Vite provides, then upgrade in two commits. The migration guide describes rolldown-vite, a package that "implements Vite 7 with Rolldown, without other Vite 8 changes." That lets you isolate bundler problems from config problems.

  1. Check Node: 20.19 or newer, or 22.12 or newer.
  2. Switch to rolldown-vite on Vite 7 and run your tests. Fix any Rolldown behavior changes.
  3. Move to Vite 8 with npm i -D vite@^8 and remove the rolldown-vite alias.
  4. Search your config for the audit terms below and replace each match.
  5. Add the CI assertion from the section above.
  6. Check plugin support. @vitejs/plugin-react 5.2.0 lists Vite 8 in its peer range, and Vitest 5.0.5 allows ^8.0.0.

Run this audit before you start:

grep -nE "esbuild|rollupOptions|manualChunks|transformWithEsbuild|minify" vite.config.* package.json

Every hit is a line to read against the table above. If you maintain a plugin, search for transformWithEsbuild first, since that is the function the guide deprecates.

Should I upgrade to Vite 8 now?

Yes if you are on Node 20.19 or newer and have a test suite; wait if your app depends on old CommonJS packages and has no browser tests. The speed gain is real and Vite 7 will fall behind. The danger is not the build error, which is obvious. The danger is the config key that silently does nothing.

Treat the first Vite 8 release in your repo as a change that needs a production smoke test. Build, serve the output, load the main pages, and grep the bundle for debug strings. That ten-minute check is cheaper than finding your internal logging in a customer's browser console.

Advertisement

FAQ

Why does Vite 8 fail with "manualChunks is not a function"?

Vite 8 no longer supports the object form of build.rollupOptions.output.manualChunks, because Rolldown expects a function. Replace the object with a function that returns a chunk name for matching module ids, or move to Rolldown's codeSplitting option.

Does esbuild.drop still remove console.log in Vite 8?

No. In our test on Vite 8.3.4, esbuild: { drop: ['console'] } was ignored and console.log stayed in the production bundle. Use build.rolldownOptions.output.minify.compress.dropConsole: true instead, and verify the result with a post-build grep.

Is build.rollupOptions removed in Vite 8?

Not yet. The migration guide marks it deprecated and renamed to build.rolldownOptions. In our Vite 8.3.4 test it still worked with no warning. Rename it during the upgrade so the eventual removal does not surprise you.

What Node version does Vite 8 need?

Vite 8.3.4 declares ^20.19.0 || >=22.12.0 in its engines field. That means Node 20.19 or later, or Node 22.12 or later. Older Node 20 releases and Node 18 are not supported by this version.

How do I upgrade to Vite 8 step by step?

Install rolldown-vite on Vite 7 first and fix bundler issues. Then switch to vite@^8, replace removed config keys, and add a post-build check for leaked debug logs. Run your browser tests once, because CommonJS interop and browser targets changed.

Comments

Loading…

Sign in to join the conversation.

Related posts

Python 3.15 default encoding change and lazy imports

Python 3.15 makes UTF-8 the default. What breaks?

Python 3.15 changes one default that can quietly alter how your scripts read files. Calling open() without an encoding argument now means UTF-8 on every system. For most code that is a fix. For code

Sun Oct 18 2026 · 10 min read · 0 views

Software