Storybook Performance: Vite vs Webpack
We benchmarked both builders to see which is faster.
Storybook is the industry-standard UI component workshop. Thousands of application and design system teams worldwide spend most of their day working inside Storybookโbuilding, documenting, and testing their UI components. Therefore, Storybook needs to run as fast as possible, so it does not slow down their workflow.
Storybook's performance when first booting up or rebuilding a changed file largely depends on how it bundles up the stories and components. Optimizing the build process offers lots of opportunities for performance gains in Storybook. Improvements for Webpack and Vite builders are part of this larger ongoing optimization effort.
This article looks at options to help you get the quickest development experience possible today. We'll examine the impact of upgrading to Webpack 5, enabling features such as code-splitting or lazy compilation and finally switching to the Vite builder. Storybook is committed to first-class support of Vite projects, and getting a baseline of our performance is the first step towards further optimization.
Storybook builders
Storybook is powered by builders such as Webpack, which process and bundle up your codeโJavascript, TypeScript, CSS, MDX, and even framework-specific modules like Vue or Svelte SFCs.
Currently, Webpack is Storybook's default builder. Storybook uses Webpack to compile its own UI (the sidebar, panels, buttons, etc.) and the preview (your stories and documentation pages). With Storybook 6.4 and above, it's possible to switch to @storybook/builder-vite to build the preview using Vite instead of Webpack.
Storybook Vite Builder
Vite is a next-gen build tool that aims to provide a faster and leaner development experience. Instead of bundling up your entire project into one or more chunks, it serves individual ES modules to the browser during development. This allows it to start up nearly instantly. Then when you update your code, hot module replacement (HMR) only needs to replace one small file rather than rebundle the entire app, making rebuilds lightning quick.
When using the Storybook Vite Builder, you'll be able to use the same Vite plugins and configuration as your app and continue to take advantage of the Storybook addon ecosystem.
So, with Vite promising such excellent performance, is Webpack obsolete? Well, hold on, the Storybook team has been working hard to improve Webpack performance too. They've introduced features like lazy compilation to speed up development performance and an on-demand architecture to reduce initial load times by leveraging code-splitting.
Let's find out if these changes are enough to match the performance of Vite in a real-world Storybook project.
Benchmarking Storybook performance using IBM Carbon Design System
To compare the performance of these two builders, I chose to run benchmarks against IBMโs Carbon Design System. Carbon has a relatively large Storybook, with over 100 React components and 250 stories using a mix of CSF and MDX format. Carbon uses Webpack 5 but not the lazy compilation or code-splitting features. Its configuration is not tightly coupled to Webpack, allowing for a reasonably straightforward migration to the Vite Builder.
This is just one example project, and these results might be different from what you would see in your own project. Performance is a complex topic which can be affected by many factors, but the results in the Carbon project illustrate some interesting differences between Storybook builder options.
Methodology
Before digging into the results, let me explain how I ran these benchmarks. I used @storybook/bench to get a complete picture of the performance differences between builders. It measures the total time for the dev server to start up and render a story in the browser, the time it takes to create a production build, and the time it takes for a browser to render the first story for a published Storybook. I also calculated the total time between editing a file and the story re-rendering in the browser using HMR.
I took the average of five samples on my 2019 Intel Macbook Pro for each of these times. I compared the results of five different Storybook builder configurations:
- Webpack 4
- Webpack 5
- Webpack 5 LC/CS (lazy compilation & code-splitting enabled)
- Vite
- Vite CS (code-splitting enabled)
Results
There are two different ways that Storybook can build your app. ย When you are working on it during development, you have to wait for the storybook dev server to start and open a browser with your stories. When youโre finished, Storybook runs a production build so you can run tests in CI and publish to the web. ย Storybook also rebuilds your story while you are working on it each time you save, so we will look at how long that takes, as well.
Development (cold start)
The first scenario we'll examine is the cold start of the dev server. This is how long you wait between the first time you run start-storybook
and the story loading up in your browser.
The Carbon project with its default configuration (Webpack 5 without code-splitting or lazy compilation) takes 61 seconds to start the dev server and render a story in the browser, about the same time as it takes Webpack 4. However, enabling lazy compilation cuts that time in half to 30 seconds.
Vite is meant to be lightning-quick, but surprisingly it was slower on the first page load. What happened? Remember that Vite sends each module to the browser unbundled, so even though the dev server started up quickly, the browser needed more time to download and process all those requests.
For comparison, Webpack sends between 16 and 33 assets to the browser, and Vite sends a whopping 1,060 if code-splitting is not enabled.
Enabling code-splitting (storyStoreV7) drastically reduces that number to 250 and we see that the speed improves, though startup was still slightly slower than Webpack 5 with lazy compilation enabled.
Development with cache (Warm Start)
After the first run, Storybook caches some of the build artifacts, so the subsequent starts are faster. The build times we see here are indeed faster across the board, and the same pattern applies. Webpack 5 with lazy compilation takes the cake, at 11 seconds before the first story loads, followed closely by Vite with ย code-splitting taking 15 seconds. The baseline Webpack 4 and Webpack 5 configs took nearly half a minute.
Production build time
To publish your Storybook online, you need to build it as a static web application using build-storybook
. Unlike local development, production builds do not require HMR. Therefore, instead of serving individual modules, Vite bundles everything up, similar to Webpack. Under the hood, it uses Rollup with an opinionated configuration for this task.
Here too, we find that Vite takes a little longer than Webpack to bundle the assets.
Production load size and time
Vite uses Rollup to perform a more aggressive dead-code elimination (tree shaking) than Webpack, which is why it takes longer to create a production build. However, the trade-off is that it generates smaller bundles, as seen in the graph below.
Generally, this means that Storybooks bundled for production by Vite will load up slightly faster for the end-user and require less bandwidth than those generated with the standard Webpack 4 or 5 configurations.
Note that lazy compilation is a development mode only feature, but the Webpack 5 LC/CS build also uses code-splitting, which explains the smaller request size seen above. Also keep in mind that while code-splitting allows the first page to load more quickly, navigating to other stories may take slightly longer because more javascript is requested and downloaded each time.
Rebuild time (Hot Module Reloading)
So far, things aren't looking that great for Vite. Compared to Webpack 5 with lazy compilation, Vite has a slightly slower dev startup time and somewhat longer production build time even with code-splitting enabled.
But one of the big reasons developers love Vite is the near-instant feedback loop between saving a file and seeing your changes in the browser. This is why it serves files unbundled in development, after all. Not surprisingly, this is where Vite really shines. Changes to React components took only half a second to appear in the browser, whereas Webpack took up to three and a half seconds.
Lazy compilation for Webpack cuts down refresh time to only one second, but that's still double that of Vite. These may seem like small numbers, but they add up to make a big difference. ย Your changes appear to happen instantly when using Vite, allowing you to keep your train of thought and iterate rapidly while building components.
Takeaways
Vite has lightning-quick rebuild times, but you'll have to enable the code-splitting feature to get the full benefits and avoid slow first-page load times for larger projects.
// .storybook/main.js
module.exports = {
stories: [],
addons: ['@storybook/addon-essentials'],
features: {
storyStoreV7: true,
},
core: { builder: "@storybook/builder-vite" },
};
Don't expect faster production build times by switching to the Vite Builder, but you'll likely get smaller production bundles that speed up load times for published Storybooks.
If your app relies heavily on Webpack, upgrading to Webpack 5 and enabling code-splitting and lazy compilation can be a quick win. You can expect startup and rebuild times comparable to Vite in most cases.
The future of Storybook with Vite
Storybook's support for Vite is continually improving. The Vite builder started as a community project and is maintained by Ian VanSchooten (me), Josh Wooding, and Eirik Sletteberg. It was recently moved under the @storybook
org to improve Vite support in Storybook.
The Storybook team has already started exploring pre-bundling the manager so that you won't need to install Webpack at all when using the Vite Builder. In the future, using HTTP/3 should help reduce the cost of Vite sending so many modules to the browser at once, and weโll be looking for other ways to improve performance as well. ย In collecting the data for this blog post, we already found one improvement that sped up our example build times by over 50%.
I'd encourage you to try the 6.5 beta release of Storybook and experiment with builder features to make your Storybook faster. Every project is different, and what works well in one project may not in another. ย To try out Vite, use npm create vite
and the npx sb@next init
command to set up Storybook in a new project. For existing projects that use Webpack, check out the configuration guide to take advantage of Webpack 5 perf improvements. Or migrate to Vite using the installation instructions.
We would love for you to get involved in the project. Drop by the #vite channel in Storybook Discord to report issues or share ideas for improvement. Iโll also be happy to answer any questions about this benchmarking project. If these results are surprising, or if they match up with your own experience, let us know on Twitter.