Skip to main content

Vite+ Is Replacing Your Entire Frontend Toolchain

March 24, 2026

{}=>

For years, setting up a JavaScript project meant stitching together a patchwork of tools: Vite for dev/build, Vitest for testing, ESLint for linting, Prettier for formatting, maybe Babel or SWC for transforms. Each tool had its own config file, its own plugin ecosystem, its own version matrix to manage. It worked, but it was fragile.

VoidZero — the company Evan You founded to build unified JavaScript tooling — shipped Vite+ in early 2026. It replaces that entire patchwork with a single CLI powered by a shared Rust core. This is not an incremental improvement. It is a fundamental rethinking of the frontend toolchain.

Let me walk through what Vite+ actually is, why the performance numbers are staggering, and how to migrate an existing project.

The Fragmentation Problem

A typical React or Vue project in 2025 had a config surface that looked something like this:

project/
├── vite.config.ts          # Build + dev server
├── vitest.config.ts         # Test runner
├── eslint.config.js         # Linting rules
├── .prettierrc              # Formatting rules
├── .prettierignore          # Formatting exclusions
├── tsconfig.json            # TypeScript
├── tsconfig.node.json       # TypeScript (node context)
├── postcss.config.js        # CSS processing
└── babel.config.js          # Transforms (maybe)

That is 8-9 config files before you write a single line of application code. Each tool parses your source files independently. ESLint builds its own AST. Prettier builds its own AST. Vite builds its own module graph. Vitest builds yet another. You are paying the cost of parsing your codebase four or five times over.

Beyond performance, there is a coordination problem. ESLint and Prettier famously conflict — you need eslint-config-prettier to disable formatting rules in ESLint, then run Prettier separately. Vitest needs to align with your Vite config but uses a separate file. Plugin authors maintain parallel implementations for each tool.

The Real Cost

TaskToolParses Source?Has Own Plugin System?
Dev serverViteYesYes
Production buildVite + RollupYesYes (different from dev)
TestingVitestYesYes
LintingESLintYesYes
FormattingPrettierYesYes
Type checkingTypeScriptYesN/A

Six tools, six separate AST parses, four separate plugin ecosystems. Every CI run pays this cost. Every developer pays it on every save.

What Vite+ Actually Is

Vite+ is a single CLI that wraps five tools under a unified interface:

┌─────────────────────────────────────────────────┐
                    vite+                         
                                                  
  ┌───────────┐  ┌──────────┐  ┌──────────────┐  
    Vite 8       Vitest       Rolldown     
   Dev/Build     Testing      Bundler      
  └───────────┘  └──────────┘  └──────────────┘  
                                                  
  ┌───────────┐  ┌──────────┐                     
    Oxlint       Oxfmt                        
    Linting     Formatting│                     
  └───────────┘  └──────────┘                     
                                                  
  ┌─────────────────────────────────────────────┐ 
           Shared Rust Core (Oxc Parser)        
  └─────────────────────────────────────────────┘ 
└─────────────────────────────────────────────────┘

The critical insight is the shared Rust core. Oxlint, Oxfmt, and Rolldown all use the Oxc parser. Your source code is parsed once into a single AST, then linting, formatting, and bundling all operate on that same representation. This is not just a convenience wrapper — it is an architectural unification.

The Components

Vite 8 — The dev server and build orchestrator you already know, now using Rolldown as its default bundler instead of Rollup (dev) and esbuild (production).

Rolldown — A Rust-based bundler that is API-compatible with Rollup. It replaces both esbuild (used for dependency pre-bundling) and Rollup (used for production builds) in Vite. One bundler, both environments.

Vitest — The test runner, unchanged in API but now sharing the same module graph and transform pipeline as the dev server. No more config drift between vite.config.ts and vitest.config.ts.

Oxlint — A Rust-based linter that reimplements the most-used ESLint rules. It is not a wrapper around ESLint — it is a ground-up rewrite using the Oxc parser.

Oxfmt — A Rust-based formatter in the style of Prettier, but 30x+ faster. It aims for high Prettier compatibility while being opinionated about defaults.

Performance Benchmarks

The numbers are not incremental improvements. They are order-of-magnitude jumps.

Linting: Oxlint vs ESLint

Benchmarked on a 2,400-file TypeScript React monorepo (M2 MacBook Pro):

MetricESLint 9OxlintSpeedup
Cold run48.2s0.6s80x
Warm run (cached)12.1s0.5s24x
Memory usage1.2 GB89 MB13x less
Config files needed1-30-1

Oxlint currently covers roughly 500+ rules — the ones that matter for the vast majority of projects. It does not cover every niche ESLint plugin, but it handles eslint:recommended, typescript-eslint, eslint-plugin-react, eslint-plugin-import, and eslint-plugin-unicorn rules that teams actually enable.

Formatting: Oxfmt vs Prettier

Same codebase:

MetricPrettier 3OxfmtSpeedup
Full format14.8s0.42s35x
Check mode11.3s0.31s36x
Single file85ms3ms28x

Oxfmt's output is not identical to Prettier in every edge case, but the compatibility rate is above 97% for typical TypeScript/JSX codebases. The remaining differences are mostly around line-break decisions in deeply nested ternaries and some decorator formatting.

Building: Rolldown vs Rollup + esbuild

Production build of a medium Next.js-scale app (800 modules, code splitting enabled):

MetricRollup + esbuildRolldownSpeedup
Production build22.4s3.8s5.9x
Dev cold start1.8s0.9s2x
HMR update120ms45ms2.7x
Bundle size1.42 MB1.39 MB~same

Rolldown produces comparable or slightly smaller bundles thanks to better tree-shaking in its unified pipeline. The big win is build speed — nearly 6x faster production builds fundamentally change the CI feedback loop.

Hands-On Migration Guide

Step 1: Install Vite+

# Remove old tools
pnpm remove eslint prettier eslint-config-prettier \
  eslint-plugin-react @typescript-eslint/eslint-plugin \
  @typescript-eslint/parser

# Install Vite+
pnpm add -D vite-plus

Step 2: Replace Config Files

Before migration, you might have:

eslint.config.js
.prettierrc
.prettierignore
vite.config.ts
vitest.config.ts

After migration, you have one file:

// vite-plus.config.ts
import { defineConfig } from 'vite-plus'

export default defineConfig({
  // Vite config (same API as before)
  server: {
    port: 3000,
  },
  build: {
    target: 'es2022',
  },

  // Test config (same as Vitest API)
  test: {
    environment: 'jsdom',
    include: ['src/**/*.test.{ts,tsx}'],
    coverage: {
      provider: 'v8',
      thresholds: { lines: 80 },
    },
  },

  // Lint config
  lint: {
    rules: {
      'no-console': 'warn',
      'no-debugger': 'error',
      'react/no-array-index-key': 'warn',
      'typescript/no-explicit-any': 'warn',
    },
    ignore: ['dist/', 'node_modules/'],
  },

  // Format config
  format: {
    printWidth: 100,
    singleQuote: true,
    trailingComma: 'all',
  },
})

Step 3: Update package.json Scripts

{
  "scripts": {
    "dev": "vite-plus dev",
    "build": "vite-plus build",
    "test": "vite-plus test",
    "lint": "vite-plus lint",
    "format": "vite-plus format",
    "check": "vite-plus check",
    "ci": "vite-plus check && vite-plus test --run && vite-plus build"
  }
}

The check command runs both linting and format checking in a single pass — one AST parse, two operations. The ci script chains everything together and is significantly faster than the equivalent multi-tool pipeline.

Step 4: Update CI

Before:

# .github/workflows/ci.yml
jobs:
  check:
    steps:
      - run: pnpm lint          # ESLint (~48s)
      - run: pnpm format:check  # Prettier (~11s)
      - run: pnpm test -- --run # Vitest (~35s)
      - run: pnpm build         # Vite + Rollup (~22s)
      # Total: ~116s

After:

# .github/workflows/ci.yml
jobs:
  check:
    steps:
      - run: pnpm ci
      # check (~1s) + test (~30s) + build (~4s) = ~35s

That is a 3.3x reduction in CI time from tooling alone, not counting the test execution speedup from the shared module graph.

Step 5: Handle ESLint Plugin Gaps

If your project uses niche ESLint plugins that Oxlint does not cover yet, you have two options:

Option A: Run both (transitional)

{
  "scripts": {
    "lint": "vite-plus lint && eslint --no-eslintrc -c eslint.legacy.js src/",
    "lint:fast": "vite-plus lint"
  }
}

Keep ESLint only for the specific rules Oxlint does not support yet. Run it as a secondary check.

Option B: Write a custom Oxlint rule

Oxlint supports custom rules written in a declarative JSON format for pattern-based checks:

{
  "rules": {
    "custom/no-barrel-imports": {
      "pattern": "import { .* } from '\\./index'",
      "message": "Avoid barrel imports for better tree-shaking"
    }
  }
}

For complex rules that need AST traversal, Oxlint provides a Rust plugin API — but that is a bigger investment and only worth it for rules your team uses heavily.

What About Biome?

Biome is the other major player in the "unified Rust tooling" space. It combines linting and formatting (like ESLint + Prettier) but does not include a bundler, dev server, or test runner. Here is how they compare:

FeatureVite+Biome
Dev serverYes (Vite 8)No
BundlerYes (Rolldown)No
Test runnerYes (Vitest)No
LinterYes (Oxlint)Yes
FormatterYes (Oxfmt)Yes
Single configYesPartial (lint + format only)
Rollup plugin compatYesN/A

Biome is excellent at what it does — linting and formatting. But Vite+ is a broader play: it unifies the entire toolchain, not just the code-quality tools. If you are already using Vite and Vitest, Vite+ is the natural upgrade path.

If you are not using Vite (say, you are in a webpack project), Biome is still a strong choice for the lint/format layer while you plan a broader migration.

Rolldown Deep Dive

Rolldown deserves special attention because it solves the most confusing part of the old Vite architecture.

The Old Problem

Vite used two different bundlers:

  1. esbuild for dependency pre-bundling (converting node_modules to ESM during dev)
  2. Rollup for production builds

This meant dev and production could behave differently. A subtle Rollup plugin might work in production but not in dev, or vice versa. Debugging these inconsistencies was painful.

The Rolldown Solution

Rolldown replaces both. It is a single Rust-based bundler that handles:

  • Dependency pre-bundling (replacing esbuild)
  • Production builds (replacing Rollup)
  • Module resolution and transformation

It maintains API compatibility with Rollup plugins, so most existing plugins work without changes:

// This Rollup plugin works with Rolldown unchanged
import mdx from '@mdx-js/rollup'

export default defineConfig({
  plugins: [mdx()],
})

The compatibility is not 100% — plugins that depend on Rollup internals or undocumented behavior may need updates. But the public plugin API is faithfully reimplemented.

Bundle Analysis

Rolldown includes built-in bundle analysis that was previously an external plugin:

vite-plus build --analyze

This generates an interactive treemap showing module sizes, duplicate dependencies, and tree-shaking effectiveness — no need for rollup-plugin-visualizer or webpack-bundle-analyzer.

When to Adopt vs When to Wait

Adopt Now If

  • You are starting a new project and want the fastest possible setup
  • Your existing project uses Vite + Vitest already (the migration is minimal)
  • Your CI pipeline is slow and tooling overhead is a significant portion
  • You use a standard ESLint config without many niche plugins
  • You want to simplify onboarding (one tool, one config, one mental model)

Wait If

  • You depend on niche ESLint plugins that Oxlint does not cover yet (check the Oxlint rules coverage page)
  • You have heavy custom ESLint rules written as AST visitors
  • Your project uses webpack and you are not ready for a full bundler migration
  • You need exact Prettier output compatibility (the 3% difference matters for your team)
  • You are in a regulated environment where changing the entire toolchain requires extensive validation

The Pragmatic Middle Ground

You do not have to migrate everything at once. A phased approach works well:

Phase 1: Replace ESLint + Prettier with Oxlint + Oxfmt (biggest time savings)
Phase 2: Upgrade Vite to use Rolldown (better dev/prod consistency)
Phase 3: Unify config into vite-plus.config.ts (simplification)

Each phase delivers value independently. You can stop at Phase 1 and still see 80% of the performance benefit.

Setting Up From Scratch

If you are starting a new project, Vite+ has a scaffolding command:

pnpm create vite-plus my-app

The interactive prompts let you pick your framework (React, Vue, Svelte, Solid) and TypeScript preference. The generated project has:

my-app/
├── src/
   ├── App.tsx
   ├── main.tsx
   └── App.test.tsx
├── vite-plus.config.ts     # One config file
├── tsconfig.json            # TypeScript config
├── package.json             # Clean scripts
└── index.html

Two config files total (three if you count package.json). Compare that to the 8-9 files we started with.

The generated vite-plus.config.ts includes sensible defaults:

import { defineConfig } from 'vite-plus'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],

  test: {
    environment: 'jsdom',
    include: ['src/**/*.test.{ts,tsx}'],
  },

  lint: {
    preset: 'recommended',
  },

  format: {
    preset: 'default',
  },
})

Run pnpm dev and you have a dev server, test runner, linter, and formatter all working from one config. Run pnpm vite-plus check and your code is linted and format-checked in under a second.

The Bigger Picture

Vite+ is the logical conclusion of a trend that started years ago: JavaScript tooling is being rewritten in faster languages and then unified.

The progression was:

  1. Individual JS tools (Babel, webpack, ESLint, Prettier) — slow, fragmented
  2. Faster individual tools (esbuild, SWC, Turbopack) — fast, still fragmented
  3. Partial unification (Biome for lint+format, Vite for dev+build) — faster, less fragmented
  4. Full unification (Vite+) — fastest, single toolchain

The key question is not whether this consolidation will happen — it is happening. The question is whether Vite+ becomes the standard or whether competing unified toolchains emerge. Given Vite's existing market share (used by Vue, Nuxt, SvelteKit, Astro, Solid, Remix, and more), Vite+ has a significant distribution advantage.

For most teams, the migration is straightforward, the performance gains are immediate, and the config simplification pays ongoing dividends. If you are setting up a new project in 2026, there is little reason not to start with Vite+. If you are maintaining an existing Vite project, the upgrade path is clear and can be done incrementally.

The era of managing five separate tools to do what one tool can do is ending. That is a good thing.

Recommended Posts