この記事は React Advent Calendar 2016 の 23 日目の記事として投稿しようと思っていたものです。
クリスマスに全然間に合いませんでした...
はじめに
先日、弊社で React をテーマとした LT イベント を開催したのですが、
そのときに React Storybook について話をしました。
(そのときの資料はこちらです: React Storybook を触ってみる // Speaker Deck)
React Storybook とは?や試してみた経緯については上記スライドで紹介していますが
実際にプロジェクトに導入しようとしたときに、割とハマりどころというかドキュメントをちゃんと読まないとわからないことが多かったので、そのあたりをまとめてみました。
まずは Default Config を理解する
参考:Default Config - React Storybook
React Storybook は webpack を使用しています。
内部で定義された webpack.config.js を使用しているようで、そのビルドの挙動については上記ページに記載されています。
JavaScript については
- Babel でトランスパイルされる。ES2016+ の文法が使える
-
プロジェクトルートに
.babelrc
があると自動的に読み込んでくれる- ので、JavaScript については特に意識せずともプロジェクトの設定をそのまま流用できそう
詳しくは ここ を見ろと記載がありますが、どうも現在は babel-preset-react-app というプリセットを読み込んでいるだけに見えます。
babel-preset-react-app はこれのことでしょうか。
https://github.com/facebookincubator/create-react-app/tree/master/packages/babel-preset-react-app
Create React App で使用されているプリセットのようです。
また、CSSや画像などの静的リソースについても
import './styles.css'
という形式で普通にインポート可能です。
余談:デフォルトの webpack.config.js はどこで確認できる?
「挙動はなんとなくわかったけど実際の webpack.config.js の内容を確認したいなー」と思って色々調べてみたんですが
ドキュメントからはわかりませんでした。
しょうがないので、カスタムの webpack.config.js(後述)を定義せずに storybook を起動したときの
=> Using default webpack setup based on "Create React App".
というログをリポジトリで検索すると以下が見つかります。
https://github.com/storybooks/react-storybook/blob/1711fd58d17795e14c02a68ee61b016052a44792/src/server/config.js#L71-L72
また、相対パス ./config/defaults/webpack.config.js
をたどって見つかるのがこれです。
https://github.com/storybooks/react-storybook/blob/1711fd58d17795e14c02a68ee61b016052a44792/src/server/config/defaults/webpack.config.js
たしかに .css
や .jpg
などのファイルに対する loader が定義されてますね。
ちなみに JS に対する loader は このあたり で定義されてますが、ソースを深く読み込んでいないので両者のファイルの関係性とかはわかってないです。
カスタムの webpack.config.js を定義する
参考:Custom Webpack Config - React Storybook
デフォルトの webpack.config.js を挙動を変更するには、.storybook
ディレクトリの下にプロジェクト用とは別の webpack.config.js
を用意する必要があります。
たとえば、デフォルトの設定では SASS などの CSS プリプロセッサに対応していないため
そういったファイルにも対応したい場合は以下のように記述します。
const path = require('path');
module.exports = {
module: {
loaders: [
{
test: /.scss$/,
loaders: ["style", "css", "sass"],
include: path.resolve(__dirname, '../')
}
]
}
}
通常の webpack.config.js と違うところとしては、このファイルは .storybook
ディレクトリの下にあるので include
オプションを↑のように指定する必要があるところですかね。
注)...とドキュメントには記載されてますが、今のところ include
の指定を忘れてうまくいかなかった場面に遭遇していません。プロジェクトの構成とかスタイルファイルをどのように扱っているかとかによる気がします。
また、
Once you create this
webpack.config.js
file, Storybook won't load the default Webpack config other than loading JS files with the Babel loader.
ということなので、カスタムの webpack.config.js を用意した場合、デフォルトの設定は無効になります(デフォルトの設定に追加、ではなく)。
「SCSS読み込ませたいけど画像とかはデフォルトの設定のままでいいや」という場合でも画像などの拡張子に対する loader もしっかり定義してあげないということですね。
まあ基本的にはプロジェクトの webpack.config.js の内容をコピーしてくることになりそうです。
カスタム webpack.config.js で指定できないもの
webpack の option のうち、以下は変更できません。
- entry
- output
- js の loader(Babel 使うのは変更できないので、
.babelrc
で設定をカスタマイズする)
余談:プロジェクトの webpack.config.js の内容を使うことはできないの?
Using Your Existing Config で軽く言及されてます。
結論としては、プロジェクトルートの webpack.config.js をそのまま使うということはできないので
-
.storybook/webpack.config.js
側ではプロジェクトの webpack.config.js を import する - 共通の config を作ってそれぞれで import する
など工夫してくれとのこと。
HTML の<link>
タグでリソースを読み込んでいる場合
参考:Add Custom Head Tags - React Storybook
プロジェクトによっては、HTML ファイルで
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
のようにリソースを読み込んでいるケースがあると思います。
その場合、.storybook/head.html
というファイルを用意し、そこに HTML の <head>
タグの中に書く内容を直接書いていきます。
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
ローカルのリソースを相対パスで読み込んでいる場合は?
CDN などから絶対パスでリソースを読み込んでいる場合は上記の通りでいいのですが、相対パスで指定したリソースがある場合は注意が必要です。
たとえば、ディレクトリ構成が以下のようになっていて、
.
├── .storybook
├── build .......... webpack でビルドした後のファイルの出力先
│ ├── assets
│ ├── index.html
│ └── bundle.js
├── node_modules
├── package.json
├── src ............ ビルド前のファイル置き場
└── webpack.config.js
npm 経由でインストールした CSS ライブラリなどを build/assets
以下にコピーし、index.html
で読み込んでいる場合です。
<link rel="stylesheet" href="assets/styles/foo/bar/main.css>
この場合、この <link>
タグをそのまま .storybook/head.html
にコピーしても正しく読み込んでくれません。
これについては今でも正解がわかっていないのですが、1つの解決策として start-storybook
の -s
オプションを使うという方法があります。
参考:Serving Static Files - React Storybook
start-storybook
コマンド実行時に
{
"scripts": {
"storybook": "start-storybook -s ./build"
}
}
のように指定すると、指定したディレクトリ内の静的リソースを利用することができるようになります。
あとは -s
で指定したディレクトリを起点とした相対パスを .storybook/head.html
に書けば OK です。