Nuxt.jsにStorybookを導入してみる

# Storybookのバージョンについて追記
2018年10月29日にStorybook4系がリリースされたみたいです。
Webpack4に対応してるので、Nuxt2系使っててStorybook追加したい人はそちらを使うことをおすすめします（いつかそっちも書きたい）。
この記事ではStorybook3系で書いてます。


# Storybookとは？
- コンポーネントのカタログ
- UIコンポーネントを単独で開発でき、コンポーネントの再利用、テストの容易性、開発スピードを向上させることができる


# なぜ必要？
- プロダクトとは切り離して開発する  
→依存関係が全くない状態を保てるため、再利用性が高いコンポーネントを作ることにつながる
- エンジニアとデザイナーの認識のズレをなくすため  
→ここデザインと違うよねーとか


# 使い方
※ 2018年10月3日時点で、`Nuxt v2`には`Storybook v4`のアルファ版しか対応してないっぽいから、正式版使いたかったら`Nuxt v1.4.2`以前を使ってね(ちなみに、使ったバージョンは`v1.4.2`)
## Install
※ `yarn`で書いていくので、`npm`使う人は適宜読み替えてね

```
$ yarn global add @storybook/cli

$ vue init nuxt-community/starter-template <プロジェクト名>
$ cd <プロジェクト名>
$ yarn install
$ getstorybook --skip-install
```

```json:package.json
// devDependenciesのstorybook部分が3系になってることを確認する
// （なってなかったら変更する）
"@storybook/vue": "^3.4.11",
"@storybook/addon-actions": "^3.4.11",
"@storybook/addon-links": "^3.4.11",
"@storybook/addons": "^3.4.11",
```

```
$ yarn  // install
$ yarn storybook   // 起動
```
設定変えて無ければ、`localhost:6006`にアクセス！

## Set up
pugとかsassとか画像とかの設定

```
$ yarn install pug pug-loader sass-loader node-sass
$ cd .storybook
$ vim webpack.config.js
```

``` js:webpack.config.js
const path = require('path')
const rootPath = path.resolve(__dirname, '../')

module.exports = {
  module: {
    rules: [
      {
        test: /\.css?$/,
        loaders: ['style-loader', 'css-loader']
      },
      {
        test: /\.scss$/,
        loaders: ['style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.pug$/,
        loader: 'pug-loader'
      },
      // Nuxtのデフォルトアセットローダー
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        loader: 'url-loader',
        query: {
          limit: 1000, // 1kB
          name: 'img/[name].[hash:7].[ext]'
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        query: {
          limit: 1000, // 1kB
          name: 'fonts/[name].[hash:7].[ext]'
        }
      }
    ],
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      '@': rootPath,
      '~': rootPath,
      'vue$': 'vue/dist/vue.esm.js'
    }
  }
}
```

#### aliasを登録している理由
- `@` or `~`: Nuxtを見ないので、sorceDirのaliasを自前で登録する
- `vue$`: `You are using the runtime-only build of Vue where the template compiler is not available`エラーへの対応

## Using

```js:/stories/index.stories.js
import './hello'
```

```js:/stories/hello.js
import { storiesOf } from '@storybook/vue'
import AppLogo from '~/components/AppLogo.vue'

storiesOf('Welcome', module)
  .add('to Nuxt', () => ({
    components: { AppLogo },
    render(h) {
      return <AppLogo />
    }
  }))
```
<img src="https://qiita-image-store.s3.amazonaws.com/0/222222/3138cce9-f781-5b4d-1b64-bb0de3437b84.png" width="70%">


**Yeah!😆🙌**

# グローバルCSSを使いたい場合
assets内にscssまとめてる場合は、Decoratorを使って呼び込む必要がある。
※別途UIフレームワークを使っている場合は、そのフレームワーク用のCSSとかも

```html:/.storybook/Decorator.vue
<template lang="pug">
  .decorator
    slot(name="story")
</template>

<script>
export default {
  name: 'Decorator'
}
</script>

<style lang="scss">
@import "~/assets/scss/style.scss";
</style>
```

```js:/.storybook/config.js
import { configure, addDecorator } from '@storybook/vue'
import Decorator from './Decorator.vue'

addDecorator((story) => ({
  components: { Decorator },
  render (h) {
    return (
      <decorator>
        <story slot="story"></story>
      </decorator>
    )
  }
}))

// automatically import all files ending in *.stories.js
const req = require.context('../stories', true, /.stories.js$/);
function loadStories() {
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);
```

# 最後に
今後はアドオンを入れて、さらに使いやすくしたいなーと思ったりなんだり。
`getstorybook`打ったときに、一応actionとlinksのアドオンが入ってたりするんですけど、これ以外にも便利なアドオンがあるっぽいんで、よかったら探してみてください。

# 参考
[Nuxt.js に Storybook を導入する 前編](https://www.chatbox.blog/2018/05/07/nuxt-js-storybook1/)