Skip to content

Migrate from Webpack/Vue CLI to Vite

Migrating to Vue 3 is a great opportunity to upgrade your toolchain to Vite too! You’ll boost your development speed, streamline configurations, and simplify migrating to TypeScript, as Vite supports it out of the box.

This guide will take you step-by-step through refactoring your Vue application from Webpack/Vue CLI to Vite.

Initial Setup: Creating a New Vite Project

Let’s first set up a fresh Vite project as a reference.

In your terminal, navigate to your projects directory and create a Vite project:

Terminal window
npx create-vite my-project
cd my-project

Choose Vue (or your preferred framework) and TypeScript if applicable. Explore the new project structure before proceeding.

To see Vite in action, run:

Terminal window
npm install
npm run dev

Migrating a Vue Project from Vue CLI

If your project is already on Vue 3, simply copy your src directory and any necessary assets like public into the Vite project:

// Original Vue CLI Structure
my-old-vue2-app/
├── src/
├── public/
├── vue.config.js
└── package.json
// New Vite Structure
my-project/
├── src/
├── public/
├── vite.config.js
└── package.json

For Vue 2 (or other frameworks), directly install Vite in your existing project.

Terminal window
npm i -D vite

Most of the Vue CLI configuration is the same as Vite. So you can just copy it over.

Migrating a Project from Webpack

Start by creating an index.html and a vite.config.js.

Your index.html should contain at least this:

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Title</title>
</head>
<body>
<div id="app"></div>
<!-- Update the path to your needs -->
<script type="module" src="/src/main.ts"></script>
</body>
</html>

In Vite, index.html acts as the entry point. If your project has multiple entry points, the next section will help you handle that.

We will now translate Webpack options one by one into the corresponding Vite options.

Entry Point, Mode, and Output

In Webpack, you’d define entry points, mode, and output like this:

webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
mode: "development", // or 'production'
};

Vite automatically handles entry points and mode settings. By default, it uses index.html and outputs builds to dist. The mode is set to development for the dev server and to production for the build.

If you need multiple entry points, or you are a library author, you can define them in vite.config.js like this:

vite.config.js
import { resolve } from "path";
import { defineConfig } from "vite";
export default defineConfig({
build: {
outDir: "dist",
lib: {
entry: resolve(__dirname, "lib/main.js"),
name: "MyLib",
fileName: "my-lib", // Extensions will be added automatically
},
},
});

If you need to change your Vite config depending on the mode, you can pass a function to defineConfig:

vite.config.js
import { resolve } from "path";
export default ({ mode }) => {
return {
// do something with mode
};
};

You can find more details in the official Vite documentation.

Webpack Loaders

Webpack uses loaders to handle file transformations, while Vite relies on ESBuild for most features right out of the box.

Here is a list of loaders you can safely remove from your Webpack configuration:

  • Babel Loader: Vite uses ESBuild for fast transpiling, eliminating the need for Babel.
  • File Loader / URL Loader: Vite automatically handles static assets (e.g., images, SVGs, JSON). More details in the Vite documentation.
  • CSS/Sass/SCSS Loader / Style Loader: Vite offers native support for CSS and preprocessors like Sass/SCSS. Just make sure you have the necessary pre-processor installed. Importing CSS files will automatically add them to the DOM.
  • JSON Loader: JSON imports work out-of-the-box with Vite.

For other specific loaders, you might need a Vite plugin. While I can’t cover all loader types, note that Vite generally handles most use cases Webpack does, with few exceptions.

Static Assets with the public Directory

As previously mentioned, Vite automatically manages asset loading. However, if you need to serve assets directly without importing them, place them in the public directory. Files in this directory are accessible from the root path.

index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- favicon stored as a static asset in the public directory -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Title</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

Dev Server

Both Webpack and Vite offer development servers, but Vite’s is significantly faster, thanks to native ES module support.

webpack.config.js
module.exports = {
devServer: {
contentBase: "./dist",
hot: true,
},
};
vite.config.js
import { defineConfig } from "vite";
export default defineConfig({
server: {
open: true, // automatically opens the browser
hmr: true, // Hot Module Replacement
},
});

Aliases

Webpack and Vite use exactly the same configuration for aliases:

webpack.config.js
const path = require("path");
module.exports = {
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
};
vite.config.js
import { resolve } from "path";
export default {
resolve: {
alias: {
"@": resolve(__dirname, "src"),
},
},
};

Environment Variables

In Webpack, you need to explicitly load environment files (e.g., using dotenv) and pass the variables to your code via the DefinePlugin:

webpack.config.js
const webpack = require("webpack");
require("dotenv").config({ path: "./.env" });
module.exports = {
plugins: [
new webpack.DefinePlugin({
"process.env": JSON.stringify(process.env),
}),
],
};

Vite automatically loads all environment variables prefixed with VITE_ and makes them available under import.meta.env. If you need to use an environment variable without the VITE_ prefix, you can define it manually in your vite.config.js:

vite.config.js
import { defineConfig } from "vite";
export default defineConfig({
define: {
"import.meta.env.ENV_VARIABLE": JSON.stringify(process.env.ENV_VARIABLE),
},
});

See the corresponding official docs for more details.

Custom Code Splitting (chunks)

While Vite automatically splits your code based on dynamic imports, Webpack allows you to manually control code splitting using special comments:

const UserDetails = () =>
import(/* webpackChunkName: "group-user" */ "./UserDetails");
const UserDashboard = () =>
import(/* webpackChunkName: "group-user" */ "./UserDashboard");
const UserProfileEdit = () =>
import(/* webpackChunkName: "group-user" */ "./UserProfileEdit");

This can be done in Vite using the manualChunks option.

vite.config.js
import { defineConfig } from "vite";
export default defineConfig({
build: {
rollupOptions: {
// https://rollupjs.org/guide/en/#outputmanualchunks
output: {
manualChunks: {
"group-user": [
"./src/UserDetails",
"./src/UserDashboard",
"./src/UserProfileEdit",
],
},
},
},
},
});

Framework Integration

To integrate your preferred framework with Vite, add the corresponding plugin to your project. Here’s how you can set it up in your vite.config.js:

vite.config.js
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import react from "@vitejs/plugin-react";
import solid from "vite-plugin-solid";
import svelte from "@sveltejs/vite-plugin-svelte";
export default defineConfig({
plugins: [
vue(), // Replace 'vue()' with the plugin for your framework
],
});

Other Webpack Plugins

Webpack has a vast ecosystem of plugins for various configurations, making it impractical to cover all of them here. However, since Vite uses Rollup under the hood for bundling, you can often find a Rollup plugin that provides the functionality you need. Check out the Rollup plugin repository for available options.

Need Assistance?

If you need help with your migration, feel free to contact me via email or visit the contact page. I offer professional assistance and guidance for migrations at fair rates.