Speed up E2E tests for Vite-based apps
Tags: vite, rollup, devex
Published: 2022-03-15 14:40:26

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.

![An overall idea of how Rollup and Vite work, with a benefit for the developer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6xkzyzdocufkqc6dhpgb.jpg)
 

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?](https://dev.to/noriste/migrating-a-150k-loc-codebase-to-vite-and-esbuild-is-it-worthwhile-part-3-3-339k) 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.

![The same overall idea of how Rollup and Vite work, with a clear disadvantage for Cypress](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2blsf77lpas131l91qu2.jpg)
 

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](https://vitejs.dev/guide/why.html#why-not-bundle-with-esbuild) and allows [enabling the Rollup watcher](https://vitejs.dev/config/#build-watch). The goal is
1. Creating a custom Vite configuration to use the Rollup watcher
2. Starting a web-server to serve the bundled-by-Rollup application
3. 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](https://www.reddit.com/r/vuejs/comments/o2p6l7/how_can_i_speed_build_vite_watch_build_even_futher/) by [@securisec](https://twitter.com/securisec)).

```ts
// 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
```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](https://vitejs.dev/guide/static-deploy.html#testing-the-app-locally). Essentially, we need to launch both `vite build` and `vite preview` simultaneously.

These are the scripts I created in our package.json
```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
1. Load the Vite config and change the minimum settings
2. Use a different preview port

I then transformed the `vite.config.js` file to expose the configuration generator
```diff
-export default defineConfig(config => {
+export default defineConfig(generateConfig)
+export function generateConfig(config) {
```
and `rollup.config.ts` now does only the following
```ts
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](https://www.npmjs.com/package/concurrently) and TSC) now is
```json
{
  "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"](https://dev.to/noriste/migrating-a-150k-loc-codebase-to-vite-and-esbuild-why-part-1-3-2idj) 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](https://excalidraw.com/#json=o3dl8F2035piP36pcWJhO,cz759VgJl0mIVkvGA2sdLw) used above.