Federated Design Systems with Storybook
Design Systems with Storybook
Storybook is a fantastic tool that allows developers to build and test components in isolation, and it has the ability to generate static sites which can be published for documentation and collaboration purposes. This makes it a great tool for use in design systems as it opens up the collaboration between developers and designers.
We at Xolv.io have recently been helping a major automotive client of ours build their design system, and Storybook has been central to our approach. It’s been great to see high feedback between developers, designers, QA’s, and product owners, and to have everyone use it as the source of truth to reason about and iterate on UI components.
Federated Components
Recently, Zack Jackson over at Webpack 5 added a little bit of magic called Federation, which basically allows you to define a remote that is able to publish its modules at runtime. So then in an app — or host as they are officially called — rather than having to do this:
import SomeLocalComponent from 'an-npm-module-at-build-time'
You define a remote location using a standard URL and then in your code, you use the module as if you were importing it locally, like this:
import SomeRemoteComponent from 'a-federation-remote-at-runtime'
This is very powerful and exciting stuff and opens up many possibilities.
So it got us thinking, could a published Storybook based design system also be a Federation remote? 🤔
This would be amazing as it would mean the same source of truth that’s used by developers and designers, can also be the mechanism to distribute components for use in applications. And when the design system is updated, all apps would receive the updates in realtime. 😎
Demo time
The Storybook below shows a cut-down version of the Xolv.io design system (see it live here). It has some components like Section, and elements like the Confetti:
The page below is independently hosted and is pulling the components and elements from the design system at runtime (see it live here).
How does it work?
- First you add the freshly created Xolv.io Storybook Federation plugin to your Storybook’s webpack config:
// Configure our plugin in your Storybook webpack.config.js like this:
plugins: [
new StorybookWebpackFederationPlugin({
name: "xolvio-ui",
files: {
paths: ["./src/**/*.ts{,x}"]
}
})
]
2. Add the plugin to your app:
plugins: [
new StorybookWebpackFederationPlugin({
remotes: ["xolvio-ui"],
})
]
3. Start federating remote modules directly from your published design system:
import { Background } from "xolvio-ui/elements/Background";
import { Title } from "xolvio-ui/components/Title";
import { CenteredContentWrapper } from "xolvio-ui/helpers/CenteredContentWrapper";
export const Services = () => (
<CenteredContentWrapper>
<Background/>
<Title title="hello" subheading="world" />
</CenteredContentWrapper>
);
Admittedly we just showed you how to draw an owl!
Watch this video for the full juicy details where we walk you through exactly how we do it.
You can also check out the plugin repo for more instructions if you want to try this yourself, and see the demo site code. All the links are at the end of the article below.
But why do this? (I hear you ask) 👂
The output of a design system is a set of documentation, components, and assets.
If the documentation site is created by Storybook, why not also use that as the same output as the distribution mechanism for the components and any assets? This creates a bundle that is an output of the same build process, so you get matching docs with code.
What’s also really cool is that any bug fixes to components are pushed live to all consumers! This is both awesome and terrifying, but the terrifying bits can be tamed as you shall see below.
What about performance? (I detect your wonder) 🤔
Well since Storybook is just a static site, these files are easily put behind a CDN, and since the host app can do SSR and that can also be behind a CDN, then client loading performance problems disappear.
What about versions? (I read in your meandering eyes) 👀
Right now versions are not supported in Webpack Federation. There is talk about supporting that somehow, so I look forward to seeing how they do it. However, in my opinion, if you need versions then you shouldn’t use federation and should instead use an NPM module. This brings us on to the next question…
Won’t defective changes break dependent systems? (I smell your fearful thoughts) 💭
Of course, they would, which is why it’s super important that you have a high-quality ever-green design system, and that you ensure every single deployment does not contain any breaking changes.
How do I never break my design system? (I sense your cogs turn) ⚙️
You invest in quality practices and tooling that detect potential problems before they become actual problems. Here are the tools, practices, and techniques to make this happen:
- Unit testing ensures that functional behaviour does not regress from designs. Tools like our very own XSpecs allow you to collaboratively write specs between designers, developers, QA’s s product owners right from within Storybook!
- Visual regression tooling like Chromatic or Percy do a phenomenal job of letting you know when the stories of your components have changed and that they need your attention.
- Integration tests that load up Storybook in a browser testing tool like Playwright, can render all your stories making sure none of them emit any errors and that the logs are squeaky clean.
- More integration tests that load up a test site that consumes the federated components and ensures no errors are emitted. This can also be run through visual regression testing.
- Typescript, formatting, and linting tools, as well as pre-commit hooks to run them all locally so that you can spend less time introducing and fixing mundane typing and spacing issues.
- Running all of the above on a continuous integration service such as GitHub Actions.
- Deploying in an active/inactive fashion where you run final smoke tests in your environment before making it live.
With all these practices in place, you can safely practice continuous deployment with the knowledge that your design system will (almost) always work.
Note: I say almost because you’ll probably find a few issues at the start, but if you focus on not just fixing the issues, but ensuring they can’t happen again through testing and automation, then you’ll eventually stop having such issues.
Start using it now
With Storybook, Webpack Federation, and our Storybook Webpack Federation Plugin, your point of distribution for your documentation becomes the SAME as your point of distribution for your code — there can be no disconnect.
I’m super excited about expanding the use cases. There’s no reason why it should stop at the design system and the same techniques can be used for component libraries also using Storybook, and maybe even full pages with some fancy CMS.
Thank you much 🙇♂️
I hope you’ve enjoyed reading this article as much as we’ve enjoyed writing it.
We are Sam Hatoum (follow me on Twitter) and Lukasz Gandecki, we are partners at Xolv.io. Please read about our offerings below, we look forward to helping you deliver higher quality software, faster!
Sam & Lukasz.
Links:
- Storybook Webpack Federation Plugin
- Demo Design System Storybook
- Demo Host
- Demo Design System Code
- Demo Host Code
- Webpack Federation SSR Example
Let me know if you have any questions or thoughts in the comments below.