Before Vite we used long bundling waitings, and applications loaded instantly in the browser. Now, the bundling waitings are over, and apps load slower. You can get an idea of what is changed in the following image.
The overall Developer's experience is excellent (you can find some benchmarks in my Migrating a 150K LOC codebase to Vite and ESBuild: is it worthwhile? article) because apps and HMR are way faster, but what about who needs to load the app more than once? Like the Cypress' E2E tests, for example. Cypress reloads the app before every test. Hence is going to pay the cost of loading the app multiple times, something like the image.
Is there a way to fix it? Can we have the best from using Vite and from using Rollup simultaneously? The answer is yes, and we can do that for free!
Enabling Rollup watcher inside Vite
Vite leverages Rollup for the production build and allows enabling the Rollup watcher. The goal is
- Creating a custom Vite configuration to use the Rollup watcher
- Starting a web-server to serve the bundled-by-Rollup application
- Avoiding to interfere with the served-by-Vite application (so both the application can run simultaneously)
1. Creating a custom Vite configuration to use the Rollup watcher
The following is the bare minimum settings enabling the Rollup watcher and also speed it up as much as possible (thanks to this Reddit post by @securisec).
// rollup.config.ts
export default defineConfig(config => {
const { mode } = config
return {
// ... Rest of the configuration...
build: {
// Enable Rollup watcher @see https://vitejs.dev/config/#build-watch
watch: {},
// Opt for the fastest build
target: 'esnext',
minify: false,
rollupOptions: { ...config.build.rollupOptions, treeshake: false },
outDir: './dist-rollup/',
},
}
})
Please note that since the Rollup-specific configuration is inside the build
object, we must run vite build
to start Rollup. The following is the script I created in our package.json
{
"rollup:dev": "yarn vite build --config rollup.config.ts",
}
2. Starting a web-server to serve the bundled-by-Rollup application
Please remember that enabling the Rollup watcher does not mean starting a we-server serving the generated assets.
Here Vite comes in handy with its preview command. Essentially, we need to launch both vite build
and vite preview
simultaneously.
These are the scripts I created in our package.json
{
"rollup:start": "yarn rollup:dev & yarn rollup:preview",
"rollup:dev": "yarn vite build --config rollup.config.ts",
"rollup:preview": "yarn vite preview --config rollup.config.ts",
}
rollup:start
is now the reference script to launch Rollup.
3. Avoiding to interfere with the served-by-Vite application (so both the application can run simultaneously)
To achieve that, I need to
- Load the Vite config and change the minimum settings
- Use a different preview port
I then transformed the vite.config.js
file to expose the configuration generator
-export default defineConfig(config => {
+export default defineConfig(generateConfig)
+export function generateConfig(config) {
and rollup.config.ts
now does only the following
import { generateConfig } from './vite.config'
export default defineConfig(({ mode }) => {
const config: UserConfig = generateConfig({ mode })
config.preview = {
port: 5004,
}
config.build = {
// Enable Rollup watcher @see https://vitejs.dev/config/#build-watch
watch: {},
// Opt for the fastest build
target: 'esnext',
minify: false,
rollupOptions: { ...config.build.rollupOptions, treeshake: false },
outDir: './dist-rollup/',
}
return config
})
That's all, you can now choose between Vite and Rollup as your development tool (or use both simultaneously). Our package.json file (we use concurrently and TSC) now is
{
"vite:start": "concurrently --names \"VITE,TSC\" -c \"bgMagenta.bold,bgBlue.bold\" \"yarn vite:dev\" \"yarn ts:watch\"",
"vite:dev": "yarn vite",
"vite:build": "vite build",
"vite:build:preview": "vite preview",
"vite:clearcache": "rimraf ./node_modules/.vite",
"________________________________________________________________________________________": "",
"rollup:start": "yarn rollup:dev & yarn rollup:preview",
"rollup:dev": "yarn vite build --config rollup.config.ts",
"rollup:preview": "yarn vite preview --config rollup.config.ts",
}
FAQ
What's the threshold? When do you start gaining the advantages of using Rollup instead of Vite?
Based on my empiric benchmarks, if you reload the same app more than three times, Rollup gets you to save time.
Can I use both Vite and Rollup simultaneously?
Yes, they are not mutually exclusive, and by using a different port, you can access both web applications.
Would disable Rollup sourcemap
increase speed?
Based on my benchmarks, no. Anyway, I disabled it in our main application due to a "JS heap out of memory" error.
How can I migrate my application to Vite?
I shared our migration experience in the "Migrating a 150K LOC codebase to Vite and ESBuild" article.
If you follow a similar pattern or have similar solutions, please drop a line in the comments with your feedback.
p.s. this is the link to the Excalidraw file used above.
Top comments (0)