loading...
Cover image for Publish Storybook components to NPM using Semantic Release and Github Actions

Publish Storybook components to NPM using Semantic Release and Github Actions

amalv profile image amalv ・5 min read

Overview

In this guide you'll learn how to publish your Storybook components to NPM. In this way the components can be easily distributed and then consumed by the client apps.

Semantic Release will be used in combination with Github Actions in order to automate the release versioning.

Basic React Setup

First Create React App must be installed. The following command will generate a Create React App with Typescript support and NPM as the package manager:

npx create-react-app storybook-npm --template typescript --use-npm

Note that instead of storybook-npm you'll have to choose your own unique name to publish to NPM or use the scoped package approach.

Initialize Storybook

Add Storybook to the project:

cd storybook-npm
npx -p @storybook/cli sb init --story-format=csf-ts

You can check that it works by running the npm run storybook command.

Install and configure Semantic Release

npm install --save-dev semantic-release

Semantic Release has a perfectly fine out of the box default config, the only thing we need to do here is to add the plugins we want to use in the package.json:

  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/github",
    "@semantic-release/npm",
    "@semantic-release/git"
  ],

Clean up files

Since this project is not going to be used as a client, let's clean up a little bit and remove all the unnecessary files:

cd src
rm -rf stories/*
git rm -rf .

Install styled components

Styled Components is going to be used to style our components:

npm install styled-components @types/styled-components

Add button component

As an exportable component example we are going to create a button.

In the src folder create a new components folder.

Inside the components folder add the Button component:

Button.tsx:

import styled from "styled-components";

export interface ButtonProps {
  primary?: boolean
}

export const Button = styled.button<ButtonProps>`
  /* Adapt the colors based on primary prop */
  background: ${props => props.primary ? "palevioletred" : "white"};
  color: ${props => props.primary ? "white" : "palevioletred"};

  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;

Still inside the components folder add an index to export this and future components:

index.ts

export * from "./Button";

Add index to src folder

index.ts

export * from "./components";

This will export our components in order to allow clients to consume them.

Add the Button stories inside the stories folder

import React from 'react';
import { action } from '@storybook/addon-actions';
import { Button } from "../components/Button";

export default {
  title: 'Button',
  component: Button,
};

export const Default = () => <Button onClick={action('clicked')}>Default Button</Button>;
export const Primary = () => <Button primary onClick={action('clicked')}>Primary Button</Button>;

Check that the new component is being displayed in Storybook

npm run storybook

You should now see the Default and Primary buttons being displayed in Storybook under the Button story.

Alt Text

Create a Github repository

https://github.com/new

In this example I called it the same name as the package: storybook-npm

Link local repository to Github repository

git remote add origin git@github.com:<username>/<repository-name>.git
git push -u origin master

Commit and push changes

git add .
git commit -m "feat: Add button component"
git push

Github and NPM tokens

We need to get Github and NPM tokens. This is needed in order for Semantic Release to be able to publish a new release for the Github repository and for the NPM registry.

You can read here how to create a token for Github. You need to give the token repo scope permissions.

And here you can read how to create a token in NPM. You need to give the token Read and Publish access level.

Once you have the two tokens, you have to set them in your repository secrets config:

https://github.com/<username>/<repositoryname>/settings/secrets

Use GH_TOKEN and NPM_TOKEN as the secret names.

Setup Github Actions

Inside the root of the project, create a .github folder, and inside the .github folder, add a main.yml file with the following content:

name: Semantic release 

on: push
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup Node.js
        uses: actions/setup-node@v1
        with:
          node-version: 12
      - name: Install dependencies
        run: npm install 
      - name: Build app
        run: npm run build 
      - name: Semantic release
        env:
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npx semantic-release

Commit and push changes

git add .
git commit -m 'feat: Add github actions'
git push

Because of the config previously added, the push will trigger Github Actions which runs Semantic Release. You can see the results in your repository action tab.

Alt Text

Github Release

If everything went well, you should see in the action results that every step was succesfully executed.

Alt Text

And in the code tab you can see now that a new release has been created.

Alt Text

However, the NPM package has not been published, in order to fix this, a couple of changes need to be made.

NPM Release

Update the tsconfig.json file:

{
  "compilerOptions": {
    "outDir": "dist",
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": false,
    "jsx": "react"
  },
  "include": [
    "src"
  ]
}

You'll also need to remove the private property from package.json in order to be able to publish to NPM and add the files and main entries:

  "files": [
    "dist"
  ],
  "main": "dist/index.js",

file will indicate to NPM that dist is the folder to be included when the package is installed as a dependency.

main represents the dependency entry point.

Commit and push changes:

git add .
git commit -m "Enable NPM registry support"
git push

This should trigger again Github Actions and this time the package will be published to the NPM registry.

Use the dependency with a client app

To try the NPM package, we'll create a new Create React App:

npx create-react-app storybook-consumer --use-npm

Then install the dependency:

npm install storybook-npm

Edit App.js in order to test it:

import { Button } from 'storybook-npm';
...
<Button>Test</Button>

And start the app:

npm start

You should now see the button in the main page.

Alt Text

Conclusion

Having a good strategy for releasing your Storybook components can make things easier to maintain. Semantic Release in combination with Github Actions automates the release process so you only have to worry about choosing the appropiate commit messages.

Tools such as commitizen or commitlint can be used to enforce valid commit messages.

You can find the complete code for this guide in the github repository

Posted on by:

Discussion

markdown guide
 
 

i have added css and it says you need additional loaders for it