Publish Storybook components to NPM using Semantic Release and Github Actions
Tags: semanticrelease, storybook, githubactions, react
Published: 2020-03-12 16:54:51

## 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](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages) 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](https://dev-to-uploads.s3.amazonaws.com/i/tedem44iri43s3dpdk2f.png)

#### 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](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) how to create a token for Github. You need to give the token repo scope permissions.

And [here](https://docs.npmjs.com/creating-and-viewing-authentication-tokens) 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](https://dev-to-uploads.s3.amazonaws.com/i/zy5ieb3ycqehmj9e6b3d.png)

#### Github Release

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


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4o7u8dkn75pcx90hhfhy.png)

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

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/u6nl98bgxhx3adv4mlpl.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/u0vflclalxtaobt7e78z.png)

### 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](https://github.com/commitizen/cz-cli) or [commitlint](https://github.com/conventional-changelog/commitlint) can be used to enforce valid commit messages.

You can find the complete code for this guide in the [github repository](https://github.com/amalv/storybook-npm)