Nuxt.jsにStorybookのMDXを追加する手順

何度も同じ作業やるので必要なモジュールだけをインストールしてモックを構築する手順を忘れないように書いておきます。

## 準備
Storybook関連のインストールで`core-js`がインストールされてNuxt側が動かなくなるのでその対策

```
yarn add -D @babel/preset-env core-js
```

```ts:nuxt-config.ts
export default {
  build: {
    babel: {
      presets: [
        [
          '@babel/preset-env',
          {
            targets: {
              ie: '11'
            },
            useBuiltIns: 'usage',
            corejs: 3
          }
        ]
      ]
    }
    // ...
  }
}
```

## Install

それでは`storybook`関連のインストールをします。
`MDX`を表現するのにreactのライブラリも必須になるのでかなりモジュールは多くなってしまいます😅
`storybook-addon-vue-info`は、Vueのpropsなどのドキュメントを自動生成するのに必要です
(将来的には別のモジュール推奨になるかもです)。

```js
yarn add -D @storybook/vue babel-preset-vue @storybook/addon-docs storybook-addon-vue-info react react-is
```


## 設定ファイルなどの環境を整える

```js:.storybook/main.js
module.exports = {
  stories: ['../src/**/*.stories.([tj]s|mdx)'],
  addons: ['@storybook/addon-docs']
}
```

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

module.exports = {
  module: {
    rules: [
      {
        test: /\.css?$/,
        loaders: ['style-loader', 'css-loader']
      },
      {
        test: /\.scss$/,
        loaders: ['style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.stories\.jsx?$/,
        loaders: [require.resolve('@storybook/source-loader')],
        enforce: 'pre'
      },
      {
        test: /\.ts$/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              appendTsSuffixTo: [/\.vue$/],
              transpileOnly: true
            }
          }
        ]
      },
      {
        test: /\.vue$/,
        loader: 'storybook-addon-vue-info/loader',
        enforce: 'post'
      }
    ]
  },
  resolve: {
    extensions: ['.js', '.vue', '.json', '.ts', '.tsx', '.scss'],
    alias: {
      '@': rootPath,
      '~': rootPath,
      vue$: 'vue/dist/vue.esm.js'
    }
  },
  node: {
    fs: 'empty'
  }
}
```

また、以下の設定などは、`.storybook/preview.js`

- グローバルのCSSを入れる
- Storybook内のリンクのエラーを防ぐ
- Storeの設定を入れる設定を書くファイルは、

```js:.storybook/preview.js
import Vue from 'vue'
import Vuex from 'vuex'
import { configure, addDecorator } from '@storybook/vue'
import user from '~/store/user.ts'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    user
  }
})

Vue.component('nuxt-link', {
  props: ['to'],
  methods: {
    log() {
      console.log('to', this.to)
    }
  },
  template: '<a href="#" @click.prevent="log()"><slot>NuxtLink</slot></a>'
})

addDecorator(() => ({
  store,
  template: `<story/>`
}))

configure(
  require.context('../storybooks', true, /\.stories.([tj]s|mdx)$/),
  module
)
```

CDNなどを追加したい場合は`.storybook/preview-head.html`を追加

```html:.storybook/preview-head.html
<link
  href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
  rel="stylesheet"
/>
<link
  href="https://cdn.jsdelivr.net/npm/@mdi/font@3.x/css/materialdesignicons.min.css"
  rel="stylesheet"
/>
```

## 参考

- [(github)storybook addons-docs](https://github.com/storybookjs/storybook/tree/master/addons/docs)
- [storybook guide-vue](https://storybook.js.org/docs/guides/guide-vue/)