Vite or Webpack? Why not both?
My journey of increasing the development productivity of the entire team
Introduction
If you are working on a complex web application that uses React and Webpack, you have probably thought about ditching Webpack completely more than once because of bugs and slowness. This tutorial will explain the easiest way to solve this problem.
What is the problem with Webpack?
Webpack is slow!
Here are some issues our dev team reported:
Slow Dev server start time, about 1:30 min (and was constantly increasing).
Slow HMR refresh time, around 5-10 seconds (sometimes also got stuck).
General development experience is annoying and not productive.
Available alternatives
Short research will reveal to you that there are much better alternatives out there, and the most popular one is Vite (vitejs.dev)
Vite is a fantastic tool. It has none of the problems that Webpack has, But it is difficult to completely replace Webpack due to existing production customizations and the fear of the development team that it might not work well.
So my solution to this problem was to add Vite to work alongside Webpack as an alternative instead of replacing it entirely.
The problems I encountered and the solutions
I have found no good tutorials about how to integrate Vite into an existing project, so luckily for you, I spent a tremendous amount of research hours to find a good solution to all the issues, so you won't need to.
The first step you need to do is to add vite and @vitejs/plugin-react packages to your existing project and create a vite.config.js
(at the root of the project).
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
type: "module",
plugins: [],
optimizeDeps: {
include: ["react"],
},
build: {
commonjsOptions: {
include: [/node_modules/],
},
},
});
Once I ran the vite
command for the first time, I got a big list of errors
Here are the main reasons for that:
Vite failed to work with existing env variables.
Vite failed to process some old npm packages that had no new versions.
Vite failed to process imports using "require".
Our Webpack config had a custom definition of import "alias" so Vite didn't know how to process them.
Our Webpack config defined custom proxy settings.
1. Environment variables solution:
Our web application used the env variables in a CRA (Create React App) way
Example: process.env.REACT_APP_VARIABLE_NAME
But Vite defines a different way to handle env variables
Like this: import.meta.env.VARIABLE_NAME
So I was looking for a way to tell Vite to define the env variable differently. I have found a good plugin that does precisely that vite-plugin-environment
By adding this plugin to the config file you solve this issue
plugins: [
...
EnvironmentPlugin("all"),
]
2. Old packages solution:
This is one of the biggest problems of Vite. He fails to process old unmaintained packages. We had a few in the App, and replacing them was not an option.
So the solution is to replace the content of the package with different content during the build.
To do this, I used a plugin vite-plugin-resolve that allows you to specify the package name and mock it with any other content. In my case, the packages I needed to fix were not used in most of the flows of the UI, so I just replaced them with empty content.
For example: we used a package named react-codemirror2
that exports a component named UnControlled
. I just replaced the content with an empty object and this resolves the issues with this package.
plugins: [
...
resolve({ "react-codemirror2": `
const UnControlled = {};
export {
UnControlled,
}`
}
]
3. imports using "require" solution
Also in this case the solution is to use a plugin vite-plugin-require that will solve the issue.
Tip: it is better to provide detailed names of the component that are using require
imports.
For example: configure the plugin to process CostViewerDialog.tsx
file only.
plugins: [
...
vitePluginRequire({fileRegex: /(CostViewerDialog.tsx)$/}),
]
4. Custom alias solution
Vite has native support for import alias
For example: to define an alias for a path ./src/Components
as Components
resolve: {
alias: {
Components: path.resolve(__dirname, "./src/Components"),
},
},
5. Proxy settings solution
Vite has native support for defining proxy settings
For example: redirect all local server calls to port 8090
server: {
port: 3000,
proxy: {
"^/api/v1/.*": "http://localhost:8090",
},
},
Additional tips
To allow debugging add the following setting to the vite.config.js
file
esbuild: {
sourcemap: true,
},
To allow type checking, you can use the vite-plugin-checker plugin.
Results
The results were amazing!
Webpack | Vite | |
Dev Server start time | 1:30 min | 20 sec |
HMR refresh time | 5-10 sec (sometimes stuck) | 0 sec (instant refresh!) |
Dev experience | Poor, slow, and annoying | Very fast and productive |
Summary
Moving to Vite is difficult, but the potential benefits are substantial. A few months after adding Vite, our dev team reported a significant increase in productivity, allowing them to create better products faster. If you're looking to make the switch but don't know where to start, I'm here to help. Reach out to me, and I'll guide you through the process, ensuring a smooth transition.