Integrating Stencil with Storybook
We have recently selected Stencil.js to build our new Design System. Stencil defines itself as a “toolchain for building reusable, scalable Design Systems”. We also wanted to take advantage of Storybook to make our new Design System available to our frontend developers. In this article we will demonstrate how to integrated Stencil with Storybook to streamline the development, testing, and documentation of generic Design System.
Stencil and Storybook in conjunction
Stencil.js is a developer tool to build Design Systems. To be more precise it is a toolchain to build Web Components that you can develop using JSX and Typescript. Using Web Components to build your Design System is a good idea, as you will later be able to leverage it in pretty much any front end application whatever is your preferred front-end framework: Angular, Vue, React, … or simply plain vanilla JavaScript.
On the other hand, Storybook is famous for its capacity to document your design system, and make it available to your frontend developers. We will use it more like a testing and documentation tool, while keeping Stencil for development activities.
Stencil and Storybook can be used together to provide a great developer experience, end to end. This is what we are about to demonstrate.
Our first basic Web Component with Stencil
Let’s start with Stencil and an ultra basic web component. To make our life easier, Stencil provides a starter kit that we will leverage.
Let’s first clone the starter kit locally :
git clone https://github.com/ionic-team/stencil-component-starter.git my-component
cd my-component
git remote rm origin
Run it:
npm install
npm start
It is done ! We have just built our first “Hello World” web component using Stencil. Once the npm start has completed, you can simply browse http://localhost:3333/ and it will display the following message:
To understand what this first basic web component does, you can check out the file src/components/my-component/my-component.tsx:
import { Component, Prop, h } from '@stencil/core';
import { format } from '../../utils/utils';@Component({
tag: 'my-component',
styleUrl: 'my-component.css',
shadow: true,
})
export class MyComponent {
/**
* The first name
*/
@Prop() first: string;/**
* The middle name
*/
@Prop() middle: string;/**
* The last name
*/
@Prop() last: string;private getText(): string {
return format(this.first, this.middle, this.last);
}render() {
return <div>Hello, World! I'm {this.getText()}</div>;
}
}
It takes three parameters: first name, middle name and last name and will display a little “Hello World” message in a basic div html tag. Nothing rocket science !
And what you are actually viewing in your web browser at http://localhost:3333/ is the simple demo of this web component as defined in /src/index.html:
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
<title>Stencil Component Starter</title><script type="module" src="/build/stencil-starter-project-name.esm.js"></script>
<script nomodule src="/build/stencil-starter-project-name.js"></script>
</head>
<body>
<my-component first="Stencil" last="'Don't call me a framework' JS"></my-component>
</body>
</html>
Ok, that’s great ! But what about Storybook ?
Publishing our Web Component into Storybook
Because Stencil produces Web Components, we can deploy those in a «Storybook for Html» project type. Simply type the following command:
npx sb init --type html
We will now create a story along our web component in src/components/my-component/my-component.stories.tsx:
export default {
title: ‘my-component’
};
export const Default = () => `<my-component first="Bipbip" last="Wallace"></my-component>`;
We are now going to exclude our stories (**/*.stories.*) from the TypeScript compilation performed by Stencil. To achieve this, we modify the file tsconfig.json to add the following exclusion:
...
"exclude": [
"**/*.stories.*",
...
]
...
In order for the web component to work correctly, we need to tell Storybook where to find the component built by Stencil by injecting them using basic script tags. Let’s add a new file in .storybook/preview-head.html with the following content:
<script type="module" src="./stencil-starter-project-name/stencil-starter-project-name.esm.js"></script>
<script nomodule src="./stencil-starter-project-name/stencil-starter-project-name.js"></script>
The last step before running Storybook, is to load static assets in the dist folder, so that the above can work. We just need to modify the package.json file and add the “-s dist” to two existing lines in charge of running and building Storybook.
..."scripts": {
...
"storybook": "start-storybook -p 6006 -s dist",
"build-storybook": "build-storybook -s dist"
},...
We are good to go ! We can now rebuild Stencil web components and start Storybook:
npm run build
npm run storybook
And here we are !
Optional step: Remove unused Stories
Storybook is installed with some default stories, serving as example. We can remove them and leave only the stories that we created along our web components.
rm -r src/stories/
Optional step: Integrate Readme.md generated by Stencil
It is also possible to integrate automatically the readme.md files that are generated automatically by Stencil. To do so, we need to install a storybook addon using npm:
npm i --save-dev @storybook/addon-notes
Then modify the .storybook/main.js file to include this addon :
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-notes/register"
]
}
Finally we need to modify our story, in src/components/my-component/my-component.stories.tsx, to to load the readme.md:
import readme from './readme.md';
export default {
title: 'my-component',
parameters:{
notes: readme
}
};
export const Default = () => `<my-component first="Bipbip" last="Wallace"></my-component>`;
Restarting storybook:
npm run storybook
A new “Notes” section will appear and will display the readme.md generated by Stencil.
Conclusion
We are now ready to :
- Add some more Web Componants to our source code.
- Build them with Stencil using a straight forward npm run build.
- Publish them to Storybook using the commande npm run storybook
What else ? Maybe integrating all this into ZeroHeight.com. This will be an excellent topic for another article around Design Systems.
External links
The full source code related to this article is available in GitHub.