DEV Community

Cover image for Vite+ — Chapter 2: What’s Inside Vite+?
Othmane Nemli
Othmane Nemli

Posted on

Vite+ — Chapter 2: What’s Inside Vite+?

In the first chapter, we looked at why Vite+ exists.

The short version was:

Modern JavaScript projects use many excellent tools, but connecting and maintaining all those tools can become complicated.

Vite+ tries to bring several of those tools together behind one workflow.

But this raises another question:

What is actually inside Vite+?

If you see:

vp dev
vp test
vp check
vp build
Enter fullscreen mode Exit fullscreen mode

what happens behind those commands?

Let's open the toolbox.


Vite+ is not one giant tool

The first thing to understand is that Vite+ isn't a single replacement for everything.

It brings together several tools, each with a specific job.

A simplified view looks like this:

                    Vite+
                      |
       +--------------+--------------+
       |              |              |
   Development      Quality        Testing
       |              |              |
      Vite       Oxlint / Oxfmt   Vitest
       |
    Building
       |
   Rolldown

       +-----------------------------+
       |
    Libraries
       |
    tsdown

       +-----------------------------+
       |
     Tasks
       |
   Vite Task
Enter fullscreen mode Exit fullscreen mode

Each tool solves a different problem.

The important part is that Vite+ gives you a consistent way to work with them.

Let's go through them one by one.


1. Vite — Development

Let's start with the tool most developers already know.

Vite is primarily a development server and build tool.

If you're building a React application, for example, you might have:

src/
├── App.tsx
├── main.tsx
└── components/
    └── Button.tsx
Enter fullscreen mode Exit fullscreen mode

You want to write code and immediately see the result in your browser.

That's where Vite comes in.

You can start your development server with:

vp dev
Enter fullscreen mode Exit fullscreen mode

Under the hood, Vite is doing the work.

Why is Vite useful?

Imagine you change:

function Button() {
  return <button>Hello</button>;
}
Enter fullscreen mode Exit fullscreen mode

to:

function Button() {
  return <button>Hello World</button>;
}
Enter fullscreen mode Exit fullscreen mode

You don't want to stop the server, rebuild the entire application, and restart the browser every time you change a line.

Vite provides a fast development experience with features such as Hot Module Replacement (HMR).

In simple terms:

You change code
      ↓
Vite notices
      ↓
Browser updates
      ↓
You keep working
Enter fullscreen mode Exit fullscreen mode

This is why Vite has become such a common part of modern frontend development.

With Vite+, you still get Vite.

Vite+ doesn't replace it.


2. Vitest — Testing

Writing code is only half of the job.

We also need to make sure it works.

That's where Vitest comes in.

Suppose you have this function:

function add(a: number, b: number) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

You could write a test:

import { expect, test } from "vitest";

test("adds two numbers", () => {
  expect(add(2, 3)).toBe(5);
});
Enter fullscreen mode Exit fullscreen mode

Then run:

vp test
Enter fullscreen mode Exit fullscreen mode

Vite+ uses Vitest as its testing tool.

Why Vitest instead of something else?

You might already know tools such as Jest.

The important thing here isn't to decide which test runner is "the best."

The interesting part is that Vitest works very naturally with the Vite ecosystem.

That means your development and testing environments can share much of the same configuration and behavior.

Conceptually:

Development
     ↓
   Vite

Testing
     ↓
  Vitest

        ↓
Shared ecosystem
Enter fullscreen mode Exit fullscreen mode

This integration is one of the reasons Vitest fits naturally into Vite+.


3. Rolldown — Bundling

Now we get to a term that can sound intimidating:

bundler.

Don't worry. The idea is simple.

Your application might contain hundreds or thousands of files:

src/
├── main.ts
├── App.tsx
├── components/
│   ├── Button.tsx
│   ├── Modal.tsx
│   └── Header.tsx
├── utils/
│   ├── date.ts
│   └── format.ts
└── ...
Enter fullscreen mode Exit fullscreen mode

The browser doesn't necessarily need to receive all those files exactly as they exist in your source code.

A bundler analyzes the relationships between your files and produces optimized output for production.

Conceptually:

Your source code
       ↓
    Bundler
       ↓
Production files
       ↓
     Browser
Enter fullscreen mode Exit fullscreen mode

Traditionally, Vite has used Rollup for production builds.

Vite+ includes Rolldown, a newer bundler written in Rust and designed to provide a high-performance bundling foundation for the Vite ecosystem.

You don't necessarily need to interact with Rolldown directly.

You can simply run:

vp build
Enter fullscreen mode Exit fullscreen mode

and let the toolchain handle it.

Why does a bundler matter?

Imagine your application has:

10,000 lines of source code
Enter fullscreen mode Exit fullscreen mode

You don't want to manually decide:

"Which files should be included?"

"Which modules depend on each other?"

"Can these files be combined?"

"Can unused code be removed?"

The bundler handles these kinds of problems.

It builds a dependency graph:

App
├── Header
├── Dashboard
│   ├── Chart
│   └── Table
└── Utils
Enter fullscreen mode Exit fullscreen mode

Then it can produce optimized output.

This is one of the areas where build performance becomes important, especially for large projects.


4. tsdown — Building libraries

Applications aren't the only thing developers build.

Sometimes you're creating a library.

For example:

my-ui-library
my-auth-library
my-api-client
my-utils
Enter fullscreen mode Exit fullscreen mode

Suppose you have:

export function formatDate(date: Date) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

You want other developers to install your package:

npm install my-utils
Enter fullscreen mode Exit fullscreen mode

Now your build process has different requirements.

You may need:

  • JavaScript output
  • TypeScript declarations
  • different module formats
  • package metadata
  • optimized output

This is where tsdown comes into the Vite+ ecosystem.

You can use:

vp pack
Enter fullscreen mode Exit fullscreen mode

to package a library.

The important distinction is:

Application
    ↓
vp build

Library
    ↓
vp pack
Enter fullscreen mode Exit fullscreen mode

The two workflows have different goals.


5. Oxlint — Linting

Now let's talk about code quality.

Imagine someone writes:

const user = getUser();

console.log(user);

if (user) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

The code might work.

But there may be problems:

  • unused variables
  • suspicious patterns
  • accidental bugs
  • inconsistent code
  • practices your team doesn't allow

A linter looks for these kinds of issues.

Vite+ uses Oxlint for linting.

You can think of it as:

Your code
   ↓
Oxlint
   ↓
Potential problems
Enter fullscreen mode Exit fullscreen mode

For example:

vp check
Enter fullscreen mode Exit fullscreen mode

can include linting as part of the overall project check.

Why another linter?

You might be thinking:

"But we already have ESLint."

Yes.

ESLint is still widely used and has a huge ecosystem.

Oxlint takes a different approach and focuses heavily on performance.

It is part of the broader Oxc toolchain and is written in Rust.

For Vite+, the important idea is not:

"ESLint is bad."

It's:

"What if common development tooling could be extremely fast and integrated into one toolchain?"

That's the philosophy behind choosing tools such as Oxlint.


6. Oxfmt — Formatting

Linting and formatting are related, but they aren't the same thing.

A linter asks:

"Is there something potentially wrong with this code?"

A formatter asks:

"Can we make the code follow a consistent style?"

For example, these are functionally similar:

const user={name:"John"};
Enter fullscreen mode Exit fullscreen mode

and:

const user = {
  name: "John",
};
Enter fullscreen mode Exit fullscreen mode

But most teams want everyone to use the same formatting rules.

That's where Oxfmt comes in.

You can think of it as the formatting part of the workflow:

Source code
    ↓
Oxfmt
    ↓
Consistent formatting
Enter fullscreen mode Exit fullscreen mode

Again, this is similar to what developers have traditionally used Prettier for.


Linting vs formatting

If you're new to frontend development, this distinction is worth remembering.

Formatting

"Make the code look consistent."

Example:

const name="John"
Enter fullscreen mode Exit fullscreen mode

becomes:

const name = "John";
Enter fullscreen mode Exit fullscreen mode

Linting

"Look for patterns that might be problematic."

For example:

const unusedVariable = 123;
Enter fullscreen mode Exit fullscreen mode

A linter can tell you:

unusedVariable is never used
Enter fullscreen mode Exit fullscreen mode

So:

Oxfmt  → How the code looks

Oxlint → Potential problems in the code
Enter fullscreen mode Exit fullscreen mode

Both can be part of:

vp check
Enter fullscreen mode Exit fullscreen mode

7. Vite Task — Running tasks

Now we get to a part that becomes more interesting as your project grows.

Most projects have tasks.

For example:

build
test
lint
typecheck
Enter fullscreen mode Exit fullscreen mode

You might define them in package.json:

{
  "scripts": {
    "build": "...",
    "test": "...",
    "lint": "..."
  }
}
Enter fullscreen mode Exit fullscreen mode

For a small project, that's enough.

But imagine a monorepo with:

apps/
  web/
  admin/

packages/
  ui/
  auth/
  utils/
Enter fullscreen mode Exit fullscreen mode

Now tasks have relationships.

For example:

ui
 ↓
web
Enter fullscreen mode Exit fullscreen mode

If the UI package changes, the web application may need to be rebuilt.

This is where a task runner becomes useful.

Vite+ includes Vite Task for task execution and caching.


Task dependencies

Let's make this concrete.

Imagine:

packages/ui
Enter fullscreen mode Exit fullscreen mode

is used by:

apps/web
Enter fullscreen mode Exit fullscreen mode

You change:

packages/ui/Button.tsx
Enter fullscreen mode Exit fullscreen mode

The dependency graph is:

ui
 ↓
web
Enter fullscreen mode Exit fullscreen mode

A smart task runner can understand:

"The web application depends on UI, so the web build may need to run."

But suppose another package didn't change:

packages/utils
Enter fullscreen mode Exit fullscreen mode

If nothing relevant changed there, rebuilding everything may be unnecessary.

That's where task graphs and caching become useful.


Caching

Caching sounds complicated, but the basic idea is very simple.

Imagine you run:

vp run build
Enter fullscreen mode Exit fullscreen mode

The build takes:

30 seconds
Enter fullscreen mode Exit fullscreen mode

You run it again without changing anything.

Why should you spend another 30 seconds doing exactly the same work?

A cache can remember the previous result.

Conceptually:

First run:

Source
  ↓
Build
  ↓
Result
  ↓
Cache
Enter fullscreen mode Exit fullscreen mode

Then:

Second run:

Source
  ↓
Anything relevant changed?
  ↓
No
  ↓
Reuse result
Enter fullscreen mode Exit fullscreen mode

This becomes particularly valuable in large repositories and CI.

We'll go much deeper into this in Chapter 4.


8. Runtime and package management

There's another part of the developer experience that is easy to overlook:

the environment itself.

A project might expect:

Node.js 22
pnpm
Enter fullscreen mode Exit fullscreen mode

while another project expects:

Node.js 20
npm
Enter fullscreen mode Exit fullscreen mode

Vite+ also provides commands and workflows for managing the runtime and package manager environment.

For example:

vp env
Enter fullscreen mode Exit fullscreen mode

can be used as part of this workflow.

The goal is to make the environment used by the project more explicit and reproducible.

This matters because:

"Works on my machine."

is one of the oldest problems in software development.


Putting the pieces together

Now we can see what sits behind the simple vp command.

                         Vite+
                           |
        +------------------+------------------+
        |                  |                  |
    Development         Quality            Testing
        |                  |                  |
       Vite         Oxlint + Oxfmt         Vitest
        |
     Building
        |
    Rolldown

        |
    Libraries
        |
     tsdown

        |
      Tasks
        |
   Vite Task
Enter fullscreen mode Exit fullscreen mode

Instead of learning every tool separately on day one, you can interact with them through a common workflow.

For example:

vp dev
Enter fullscreen mode Exit fullscreen mode

→ development

vp test
Enter fullscreen mode Exit fullscreen mode

→ testing

vp check
Enter fullscreen mode Exit fullscreen mode

→ code quality

vp build
Enter fullscreen mode Exit fullscreen mode

→ production build

vp pack
Enter fullscreen mode Exit fullscreen mode

→ library packaging

vp run
Enter fullscreen mode Exit fullscreen mode

→ project tasks


But should you care which tool is underneath?

Yes.

Even though Vite+ gives you a unified interface, you shouldn't treat it as magic.

If something goes wrong with your tests, knowing that Vite+ uses Vitest helps you investigate.

If your build has an issue, understanding Vite and Rolldown helps.

If linting reports something unexpected, knowing that Oxlint is involved gives you a direction for debugging.

This is especially important for senior developers.

A good abstraction hides unnecessary complexity.

It shouldn't hide useful knowledge.


The important mental model

Don't think:

Vite+ = one giant replacement for everything
Enter fullscreen mode Exit fullscreen mode

Think:

Vite+ = an integrated workflow

             ↓

     +-------+-------+
     |       |       |
    Vite   Vitest  Oxlint
     |       |       |
 Rolldown  Tests   Oxfmt
     |
   tsdown
     |
 Vite Task
Enter fullscreen mode Exit fullscreen mode

Each component has a job.

Vite+ connects those components.


What we've learned

At this point, you don't need to remember every detail.

Just remember this:

Tool Simple explanation
Vite Develop and build web applications
Vitest Test your code
Rolldown Bundle your application
tsdown Package libraries
Oxlint Find potential code problems
Oxfmt Format your code
Vite Task Run tasks and reuse cached results

And Vite+ provides the common workflow around them.


One last question

Now that we know what's inside Vite+, there's still a practical question:

What does using it actually feel like?

It's one thing to read:

vp dev
vp test
vp check
vp build
Enter fullscreen mode Exit fullscreen mode

It's another thing to create a project and use those commands yourself.

So in the next chapter, we'll stop talking about the pieces individually.

We'll build something.

We'll look at:

Create a project
      ↓
Install dependencies
      ↓
Start development
      ↓
Write code
      ↓
Run tests
      ↓
Check the project
      ↓
Build for production
Enter fullscreen mode Exit fullscreen mode

That's where Vite+ starts becoming something you can actually use rather than just something you understand.

Next chapter: Vite+ in Practice — From Your First Project to Production

Top comments (0)