KJ DEV
How to

CSS ModulesをStorybookで適用するために必要なwebpackの設定

ReactやVueを使っているとCSS Modulesでコンポーネントのスタイルを適用するがあります。

CSS Modulesを使うことで1つのコンポーネントに対して1つのスタイルシートを適用でき、ローカルスコープが適用できたりするので、とても便利です。
そんな便利なCSS Modulesですが、Storybookを使うときには注意が必要です。

webpackの設定で適切なオプションを記述しておかないと、スタイルが当たらない状態になってしまいます。

目次
  1. Storybookのcss-loaderオプションを設定する
  2. css-loaderのオプション
    1. importLoaders
    2. modules.mode
    3. modules.localIdentName
    4. modules.context
    5. modules.hashPrefix
  3. まとめ

Storybookのcss-loaderオプションを設定する

まずStorybookでもCSS Modulesを使ったスタイル指定が動くwebpackの設定が下記です。
このコードはStorybookのissueでコメントされていたものです。

https://github.com/storybookjs/storybook/issues/2320

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports = async ({ config, mode }) => {
    config.module.rules.push({
        test: /\.scss$/,
        loaders: [
            require.resolve('style-loader'),
            {
                loader: require.resolve('css-loader'),
                options: {
                    importLoaders: 1,
                    modules: {
                        mode: 'local',
                        localIdentName: '[path][name]__[local]--[hash:base64:5]',
                        context: path.resolve(__dirname, 'src'),
                        hashPrefix: 'my-custom-hash',
                    },
                },
            },
            require.resolve('sass-loader')
        ],
    });

    return config;
}

今回重要になるのはcss-loaderの部分です。

css-loaderのオプション

指定しているオプションを順番にみていきます。
css-loaderのオプションについてはwebpackの公式で説明があります。

https://webpack.js.org/loaders/css-loader

それぞれのオプションを日本語訳にかけてみました。

importLoaders

> タイプ:数値デフォルト:0
>
> CSSローダーの前に適用されるローダーの数を有効/無効または設定します。
>
> オプションimportLoadersを使用すると、css-loaderを@importedリソースに適用する前にローダーの数を構成できます。

modules.mode

> タイプ:文字列|関数デフォルト: 'local'
>
> セットアップモードオプション。 ローカルモードが必要な場合は、値を省略できます。
>
> ストリング
> 可能な値-ローカル、グローバル、および純粋。

modules.localIdentName

> タイプ:文字列デフォルト: '[hash:base64]'
>
> 生成されたIDは、localIdentNameクエリパラメータで構成できます。 オプションの詳細については、loader-utilsのドキュメントを参照してください。
>
> 推奨事項:
>
> 開発には「[パス] [名前] __ [ローカル]」を使用
> 本番には「[hash:base64]」を使用
> [local]プレースホルダーには、元のクラスが含まれています。
>
> 注:予約済みおよび制御ファイルシステムの文字([local]プレースホルダー内の文字を除く)はすべて-に変換されます。

modules.context

> タイプ:文字列デフォルト:未定義
>
> ローカルID名の基本ローダーコンテキストを再定義できます。 デフォルトではローダーのrootContextを使用します。

modules.hashPrefix

> タイプ:文字列デフォルト:未定義
>
> カスタムハッシュを追加して、よりユニークなクラスを生成できるようにします。

まとめ

Storybookはwebpackの設定を個別に設定する必要があるのでハマりがちです。

フレームワークを使っていると内部でよしなにやってくれている場合なんかだと、アプリは動いているのにStorybookでは正しく動いてくれない・・。
こういうときは大体Storybookのwebpackの設定を見直すことで解決できることが大半です。

今回のようにstorybookでCSS Modulesを使うにはcss-loaderの設定が必要ということを頭に置いておくと良いと思います。

開発で参考になった本

実際に読んでみて開発に役立った本を紹介しています。

これから本格的にデザインシステムを学んで作りたい時にとても参考になる一冊でした。デザインシステムついて幅広く触れられているけど、「tailwindを触ってデザインシステムに興味を持った」という人でも少しずつ取り入れやすいです。