🐝 Tjoskar's Blog
I write about stuff, mostly for myself
Write your own storybook with vite 🏎️
TL;DR: Use the right tool for the work, and if you can’t find the tool, do not be afraid to create it. It is sometimes easier than you think and you can learn a lot. You can see a demo of our Storybook-ish implementation in Vite here.
Storybook is a fantastic tool. It helps frontend developers create components in isolation and test edge cases that can be hard to set up in a larger application. It has a huge collection of plugins and a rich feature set. You can do almost anything in Storybook, in any framework.
We have been using Storybook at my company for several years now. We were super happy with it — at first. But as our number of components grew and our build steps required a more complex setup, it became more cumbersome to work with.
Some of our pain points:
- In a new installation of Storybook (
npx sb init), we get:- 38,000 new lines in
package-lock.json - Ten new dev dependencies
- Ten deprecated warnings during the installation
- 38,000 new lines in
- It could take over a minute to start Storybook.
- If you need to update any Babel/Webpack config for Storybook, it could take hours to understand what file you need to change.
- Storybook makes breaking changes from time to time that can be very time-consuming to fix.
- Storybook supports so many frameworks and plugins that the configuration can be tough to understand.
- It can be hard to customize.
So we asked ourselves: Do we need everything Storybook provides? Don’t we just need an easy way to visualize our components?
So what do we need:
- An easy way to document our components
- It should be fast, easy, and fun to use
- We only need to support React for now
- Easy to extend
So we need a dev server that automatically finds our story files and renders them. Something like:
- Find all
*.story.tsxand*.story.mdfiles - Add a link to a menu in a web app for every file
- When the user clicks on a link, lazy load the file and render the story
It doesn’t need to be more complicated than that. It turned out that Vite has support for importing glob patterns, which solves 1.
We can then just pick the result and build a menu. Something like:
const modules = import.meta.glob("./**/*.story.tsx");
const menu = Object.entries(modules).map(([path, loader]) => ({
title: convertPathToTitle(path),
loader,
}));
And when the user clicks the link, we just lazy load the component.
We ended up creating a tool called Toybox (you can see a demo here).
If you want to try it out without setting up GitHub’s npm registry, you can
install it with: npm i @tjoskar/toybox
Or just clone: https://github.com/kivra/toybox and hit npm start.
We have been using it for the last 6 months and are very happy with the result. Toybox is quite specific to our company right now, so it might not fit your needs. The purpose of open-sourcing Toybox at this stage is to demonstrate a solution and maybe give some inspiration to you. Happy hacking.
P.S. Vite is a huge cornerstone in this project. We would not have been successful without it.