Vite vs Webpack

Vite or the Vue CLI: Which One To Choose

As the Vue ecosystem has matured, we’ve been introduced to a number of new technologies. While some developers may have started with just a plain JavaScript file and included Vue on the page, over time using bundlers and command-line interfaces has become more standard when developing Vue applications.

Vue doesn’t force you into any specific decisions on how you handle development or bundling, but the ecosystem is aided by a number of tools such as the Vue CLI and, more recently, Vite js. So should you use Vite or the Vue CLI? When it comes to making that choice, it’s helpful to understand the differences between Vite and Vue CLI.

In this article, we’ll explore Vite vs Vue CLI under the hood so you can make the best choice for your needs.


How does the Vue CLI Work?

The Vue Command Line Interface (CLI) works by creating a wrapper around Webpack to compile your Vue project. But why do we compile it? Before bundlers like Webpack and Rollup, we could just deploy our JavaScript files to a server and include them all on a page. This worked well when our projects were small, but as Vue matured we started using features that required some level of packaging. Single File Components (SFC) and TypeScript both brought the requirement of building our project. That’s where the Vue CLI came in.

The Vue CLI allows us to create and build projects during development and production. The CLI hid the details of the, then complex, configuration of Webpack as well as providing a way to serve our projects during development and in production if necessary. But if we’re going to compare it to Vite, let’s dig a little deeper.

Webpack

As the Webpack website explains, Webpack is a static module bundler. But what does that mean? The main goal of Webpack is to take the assets of your web project and bundle them into a small number of files to be downloaded by the browser. This doesn’t mean that all the files of your project are loaded immediately, but they can be downloaded as needed as well.

While Webpack can bundle non-code assets, it is the bundling of related code where it really shines. You could think of bundling as simply taking all the code files (e.g. JavaScript/TypeScript) and just merging them together, but in fact there is more going on here.

In order to perform the bundling, Webpack follows the imports/require statements in the code to only include the files that are actually needed. In addition, it often does ‘tree-shaking’ which can prune out individual blocks of code (e.g. class, functions) that aren’t actually ever referenced. In this way, Webpack can package your projects in a very efficient way. But if we’re looking at how Vue CLI (with Webpack) compares to Vite, we really should look at what happens at development time.

Webpack During Development

In the Vue CLI, Webpack is used for module bundling. This happens at development time as well. When you are developing a Vue project via the CLI, it instructs Webpack to incrementally build your project and watch for changes so it can package the changed files and replace them in the browser. Because building the package is incremental, it can integrate changes as you are developing a project very quickly. The initial build of the project may be slower (i.e. 3 seconds or more depending on your project size) but once the project is bootstrapped, the incremental changes are incredibly fast (i.e. < 1 second and often under 100ms).


How Does Vite js Work?

If you’re new to Vite, I suggest learning straight from the source, from its creator Evan You, who teaches us about Vite in Vue Mastery’s course Lightning Fast Builds w/ Vite.

If you’ve watched the first lesson from that course (it’s free), you’ll understand how to get started, but before we can compare it to the Vue CLI and Webpack, we need to understand how Vite works.

When you create a basic Vite project (in our case, a Vite project for Vue 3), the index.html file is pretty basic:

📄 index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" 
          href="/vite.svg" />
    <meta name="viewport" 
          content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue</title>
  </head>
  <body>
    <div id="app"></div>
    **<script type="module" src="/src/main.js"></script>**
  </body>
</html>

You’ll notice that this looks similar to how the Vue CLI looks, with one main exception: the script tag uses type="module". Unless you’re using TypeScript, there is no real build step here. The src of the script points at your actual source code file.

When this request comes in, it sends the main.js file to the browser as a native ES module. This means that it does not bundle your code at all. In fact, the source file is just a simple Vue startup file:

📄 main.js

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'

createApp(App).mount('#app') 

What is happening here? Vite is leveraging native ES modules and dynamic ESM modules to allow your code to be injected into the browser as needed. Essentially, each import in your project is forcing the browser to load each payload as it is needed. These imports will be cascading to get all the code you need in a particular case.

This means that during development, while Vite will serve your web site, it is also making this dynamic loading happen (both for new browsers that support it and backfilling it for older browsers).

In addition, Vite is using Hot Module Replacement (HMR) to update changed code while you’re developing your project. This creates the least amount of friction while you’re developing with an almost-instant launch speed to your project.

But how does Vite accomplish this for production builds? Let’s take a look…

Vite and Production

While Vite uses its ability to serve these files during development to speed up that process, Vite itself doesn’t actually package your project. Instead, it relies on a packager called “Rollup” to do the actual bundling.

By using the build command in Vite, it will use rollup to build your project for production:

📄 command-line

> vite build

This will build the project, producing several files (with checksums to break the cache):

📄 command-line

vite v3.0.9 building for production...
✓ 16 modules transformed.
dist/assets/vue.5532db34.svg     0.48 KiB
dist/index.html                  0.44 KiB
dist/assets/index.43cf8108.css   1.26 KiB / gzip: 0.65 KiB
dist/assets/index.3ee41559.js    52.82 KiB / gzip: 21.30 KiB

Much like the Vue CLI, Vite allows you to configure Rollup via the configuration file (with very sane defaults):

📄 vue.config.js

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  build: {
    sourcemap: true,
    outDir: "public/build/"
  }
})

For example, setting the sourcemap option and the outDir, both are passed directly to Rollup configuration. This build option in the vite.config.js file allows you to deeply configure Rollup if you find it necessary.

So, using Vite really is supplying you with two different experiences: a quick, debugging experience at development time, and deferring to Rollup and allowing you to build your projects in the way that you want.

While Vite is using Rollup, Rollup is not required. You could decide to use any bundler that you want instead of Rollup for building your Vue project; you’d just be completely responsible for setting that outside of Vite.


Vite or Vue CLI: Which should I Choose?

There is not a clear-cut answer to the question, Which is better, Vite or Vue CLI?

But I’d like to split it into two different discussions: using it in development and using it in production.

Development Time

The overall experience of the Vue CLI (and Webpack by extension) and Vite can be similar during development. Both incrementally build your project and use Dynamic Module Replacement to replace changed code in your continually running project.

The difference between the two boils down to speed. Webpack is building the project from source and continuing to do incremental builds as you are developing your project.

Vite, on the other hand, is loading your actual code into the browser as needed. This means there is less of a need for sourcemaps as the code running in the browser is the actual code (and files) that you’re working with. This means, for the most part, you’ll find Vite to be a more direct development and debugging experience than Vue CLI. Instead of debugging with the code you’re writing, in Vue CLI, you’ll be debugging the code generated by Webpack (by utilizing the sourcemaps).

Another benefit is that Vite isn’t tied to Vue.js. Vite can be used in different environments: plain JavaScript, React, PReact and SvelteKit. So if you’re working in more than one environment, a single tool can be easier to work with (and configure) for different projects.

Production Time

Rollup is similar to Webpack (and Parcel, another popular bundler) though how they work is a bit different.

Webpack is based on the CommonJS (e.g. cjs) API for managing JavaScript modules. Even though Webpack supports ES Modules, the underlying build system still expects that modules could be dynamically loading (since require() only imports a module when the function is executed).

In contrast, Rollup relies on ES Module support, which means it can do static analysis more easily than Webpack, though this difference is pretty small. Using Rollup, though, requires you have dependencies that support ES Modules. This can create some problems for libraries that do not support ES Modules, but thos libraries are getting rarer these days.


Ultimately, it’s up to you

While I can’t make the decision for you, I hope I’ve laid out the pros and cons of both approaches. I typically use Vite (with Rollup) for new projects, but I haven’t seen enough of a benefit to migrate all my existing Vue CLI projects to Vite, as the effort isn’t worth the change.

At some point, this is unlikely to matter as Evan You has stated that they will converge at some point (e.g. replacing Webpack with Vite inside the CLI). But for now, that hasn’t happened yet and both approaches are well supported.

Download the cheatsheets

Save time and energy with our cheat sheets.