初めての Storybook ~ 環境構築からプロジェクトで呼び出すまで ~

# はじめに

この記事では Storybook の始め方からプロジェクト導入までの手順を**ざっくり**解説した記事です。「Storybook ってなにがええねん」「どうやってプロジェクトで使うねん」と使い始めた当初ちんぷんかんぷんだったので、（おまけに参考サイトが英語の記事ばっかり~~でしんどい~~）、少しでも役に立てばいいなと思い記事にまとめてみました。

Storybook 自体に関する詳細や具体的な運用手順は、すでにわかりやすい記事がたくさんあると思うので、最低限の説明にとどめています🙇‍♂️

# 前提

* 今回は本プロジェクトとは別に「Storybook用のリポジトリ」（つまりコンポーネントを管理するだけのリポジトリ）を作成して運用して行きます。理由は後述します。
* Storybook を導入するプロジェクトは既に存在している前提で話は進みます

# Storybook とは

UIコンポーネントのカタログを作るツール

わかりやすかった記事
https://www.ey-office.com/blog_archive/2020/11/18/storybook-is-good-tool/

# Storybook 導入の経緯

## どのファイルがどんな見た目してるのかぱっと見じゃわからん

自分が現在参画してるプロジェクトは、ある程度画面が出来上がった状態でアサインされました。最初に画面実装を任せてもらったのですが、とにかくコンポーネント数が多く、カンプ通りに実装するために 

* このコンポーネントはすでに作成されてる、、？
* 似たような見た目やけど絶妙に見た目が違う、、？
* props がいっぱいあるけど、どの props を渡したらどんな表示になるん、、？

というのを確認するのにかなりの時間がとられてしまいました。挙句の果てにめんどくさくなって既に存在するコンポーネントをわざわざ作成したりもしました（ごめんなさい）

Storybook を使えばそんな問題もすぐに解決できちゃいます。

> You can use args in your stories to configure the component's appearance, similar to what you would do in an application. 

公式様より引用 https://storybook.js.org/docs/react/writing-stories/args#args-can-modify-any-aspect-of-your-component

引数を渡すことで外観を変更することができる

## 別のプロジェクトでも似たようなコンポーネントを作成するので、使いまわせるものは使いまわしたい

実は自分がアサインされたプロジェクトとは別で、同じクライアント様から別の案件も受注してるらしいのですが、何と似たような UIになってるではありませんか！ Storybook では　「1つの Storybook を複数のプロジェクトで共有する」なんてこともできてしまうので、導入しない手はありませんね。


https://storybook.js.org/tutorials/design-systems-for-developers/react/en/distribute/



# Storybook をインストール

前置きが長くなってしまいましたが、Storybook を導入してみましょう。今回は複数プロジェクトで使い回すことを前提とするので、プロジェクトとは別に **Storybook 用のリポジトリを作成**します。

### Nuxt のプロジェクトを作成

```
npm init nuxt-app nuxt-storybook
cd nuxt-storybook
npm run dev
```

詳細は割愛、、
https://nuxtjs.org/ja/docs/get-started/installation

### Nuxt に Storybook を入れる

```
npm install --save-dev @nuxtjs/storybook postcss@latest
```

Storybook の詳細設定は nuxt.config,js から行えます。
今回は一旦　*stories フォルダ以下の storie.js は全てインポートする*、という設定だけ追記しておきます。

```
 storybook: {
    stories: ['~/stories/**/*.stories.js'],
  },
```

他にもオプションがあるので必要に応じて追加してみてください！
https://storybook.nuxtjs.org/api/options

ここまでできたら Github のリポジトリを作成、push し、Storybook が立ち上がるかも確認しておきましょう。

```
npx nuxt storybook
```
公式通りに進めればこれで 3003番ポートが立ち上がり、Storybook が表示されます。

# コンポーネントを作成し、Storybook に表示させる

作成したコンポーネントを Storybook で表示させてみましょう。イメージとしては、「UIカタログにコンポーネントを掲載する」ことをゴールとします。

## ① コンポーネントを作成

なにはともあれコンポーネントを作成しましょう。
今回は簡単な複数のカラーバリエーションが存在するボタンを作成します。

```
  <div>
    <button
      class="app-button"
      :class="{
        '-red': red,
        '-blue': blue,
      }"
    >
      Button
    </button>
  </div>
```

## ② 作成したコンポーネントを Storybook に組み込む

```
import AppButtonComp from '@/components/atoms/AppButton'

export default {
  title: 'Components/Button',
  component: AppButtonComp,
  argTypes: {
    red: false,
    blue: false,
  },
}

const AppButton = (_args, { argTypes }) => ({
  components: AppButtonComp,
  template: `
    <AppButton
      v-bind="$props"
    />
  `,
  props: Object.keys(argTypes),
})

// デフォルト表記
export const Default = AppButton.bind({})

// ボタンを赤くする
export const Red = AppButton.bind({})
Red.args = {
  ...Default.args,
  red: true,
}

// ボタンを赤くする
export const Blue = AppButton.bind({})
Blue.args = {
  ...Default.args,
  blue: true,
}

```

argTypes の中で引数を指定し、props や action（イベント）を作成することができます。
詳細: https://storybook.js.org/docs/react/api/argtypes

ここまで行うと Storybook 上で作成したコンポーネントを見ることができます。

![スクリーンショット 2021-12-16 21.22.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1741616/eb1b3599-461f-e980-71b6-ab443ccc77aa.png)


![スクリーンショット 2021-12-16 21.21.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1741616/1a01b6bf-b06d-b043-4fe2-723dc1004cc1.png)

![スクリーンショット 2021-12-16 21.22.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1741616/bfd229e6-66dc-8975-6ba9-2bbda684daee.png)


これでどのコンポーネントがどんな形をしてるのか、どういう props を受け取り何パターンに変化するのかが視覚的にわかるようになりました。

# プロジェクト側で呼び出す

Storybook を導入したものの、プロジェクト側でどうやって呼び出せばいいのでしょう。 Storybook のリポジトリからわざわざ Vue ファイルと cssファイルをコピペすれば使えますが少し面倒ですね。そこで先輩にご相談したところ、`npm package` と `git submodules` を2つのやり方が主流らしく、今回は導入コストの低そうな `git submodules` で実装していくことにしました。

## git submodules とは

git submodule は、外部の リポジトリを、プロジェクトの git リポジトリのサブディレクトリとして登録し、特定の commit を参照する仕組みのことです。

git submodule に関してはこちらの記事に詳しくまとめられていたのでよければご覧ください
https://qiita.com/sotarok/items/0d525e568a6088f6f6bb

今回は「ビルドした時に、Submodulesの components ディレクトリと css ディレクトリを、本 projectのフォルダにコピーしてくる」 ように設定して行きます。

## build したときに Storybook リポジトリからコピー

最初に npm script が走った時にファイルをコピーできるよう cpx パッケージをインストールしましょう。

```
$ npm install --save-dev cpx
```

参考 https://maku77.github.io/nodejs/npm/npm-run-copy-file.html

次に package.json に以下のコマンドを追記して行きます。
今回はわかりやすくするために小分けにしています。

```

 // Submodules 内の storybook用リポジトリから最新のコミットを pull
 "pull": "cd storybook-repo && git pull origin main",
 // Submodules 内の storybook用リポジトリからコンポーネントをコピー
 "copy:component": "cpx 'storybook-repo/components/**' 'src/components/'",
 // Submodules 内の storybook用リポジトリからコンポーネントをコピー
 "copy:scss": "cpx 'storybook-repo/assets/scss/components/**'  'src/assets/scss/components'",

```

このコマンドを随時実行してもいいのですが、面倒くさいのでビルドした時に実行してみます。

```
 "dev:story": "npm run pull && npm run copy:component && npm run copy:scss && npm run copy:image && nuxt",
```

これでビルドするたびに submodules から呼び出せるようになりました！


# 参考
https://www.ey-office.com/blog_archive/2020/11/18/storybook-is-good-tool/
https://storybook.js.org/docs/react/writing-stories/args#args-can-modify-any-aspect-of-your-component
https://storybook.js.org/tutorials/design-systems-for-developers/react/en/distribute/
https://maku77.github.io/nodejs/npm/npm-run-copy-file.html