Vite or Webpack? Why not both?

Vite or Webpack? Why not both?

My journey of increasing the development productivity of the entire team

·

4 min read

Featured on Hashnode

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:

  1. Vite failed to work with existing env variables.

  2. Vite failed to process some old npm packages that had no new versions.

  3. Vite failed to process imports using "require".

  4. Our Webpack config had a custom definition of import "alias" so Vite didn't know how to process them.

  5. 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!

WebpackVite
Dev Server start time1:30 min20 sec
HMR refresh time5-10 sec (sometimes stuck)0 sec (instant refresh!)
Dev experiencePoor, slow, and annoyingVery 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.