【Storybook】Rails × React × Webpacker環境にStorybookを導入してみた件

Storybook
  • URLをコピーしました!

こんにちは!RYOTAです!

当記事をご覧いただきありがとうございます!

プロジェクトでStorybookを導入したので、その際のハマりポイントをまとめた記事となります。

目次

はじめに

現在、本業で所属している会社がドキュメント化の文化がなかったので、ドキュメント整備の観点からStorybookを導入してみました。

Vue.js / ReactのSPA環境にStorybookを導入したことはあったのですが、今回導入したプロジェクトがRailsのモノリス構成でテンプレートからReactコンポーネントを呼び出している形だったので、ビルドの設定にそこそこハマってしまいました。

今後の備忘録を兼ねてエラー内容と対処法をまとめます。

環境

今回Storybookを導入した環境は以下の通りです。

  • Ruby: 2.7.3
  • Ruby on Rails: 6.1.4
  • webpakcer: 5.4.3
  • webpacker-react: 0.3.2
  • slim-rails: 3.4.0
  • sass-rails: 6.0.0
  • @svgr/webpack: 5.5.0

モノリスRailsでテンプレートにSlimを使用し、その中でReactコンポーネントを呼び出しています。

CSSはmoduleでsassを呼び出していて、ビルドはwebpackerで行なっています。

エラー&対処

Sassビルドエラー

Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

ERROR in {path}/style.sass 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> .container
|   display: flex
|   justify-content: flex-end

まず一つ目のエラーはSassのコンパイル。

シンプルにWebpackがSassを認識できていないので、ロード時に上記のエラーが出てしまいました。

Sassビルド対応

対応としては.storybook直下にあるmain.jsにWebpackのビルド設定を記述することで解決しました。

module.exports = {
  stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: ['@storybook/addon-essentials', '@storybook/addon-links'],
  framework: '@storybook/react',

  // ~~ ここから追加 ~~
  webpackFinal: async (baseConfig) => {
    baseConfig.module.rules.push(
        test: /\.sass$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              modules: {
                localIdentName: '[local]___[hash:base64:2]',
              },
            },
          },
          'sass-loader',
        ],
      }
    );

    return { ...baseConfig };
  },
  core: {
    builder: 'webpack5',
  },
  // ~~ ここまで追加 ~~
};

下記のローダーをインストールすると逆にビルド出来ない現象が発生したので注意が必要

  • style-loader
  • css-loader
  • sass-loader

(いやいやいや、指定するのに入ってるとダメとか意味わからん。)

SVGビルドエラー

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it’s defined in, or you might have mixed up default and named imports.

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

お次はSVGのエラー。

Reactコンポーネント内でSVGファイルをコンポーネントとして呼び出す際に@svgr/webpackを使用しているのですが、こちらが認識されていないっぽいですね。

SVGビルド対応

module.exports = {
  stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: ['@storybook/addon-essentials', '@storybook/addon-links'],
  framework: '@storybook/react',
  webpackFinal: async (baseConfig) => {
    // ~~ 下記一行追加 ~~
    baseConfig.module.rules.find((rule) => rule.test && rule.test.test('.svg')).exclude = /\.svg$/;
    baseConfig.module.rules.push(
      // ~~ ここから追加 ~~
      {
        test: /\.svg$/,
        use: ['@svgr/webpack', 'file-loader'],
      },
      // ~~ ここまで追加 ~~
      {
        test: /\.sass$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              modules: {
                localIdentName: '[local]___[hash:base64:2]',
              },
            },
          },
          'sass-loader',
        ],
      }
    );

    return { ...baseConfig };
  },
  core: {
    builder: 'webpack5',
  },
};

特に7行目のexclude設定が大事っぽい。(今回ハマったのがここ。)

baseConfig.module.rules.find((rule) => rule.test && rule.test.test('.svg')).exclude = /\.svg$/;

TSエイリアスインポートエラー

ModuleNotFoundError: Module not found: Error: Can’t resolve ‘@{alias}/{path}’ in ‘{path}’

ModuleNotFoundError: Module not found: Error: Can't resolve '@{alias}/{path}' in '{path}'

そんなモジュールはないと怒られてますね。

こちらはシンプルでtsconfig.jsonで記述したpathsの設定ではTypeScriptの中でエイリアスの認識が出来るものの、Webpack側がそれを認識できないので設定を追加してあげる必要があります。

tsconfig-paths-webpack-pluginというプラグインを使ってあげると簡単に設定ができるのでサクッとインスコしましょう。

$ yarn add --dev tsconfig-paths-webpack-plugin
// ~~ 下記二行追加 ~~
const path = require('path');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');

module.exports = {
  stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: ['@storybook/addon-essentials', '@storybook/addon-links'],
  framework: '@storybook/react',
  webpackFinal: async (baseConfig) => {
    baseConfig.module.rules.find((rule) => rule.test && rule.test.test('.svg')).exclude = /\.svg$/;
    baseConfig.module.rules.push(
      {
        test: /\.svg$/,
        use: ['@svgr/webpack', 'file-loader'],
      },
      {
        test: /\.sass$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              modules: {
                localIdentName: '[local]___[hash:base64:2]',
              },
            },
          },
          'sass-loader',
        ],
      }
    );

    // ~~ 下記二行追加 ~~
    baseConfig.resolve.modules = [...(baseConfig.resolve.modules || []), path.resolve(__dirname, '../app')];
    baseConfig.resolve.plugins = [...(baseConfig.resolve.plugins || []), new TsconfigPathsPlugin()];

    return { ...baseConfig };
  },
  core: {
    builder: 'webpack5',
  },
};

以上。無事動作!

さいごに

という訳で今回はモノリスのRails×Reactの環境にStorybookを突っ込んでみました。

ビルド設定に地味にハマりましたが、Webpackちゃんと久々に対話出来たので楽しかったです。

(しばらくやりたくない、、、)

以上。

最後までご覧くださりありがとうございました!

少しでも参考になれば幸いです!

Storybook

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次