Migrating single-spa monorepo to Vite with minimal changes in PR
Tags: vite, frontend, webdev
Published: 2023-04-22 09:22:21

I have been with webpack for quite a long time, starting with version 3, then 4, and finally 5. It is familiar and incredibly customizable. Nevertheless, when you have to wait about 30 seconds to get your build done and then about 5 seconds for your changes to become interactive, love for webpack slowly vanishes.

Usually there are three ways to deal with this tiring waiting:

1. Optimize webpack to make it faster (e.g. try [lazy compilation](https://webpack.js.org/configuration/experiments/#experimentslazycompilation))
2. Reduce bundle size ([webpack-bundle-analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer) is useful for this)
3. Look for an alternative solution

While I tried the second option, it didn't fully solve the issue. Vite has long been on everybody’s lips, promising quick builds and almost instant HMR. I decided to experiment with our single-spa monorepo and see the results.

**About migration**
There are many migration guides available online, so I won't repeat them here,as they are easy to find. Generally, these are the steps to follow:

1. Install the necessary packages.
2. Introduce an `index.html` file in the root folder.
3. Add the Vite config and customize it for your build.
4. Change the commands to use Vite.

While going through these steps, I encountered following issues in adapting my configs of build into vite:

**Env-variables**
Vite requires all env variables to have the `VITE_ ` prefix, but changing all references would have resulted in a large PR that would be difficult to review. I found a solution in [vite-plugin-environment](https://github.com/ElMassimo/vite-plugin-environment), which allowed me to keep all `process.env` references untouched

**Absolute ts imports**
Many of our imports, like `lib/exampleHook`, were broken after switching to Vite. The issue was resolved just by adding [vite-tsconfig-paths](https://www.npmjs.com/package/vite-tsconfig-paths) and all started working.

**License generation**
Webpack creates license files out-of-the-box, while rollup that is inside vite, doesn’t. This can be fixed by [rollup-plugin-license](https://www.npmjs.com/package/rollup-plugin-license), it has a lot of customization, but in the end, I found the text files not so fancy as webpack. Maybe I just did not get it right.

**Npm-package, that is not a module**
We used [single-spa-html](https://github.com/single-spa/single-spa-html) module for displaying some static errors, that was not a module, but a IIFE inside. I had to fork it and to put it inside my repo, changing it into a module.

**Single-spa complications**
When developing locally, we loaded some scripts from test environment, that are transpiled into commonjs and that was a complication, as local modules should have been handled by vite, whereas those modules had to be registered via System Js. It lead to ugly if else that I won’t even add here.

Another issue was that we had a module, that was used by all others externally. And again, the modules from test env needed commonjs version of sdk, while local needed es6 version, which also lead to pre-building it and serving from dist. I tried various configs, but didn’t succeed — vite was unstable when loading it and that sometimes affected the performance of the whole application.

Results with vite actually working:

- Local startup was about 30s, with vite about 3–4 seconds
- CI build time decreased by 30 seconds
- HMR was almost instant

**Conclusion**
Vite is great, it really is a silver bullet for apps that take a long time building. However, if you have already codebase with customizations, the migration can be painful. As vite was working unstable with our external module and this issue required a lot of investigation, we decided to postpone the migration for now. Hopefully, after some other refactoring, we will get back to it.