結局 Next (TypeScript) にStorybookを入れるには何が必要なの?

公開:2020/10/12
更新:2020/10/16
2 min読了の目安(約2200字TECH技術記事

なんかググったらいろいろ出てきますが、どれを試してもうまくいかなかったので最小構成を探ってみました

あなたのNextプロジェクトを汚さずにStorybookを導入しよう!

手順

依存関係のインストール

$ yarn add --dev @storybook/react ts-loader css-loader babel-preset-react-app babel-plugin-react-require 

追加するのは

  • @storybook/react
    • これがなきゃ始まらないだろう…たぶん
  • ts-loader
    • これがあれば babel-loader は要りません
  • css-loader
    • CSS Modulesに対応するために必要
  • babel-preset-react-app
    • たぶんbabelがJSXを解釈するために必要
  • babel-plugin-react-require
    • Nextのコンポーネント内ではReactを明示的にインポートする必要がないのでそれに合わせるためのbabel-plugin

npm scriptの定義

これは厳密には必須ではありませんが、なにかしらscriptsに登録しないとStorybookの起動に不便なので、こんな感じの追記をおすすめします

package.json
{
  "scripts": {
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook"
  }
}

.babelrc をつくる

さっきインストールしたpresetとpluginをbabelに伝えます

.storybook/.babelrc
{
  "presets": [
    "react-app"
  ],
  "plugins": [
    "react-require"
  ]
}

main.js をつくる

しばらく前には config.js と呼ばれていたそうです (参考)
なんか .storybook/webpack.config.js を作っても読んでもらえなかったので、webpack configはここに書いたほうが良さそうです

.storybook/main.js
const path = require("path")

module.exports = {
  stories: ['../stories/**/*.stories.tsx'],  // どのstoryファイルを読み込むのか
  webpackFinal: async (config) => {
    config.module.rules = [
      // デフォルトのrulesに入っているCSS用の設定が悪さをするのでお帰りいただく
      ...config.module.rules.filter(rule => rule.test.source !== (/\.css$/).source),
      // css-loader を設定しなおす
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
    config.resolve.alias = {
      "@": path.resolve(__dirname, "..")      // こっちは私の趣味です
    }
    return config
  }
}

余談ですが、aliasの設定は

  webpackFinal: async (config) => ({
    ...config,
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "..")
      }
    }
  })

って書くのも読んでもらえなかったので、あんまり融通がきかないようです
rulesは読めるのになんでだろうね

おわりに

インターネットの海に浮かんでいるミスリードたちに阻まれながら、私はここにたどり着くために今日1日を費やしてしまいました
悩んでいるあなたを救えたのなら私も苦労した甲斐があったというものです

なにか改善点などアドバイスがあればコメントいただけるとうれしいです

では、良いStorybookライフを!

2020/10/16 追記

CSS ModulesでインポートしていたclassNameがundefinedになっていることに気付いたので調査
依存関係に css-loader が必要になりました
それに伴って main.js も書き換わっています