Speeding up Storybook locally by running filtered stories 🚀

08/04/2021

Recently at work, using Storybook locally became really painful. As the team and codebase grow, working on a monorepo using the default Storybook configs means that we were building all our 200+ stories files everytime. This was taking about 1min to build + about 20s to load... 😫

It became really annoying in terms of developer experience so, I spent some time thinking about how to improve it.

Even though Storybook 6.0 is talking about a new exciting feature called "pluggable builders", it doesn't seem to be quite ready yet so, while we wait to be able to eventually swap Webpack for ESBuild, I still wanted to see if something could be done. This is where I came up with the idea of trying to run a single component's stories instead of all them.

Most of the time, when we are using Storybook, we only care about the component we are currently working on, and we don't need to see all other stories. Being able to run only selected stories doesn't seem to be a feature provided by Storybook by default, so I tried to see if there was a simple way to do this, and there is! 🎉

My goal was to have a clear command my teammates and I could use to specify which stories we wanted to run, something like yarn storybook -stories src/components/Nav/Nav.stories.js.

Usually, you define the stories in the main.js config file, under the stories property.

Beforehand, we had the following config:

module.exports = {
  stories: () => [
        '../src/**/*.stories.@(js|mdx|ts|tsx)',
        '../src/components/stories/stylesheets.js',
      ],
  core: {
    builder: 'webpack5',
  },
  addons: [
    ...
  ],

};

This config was running all files matching a certain naming convention and location, as well as a stylesheets file.

To be able to run only a specific file, I changed this to use process.argv to check for the presence of arguments in the command used.

This way, it can detect if the -stories flag is used, and if so, use the 5th argument which is the relative path to the stories file.

const getStories = () => {
  return process.argv[4] === '-stories'
    ? [`../${process.argv[5]}`]
    : [
        '../src/**/*.stories.@(js|mdx|ts|tsx)',
        '../src/components/stories/stylesheets.js',
      ];
};

module.exports = {
  stories: () => getStories(),
  core: {
    builder: 'webpack5',
  },
  addons: [
    ...
  ],

};

This way, we can still run all the stories if we want by running the base command yarn storybook, but we also have the option to run a single component's stories.

Making this change made Storybook build 2x faster!! 🚀

Before:

Preview build time is 1min

After:

Preview build time is 35s

This is a huge improvement in terms of speed of local development and quality of developer experience.

Sometimes, the simplest solutions have the biggest impact. 🙂