Setting up Storybook in TypeScript/Sass environment with Webpack 4
Storybook is a wonderful tool for developing UI components. It allows you to see your components in all their supported states by providing proper data to them. It supports quite a few libraries (Angular, Vue, React, and others). We have been using it for quite some time in our shared UI elements packages without issues. However, when we tried to add it to our Moje VZP Single Page App it was not exactly easy to make it work. In this article, we will describe the process of setting up the Storybook integration and the issues we encountered.
The previous post on this blog goes into great detail about the Moje VZP project technology stack, so let’s just point out the relevant information here.
The recommended way to set Storybook up is by using their CLI utility — @storybook/cli. While this utility works well for “standard” projects, it has two issues that prevented us from using it:
Because of those two reasons we have to set Storybook up manually by loosely following the slow start guide.
The first step is to install Storybook itself by running
yarn add -D @storybook/react @types/storybook__react. This adds the React version of Storybook and TypeScript type definitions for it (this allows us to write the stories in TypeScript, more on that later on).
Next, we add a script for starting the Storybook to our
Finally, we create the config file
.storybook/config.js in our app's root:
The file tells Storybook that the story files are located inside the
app folder and their names end in
.stories.tsx. The reason for not using the default file is that we think it is more clear when the stories are right next to "their" components rather than in some arbitrary folder. So for example for the Currency component specified in
Currency.tsx there is now
Currency.stories.tsx file with its stories right next to it.
Notice that the stories will be written in TypeScript. In a project with components written in TypeScript as well this makes writing the stories much easier — the prop types are checked therefore you are unlikely to pass nonsensical data to the component. This is especially useful with components that display complex data.
Making TypeScript work
Unfortunately, Storybook does not support TypeScript out of the box. There is a guide for setting it up, however we ran into some issues using it.
The guide states that we need to extend the Storybook Webpack config in order to use TypeScript files. However, there are two issues with this:
- the current stable version of Storybook (3) uses Webpack 3, whereas we use Webpack 4
- the guide suggests using
awesome-typescript-loader, whereas we use
These two facts together mean that if we wanted to use
ts-loader we already use in bundling our app (which is only compatible with Webpack 4), we would need to have two versions of
ts-loader – one for Webpack 4 for bundling our app and one for Webpack 3 to use with Storybook. This is of course not desirable. Fortunately, there is an alpha version of Storybook 4 available that uses Webpack 4.
Therefore the first step to make the TypeScript work is to install the alpha version —
yarn add -D @storybook/react@alpha. Next, we can create the
As for the
tsconfig.test.json, it extends our "normal"
tsconfig.json and overrides some settings needed by Storybook (and Jest as well, hence the name
As we can see, it uses the extend functionality to override our standard configuration. It changes is the module system and tells TypeScript to compile JSX (our base config uses the
esnext module system and does not compile JSX). This makes TypeScript output files Storybook can use.
This is all it takes to make TypeScript work (tested with
Making styles work
As stated earlier, the styles for our app are written in Sass. This again requires additional configuration in Storybook.
First, we need to make sure Storybook knows how to process
.scss files by updating
As we can see, the setup is similar to the TypeScript one — we add appropriate loaders and add the extension. Note that we did not add loader configuration for CSS as Storybook supports it by default and adding it here would cause errors. The
getSassLoaderConfig function is used by our standard Webpack config as well and looks like this:
The last thing to do is to include the styles in the stories. This can be done for all the stories at once by updating the
.storybook/config.js with an import of the styles' main file:
Writing components properly
Having made Storybook work with our stack, the last thing is to write the stories themselves. There is a guide on how to do it so we will not go into detail here.
The important thing is that you must write your components in a way that makes using them in Storybook possible. For us this meant splitting components using Redux into two as mocking Redux would be impractical.
HotNews as an example:
This component downloads some news data and displays it. This works well, but we cannot write stories for it because it is connected to Redux which is not available in Storybook. The solution is to split
HotNewsList into two components:
HotNews component no longer handles the data obtaining, just the data display. Thanks to this change it can now be used in Storybook, we just provide it the relevant data. There is no need for the complication of mocking Redux.
The logic behind getting the data from server and connecting to Redux was moved to
HotNewsContainer which uses the
HotNews internally and passes it the data from the server. Also, wherever we previously used
HotNews in our app, we now must use
In this article we’ve shown a way to make Storybook work in an environment with TypeScript, Webpack 4 and Sass. We also discussed how to write components in a way suitable for Storybook. Hopefully, this will inspire you, to try Storybook yourself, it really is worth it!