Vue CLI 4 でStorybookを使う

今更ですが、Storybookに手を出していこうと思い、環境構築から順にメモとして残していきます。

# 始めに

## Storybookとは？
<img width="535" alt="スクリーンショット 2020-02-11 0.22.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242655/b834df32-150f-7de9-64ff-e9625593c17f.png">


- 公式サイト：https://storybook.js.org/
- UIコンポーネントカタログが作成できるツール
- デザイナとプログラマの認識合わせに使える
- Docなども記載できるため、チーム開発での意思疎通にも使える

# Storybookの環境構築

## 環境
```shell:Console
% node -v
v12.13.0
% npm -v
6.13.6
```

## プロジェクトの作成
Vue CLIを使ってお好みの設定でプロジェクトを作成します。

```shell:Console
% npx @vue/cli create vue-storybook-demo 

Vue CLI v4.2.2
? Please pick a preset: Manually select features
? Check the features needed for your project: TS, Linter
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? No
? Pick a linter / formatter config: Prettier
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint o
n save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
```

## 開発サーバの起動
```shell:Console
% cd vue-storybook-demo 
% npm run serve
```
ブラウザで`http://localhost:8080/`へアクセスし表示確認を行う。

## Storybookプラグインの追加
```shell:Console
% npx @vue/cli add storybook

? What do you want to generate? Initial framework
? What storybook version do you want? (Please specify semver range) >=5.3.0
? Use Storybook CSF (component story format)? Yes
? Use Storybook Docs? Yes
```

### 自動生成されたサンプルの修正
今回のVueCLIの設定だと、自動生成されるサンプルでエラーが発生していたので、修正します。

```diff:src/components/MyButton.vue
 <script lang="ts">
- export default {
-   name: "my-button",
- 
-   methods: {
-     onClick() {
-       this.$emit("click");
-     }
-   }
- };
+ import { Component, Vue } from "vue-property-decorator";
+ 
+ @Component
+ export default class MyButton extends Vue {
+   public onClick(){
+     this.$emit("click");
+   }
+ }
 </script>
```

## Storybookサーバの起動
```shell:Console
% npm run storybook:serve
```
ブラウザで`http://localhost:6006/?path=/story/button--with-text`へアクセスし表示確認を行います。
（というか勝手にブラウザが開く。）

![localhost_6006__path=_story_button--with-text.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242655/035d6c78-ef61-a6cd-9916-ca1ae8d4ab6d.png)
![localhost_6006__path=_story_button--with-text (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242655/da0d296f-9928-163e-e0ec-59872435b6a8.png)

# Storyの追加
## オリジナルのコンポーネントの作成
以下のファイルを新規作成します。

```vue:src/components/MyHeading.vue
<template>
  <h1>
    <slot></slot>
  </h1>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component
export default class MyHeading extends Vue {}
</script>
```
## Storyの追加
以下のファイルを新規作成します。

```javascript:src/stories/MyHeading.stories.js
import MyHeading from "../components/MyHeading.vue";

export default {
  component: MyHeading,
  title: "Heading"
};

export const withText = () => ({
  components: { MyHeading },
  template: '<my-heading>Hello Title</my-heading>'
});
```

```md:src/stories/MyHeadding.stories.mdx
import { Meta, Props, Story, Preview } from '@storybook/addon-docs/blocks';
import MyHeading from '../components/MyHeading.vue';

<Meta title="MDX|Heading" component={MyHeading} />

# MyHeading

<Props of={MyHeading} />

This is a simple button with some text in it.

<Preview>
  <Story name="With Text">
    {{
        components: { MyHeading },
        template: '<my-heading>Hello Title</my-heading>'
    }}
  </Story>
</Preview>
```

## ブラウザで表示確認
![localhost_6006__path=_story_mdx-heading--with-text.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242655/6e52bf62-d660-a7e4-a925-9b80a7a2a792.png)

以上で環境構築は完了です。
ここから自作のコンポーネントを追加したり、お好みのStorybookプラグインを追加してプロジェクト毎のコンポーネントカタログを作成していきます。