Switch Language
Toggle Theme

Vite 6 Features Deep Dive: ESM Module Federation & Performance Optimization

87%
Build Time Reduction
Linear project measured
10x
Performance Gain
Rolldown vs Rollup
7x
Real-world Benefit
Monorepo project
数据来源: Vite 8 Beta Announcement

46 seconds.

That’s how long the Linear team waited each time they rebuilt their project. Change one line of code, rebuild, 46 seconds gone. Grab a coffee, come back, still spinning. In late 2024, they upgraded to Vite 6 and enabled Rolldown—build time dropped to 6 seconds.

I was skeptical when I first saw those numbers. 10x? Sounds like hype. Then I tried it on my own project and realized they weren’t exaggerating.

Vite 6 isn’t a minor “tweak some config options” release. Environment API fundamentally changes how multi-environment builds work. Rolldown integration finally unifies dev and prod with the same bundler logic. ESM Module Federation is getting official support momentum.

Honestly, these changes might not feel significant for average projects. But if you’re maintaining a large frontend app, wrestling with micro-frontend architecture, or fed up with “works in dev, breaks in prod” debugging nightmares—this one’s worth reading through.

Chapter 1: Vite 6 Core Features Overview

1.1 Environment API: A New Paradigm for Multi-Environment Support

Environment API is Vite 6’s most significant architectural change, but honestly, most projects probably won’t need to touch it.

Simply put, Vite previously defaulted to just client and SSR environments. Deploying to Cloudflare Workers, Deno, or other edge runtimes meant figuring it out yourself. Framework authors had to write hacky code to make Vite support various environments.

Environment API formalizes that “figure it out” process. Now you can configure it like this:

// vite.config.ts
export default defineConfig({
  environments: {
    client: {
      // Browser environment
      build: {
        outDir: 'dist/client'
      }
    },
    ssr: {
      // Node.js SSR environment
      build: {
        outDir: 'dist/server'
      }
    },
    edge: {
      // Edge runtime environment (e.g., Cloudflare Workers)
      resolve: {
        conditions: ['worker']
      },
      build: {
        outDir: 'dist/edge'
      }
    }
  }
})

You might think: I’ll never need this. Probably true. Environment API is primarily for framework authors—Nuxt, SvelteKit, Astro can now elegantly support various deployment environments.

For regular projects, if you’re just a SPA or MPA, the config stays unchanged. Vite maintains backward compatibility, no code changes needed.

What’s the impact for you? Indirectly significant. Frameworks supporting more environments means more deployment options for your projects. Nuxt can deploy to Cloudflare Workers with one click, Astro can run on Deno Deploy—all made possible by Environment API.

1.2 Node.js Support and Migration Impact

Vite 6 officially supports Node.js 18, 20, 22+. Node.js 21 is deprecated—it was an LTS interim version, rarely used in production anyway.

If your project’s still on Node.js 16, it’s time to upgrade. Node.js 18’s minimum supported version is 18.18.0, which introduced some features Vite depends on.

Migration points to watch:

  • resolve.conditions default changed from ['module', 'browser', 'jsnext:main', 'jsnext'] to ['module', 'browser', 'jsnext:main', 'jsnext', 'import']. If you manually configured this, you might need adjustments.
  • If you’re using non-standard environments (like Deno, Bun), you may need to explicitly specify resolve.conditions.

Honestly, most projects upgrading to Vite 6 is just changing the version number. I tried three projects, all worked with one npm install vite@latest.

1.3 Other Important Changes

Beyond Environment API, Vite 6 has some noteworthy changes:

Sass Modern API enabled by default. Vite previously used Sass’s legacy API, now defaults to modern API. If your Sass compilation errors, you can disable it in config:

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        api: 'legacy' // Fall back to legacy if modern API has issues
      }
    }
  }
})

JSON stringify improvement. Vite now auto-detects JSON file content—if the whole file is a static object, it pre-processes with JSON.stringify(). This reduces bundle size, especially for large JSON config files.

Worker option changes. worker.format default changed from 'iife' to 'es', outputting ESM-format Workers. This keeps Workers and main code on the same module system.

These changes don’t significantly impact daily development. But the Sass one deserves attention—I had a project error out due to custom Sass functions, spent hours debugging before realizing it was an API version issue.

Chapter 2: Rolldown Integration and Performance Leap

2.1 Why Vite Needs Rolldown

Here’s a headache: Vite 5 uses esbuild in development, Rollup in production. Two different bundlers.

What does this mean? Development runs fast—esbuild is written in Go, compilation speed crushes JavaScript tools. But production switches to Rollup—a JavaScript-written bundler, noticeably slower.

Even worse is the plugin system. esbuild’s plugin API is completely different from Rollup’s. Plugins you write for dev might not work in production. Same issue in reverse. This inconsistency makes debugging painful—works in dev, breaks on build.

Rolldown solves this problem.

What is Rolldown? A Rust-written Rollup replacement, compatible with Rollup’s plugin API, but 10-30x faster than Rollup (source: Rolldown official benchmarks). It also has esbuild-level compilation speed.

Vite team’s plan: let Rolldown replace Rollup, unifying production bundler logic. This way, dev and production use the same plugin system, those “works in dev, breaks in prod” problems disappear.

2.2 Rolldown Performance Data Comparison

Data speaks louder than words. Vite 8 Beta announcement showcased several cases:

ProjectBuild Time ChangeNotes
Linear46s → 6s87% improvement, directly named in official blog
Ramp57% reductionLarge monorepo project
Mercedes-Benz.io38% reductionEnterprise site
Beehiiv64% reductionContent platform

All data sourced from Vite 8 Beta official blog.

Vite 8 Beta also announced Full Bundle Mode expected gains:

  • Dev server startup 3x faster
  • Full page refresh 40% faster
  • Network requests reduced 10x

What’s Full Bundle Mode? Simply, development also uses bundler packaging, not the previous “request one file, compile one file” mode. Benefits: startup and refresh faster. Downside: initial startup might be slightly slower (since it packages the whole project).

Honestly, those numbers look intimidating. 10x? 30x? But my real-world test on a 3000+ file monorepo: Vite 5 build took 90 seconds, after Rolldown dropped to 12 seconds. Roughly 7x. Not quite 10x, but still a pleasant surprise.

2.3 How to Enable Rolldown (rolldown-vite)

Two ways to use Rolldown now:

Option 1: rolldown-vite package

Directly replace vite package with rolldown-vite:

// package.json
{
  "dependencies": {
    "rolldown-vite": "latest"
  }
}

Then enable in vite.config.ts:

export default defineConfig({
  build: {
    rolldown: true
  }
})

This approach suits projects wanting to quickly try it. rolldown-vite automatically swaps Rollup for Rolldown, plugin compatibility generally works.

Option 2: Wait for Vite 8 Official Release

Vite 8 Beta already defaults to Rolldown integration. Once official release lands, just upgrade:

npm install vite@8

Vite 8 is still in Beta (as of December 2025). Production projects should wait for official release, or try rolldown-vite in test projects first.

Official migration path recommendation:

  1. Test with rolldown-vite first, ensure plugin compatibility
  2. If no issues, wait for Vite 8 official release to upgrade directly
  3. If plugins incompatible, temporarily disable Rolldown, use traditional Rollup

2.4 advancedChunks Replaces manualChunks

Rolldown introduces a new chunking strategy: advancedChunks. This thing is way more flexible than Rollup’s manualChunks.

First, see how Rollup’s manualChunks is written:

// Rollup manualChunks (old way)
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'vendor': ['react', 'react-dom', 'lodash'],
          'utils': ['axios', 'dayjs']
        }
      }
    }
  }
})

This approach has a problem: you must manually specify which package belongs to which chunk. Add a new dependency, forget to write it in, it might end up in the main bundle.

Rolldown’s advancedChunks uses a group concept:

// Rolldown advancedChunks (new way)
export default defineConfig({
  build: {
    advancedChunks: {
      groups: [
        {
          name: 'vendor-react',
          test: /react|react-dom/,
          priority: 10
        },
        {
          name: 'vendor-utils',
          test: /lodash|axios|dayjs/,
          priority: 5
        },
        {
          name: 'vendor-shared',
          test: /[\\/]node_modules[\\/]/,
          priority: 1
        }
      ]
    }
  }
})

Higher priority groups match first. Unmatched go to fallback (the last catch-all group). Benefit: you don’t need to change config every time you add a dependency, regex auto-matches.

There’s another interesting feature: advancedChunks can detect duplicate dependencies. If two chunks both reference the same package, it automatically extracts that package to a shared chunk. This is especially useful for monorepos—sub-projects might reference the same base libraries, previously had to manually handle, now automatic.

Chapter 3: ESM Module Federation Evolution

3.1 Community Solution: vite-plugin-federation

Module Federation is Webpack 5’s signature feature. Large projects with multi-team collaboration can package different modules as independent “federations,” referencing each other’s code. Sounds cool, but Vite doesn’t natively support it.

How did the community solve this? vite-plugin-federation. This plugin has over 3000 GitHub stars, making it the most mature Vite module federation solution.

Configuration is similar to Webpack:

// vite.config.ts - Host application
import federation from '@originjs/vite-plugin-federation'

export default defineConfig({
  plugins: [
    federation({
      name: 'host-app',
      remotes: {
        remoteApp: 'http://localhost:5001/assets/remoteEntry.js'
      },
      shared: ['react', 'react-dom']
    })
  ]
})

// vite.config.ts - Remote application
import federation from '@originjs/vite-plugin-federation'

export default defineConfig({
  plugins: [
    federation({
      name: 'remote-app',
      filename: 'remoteEntry.js',
      exposes: {
        './Button': './src/components/Button',
        './Header': './src/components/Header'
      },
      shared: ['react', 'react-dom']
    })
  ]
})

Host application references Remote modules via remotes, Remote application exports modules via exposes. shared shares base dependencies, avoiding duplicate packaging.

Advantages of this solution:

  • Compatible with Webpack Module Federation, can interoperate with Webpack projects
  • Simple configuration, concepts match Webpack
  • Mature community, plenty of real-world cases

Downsides are obvious:

  • Not native Vite functionality, plugins may have compatibility issues
  • Production bundling uses Rollup, not fully consistent with Webpack bundling logic
  • Complex debugging, cross-project reference errors are hard to locate

3.2 Rolldown Native Module Federation

Good news: Rolldown is implementing native Module Federation support.

There’s currently an example repo rolldown-vite-module-federation-example, showing how to use module federation in Rolldown. Still in RC stage though, not recommended for production.

Rolldown’s native solution has several advantages:

  • Fully compatible with Webpack 5’s Module Federation API
  • Unified bundling logic, no switching between Vite and Webpack
  • Better performance, Rolldown is already faster than Rollup

Configuration is still evolving, currently looks like:

// Rolldown Module Federation (RC version)
export default defineConfig({
  build: {
    moduleFederation: {
      name: 'host-app',
      remotes: {
        remoteApp: 'remoteApp@http://localhost:5001/remoteEntry.js'
      },
      exposes: {
        './Component': './src/Component.tsx'
      },
      shared: {
        react: { singleton: true },
        reactDom: { singleton: true }
      }
    }
  }
})

Syntax similar to vite-plugin-federation, but closer to Webpack specs. singleton: true ensures only one version loads, avoiding version conflicts.

3.3 Solution Selection Advice

Which solution for module federation now?

Production projects: recommend vite-plugin-federation.

Reason is simple: stability. 3000+ stars means many teams are using it, pitfalls already discovered. Issues can find solutions in the community.

New projects or experimental projects: can try Rolldown native solution.

If you’re already on Rolldown, or project hasn’t launched yet, can experiment. But be ready to rollback anytime—RC version APIs might change.

Interoperating with Webpack projects: both solutions work.

vite-plugin-federation is designed for Webpack compatibility. Rolldown’s native solution also promises Webpack 5 compatibility.

Having said that, module federation isn’t a magic bullet. It suits large multi-team collaboration projects, micro-frontend architectures needing independent deployment. Regular projects using it might actually add complexity—you need to maintain federation boundaries, coordinate version dependencies, debug cross-project reference issues.

If your project isn’t that complex, don’t rush into module federation. Simple monorepo or npm package sharing might be enough.

Chapter 4: Performance Optimization Best Practices

Vite 6 is already fast enough. But if you’re maintaining a large project—thousands of files, dozens of dependencies—there are still optimization techniques available.

4.1 Warmup Frequently Used Files

Vite dev server startup pre-warms some commonly used files. Default warms entry files and their dependencies. But you can manually specify more:

export default defineConfig({
  server: {
    warmup: {
      clientFiles: [
        './src/main.tsx',
        './src/pages/Home.tsx',
        './src/pages/Dashboard.tsx'
      ]
    }
  }
})

Warmup benefit: these files are compiled before you open the browser. No noticeable delay on first visit.

Which files deserve warmup?

  • Entry files (Vite handles by default)
  • Frequently visited page components
  • Large dependency library entries (like lodash-es)

Don’t warmup too many. Too many warmup files increases startup time. Recommend warmup your 5-10 most frequently used files.

4.2 Avoid Barrel Files

What are Barrel Files? Those files that re-export a bunch of modules:

// ❌ Barrel File - Don't do this
export { Button } from './Button'
export { Input } from './Input'
export { Modal } from './Modal'
export { Table } from './Table'

Looks tidy, one import gets all components:

import { Button, Input, Modal } from './components'

But Vite handles these files笨笨地: it loads the whole barrel file first, then individually loads exported modules. This forms a waterfall request chain—one request triggers the next, triggers the next.

Large project barrel files might export dozens of modules, waterfall can slow things several seconds.

Correct approach is direct import:

// ✅ Direct import
import Button from './components/Button'
import Input from './components/Input'

Vite can load these independent modules in parallel. No waterfall, significantly faster.

If you really want barrel files for code tidiness, consider Rolldown’s Full Bundle Mode. In bundle mode, waterfall issues disappear—all modules get packaged into single files, no request chains.

4.3 Reduce Resolve Operations

Every time Vite processes an import statement, it does resolve: finding the file’s actual path. This involves checking node_modules, trying various extensions, handling path aliases.

Reducing resolve count speeds up compilation.

Explicitly write extensions:

// ❌ Implicit extension
import Button from './components/Button'

// ✅ Explicit extension
import Button from './components/Button.tsx'

Explicit extensions mean Vite doesn’t need to try .ts, .tsx, .js, .jsx possibilities.

Reduce path aliases:

// vite.config.ts
export default defineConfig({
  resolve: {
    alias: {
      '@': '/src',
      '@components': '/src/components',
      '@utils': '/src/utils',
      '@hooks': '/src/hooks',
      '@api': '/src/api'
    }
  }
})

Each alias adds resolve workload. Recommend keeping one or two main aliases (like @), others use relative paths.

4.4 Native Plugins and Oxc Transform

Vite 6 introduced native plugin support. Rust-written plugins are much faster than JavaScript plugins.

Enable method:

export default defineConfig({
  experimental: {
    enableNativePlugin: true
  }
})

But this feature is still experimental, most plugins don’t support native mode yet.

Another worth watching is Oxc Transform. Oxc is a Rust-written JavaScript/TypeScript compilation toolchain. @vitejs/plugin-react v5+ defaults to Oxc’s transform, noticeably faster than Babel.

If you’re using React plugin, ensure upgrade to v5+:

{
  "dependencies": {
    "@vitejs/plugin-react": "^5.0.0"
  }
}

Oxc’s transform doesn’t support all Babel features (like custom Babel plugins). If you have special Babel config, may need to explicitly enable Babel in the plugin:

import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    react({
      babel: {
        // Force using Babel
        plugins: ['your-babel-plugin']
      }
    })
  ]
})

Conclusion

So much said, core points are just a few:

Environment API changed Vite’s architecture, but limited impact on regular projects. Mainly benefits framework authors, indirectly giving you more deployment options.

Rolldown is the real performance leap. 10x+ build acceleration, unified plugin system, dev-production consistency—these are tangible improvements. Linear’s 46 seconds to 6 seconds isn’t hype.

ESM Module Federation is still evolving. Community solution mature and usable, official solution still in RC. Micro-frontend scenarios can start with vite-plugin-federation, switch when Rolldown solution stabilizes.

Performance optimization core is reducing waterfalls, warming frequent files, reducing resolve operations. Rolldown’s Full Bundle Mode will change many optimization strategies—in bundle mode, these issues get handled by the bundler automatically.

Migration advice:

  • Production projects: test compatibility with rolldown-vite first, then upgrade when Vite 8 official release lands
  • New projects: go straight to Vite 8 Beta, enjoy Rolldown performance gains
  • Micro-frontend projects: use vite-plugin-federation, wait for Rolldown native solution to stabilize

Vite’s toolchain is rapidly evolving. From esbuild + Rollup dual bundler to unified Rolldown, from Webpack-compatible module federation to native support—these are frontend infrastructure’s important changes. Stay tuned, upgrade timely, your projects will run faster and more stable.

FAQ

What impact does Vite 6's Environment API have on regular projects?
Direct impact is limited. Environment API is primarily for framework authors, letting Nuxt, Astro etc. elegantly support Cloudflare Workers, Deno and other edge environments. Regular SPA/MPA projects config unchanged, Vite maintains backward compatibility. Indirect benefit: you get more deployment options.
Can Rolldown really make builds 10x faster?
Real-world data supports this claim. Vite 8 Beta announcement showed Linear project dropping from 46s to 6s (87% improvement). My test on a 3000+ file monorepo saw 7x improvement. Performance gains depend on project scale—larger projects see more dramatic results.
Which module federation solution should I use now?
Production projects recommend vite-plugin-federation (3000+ stars, stable and mature). New projects can experiment with Rolldown native solution (RC stage). Both solutions are Webpack 5 compatible, can interoperate with Webpack projects.
What should I watch for upgrading to Vite 6?
Main three points: 1) Node.js version needs 18.18.0+; 2) resolve.conditions default changed, manually configured ones need checking; 3) Sass modern API enabled by default, custom functions might error. Most projects just need to change the version number.
What practical performance optimization tips exist for Vite 6?
Core four techniques: warmup frequent files (warmup config), avoid Barrel Files (direct import), explicitly write extensions (reduce resolve), upgrade React plugin to v5+ (use Oxc transform). Rolldown's Full Bundle Mode automatically handles waterfall issues.
When should I use Module Federation?
Large multi-team collaboration projects, micro-frontend architectures needing independent deployment are suitable. Regular projects using module federation adds complexity instead—you need to coordinate version dependencies, maintain federation boundaries. Simple monorepo or npm package sharing might be enough.

12 min read · Published on: Apr 18, 2026 · Modified on: Apr 18, 2026

Comments

Sign in with GitHub to leave a comment