📚

【StoryBook】Next.js + Tailwindcss + cssModule 環境でのStoryBook導入方法

2022/08/28に公開

概要

StoryBookとはフロントエンド開発において、様々なコンポーネントをアプリケーションから独立した状態でデザインや動作チェックなどを行い、さらにコンポーネント群をカタログ化して管理することのできる開発支援ツールです。

https://storybook.js.org

今回は、Next.js + Tailwindcss + cssModule の開発環境にStoryBookを導入する手順についてまとめました。
StoryBookインストール直後では、TailwindcssとcssModuleによるスタイルが適用されず、コンポーネントのデザインが全く確認できないため、その解決方法についても解説します。

導入手順

Next.js、Tailwindcss、cssModuleはインストール済の状態を前提として、StoryBookを追加で導入する方法を説明します。

StoryBookのインストール

次のコマンドでStoryBookに必要なライブラリ一式をインストールします。

npx sb init

インストール途中で"Do you want to run the 'eslintPlugin' fix on your project?を聞かれます。ESLintを使用してコードを検査している方は、“y”を選択してeslint-plugin-storybookをインストールしておくと良いかもしれません。

設定ライブラリのインストール

次のコマンドでstorybook-css-modules-presetライブラリをインストールします。
これをインストールすることで、簡単にcssmoduleをStoryBookに適用することができるようになります。

npm install --save-dev storybook-css-modules-preset

ライブラリのWEB公式サイト
!()[https://www.npmjs.com/package/storybook-css-modules-preset]

Storybookの設定

  1. Storyファイルのパス指定
    Storyファイルを格納するパスを設定します。各々の開発環境により、適宜ファイルパスを変えてください。
    私の開発環境ではコンポーネント群を./componentsフォルダ配下に格納しており、またStoryファイルもコンポーネントファイルと同階層に置くと決めたため、以下のような設定を追記しました。
./storybook/main.js
stories: ["../components/**/*.stories.@(js|jsx|ts|tsx)",]
  1. cssModuleの適用
    cssModuleでスタイル付けしたコンポーネントが、Storybook画面上でもスタイルが反映されるように設定を行います。
    次のコマンドでstorybook-css-modules-presetライブラリをインストールします。
npm install --save-dev storybook-css-modules-preset

Storybookの設定ファイルに以下を追記します。

./storybook/main.js
  addons: ["storybook-css-modules-preset",]
  1. cssの適用
    Next.jsにおいては、グローバルに適用するcssを./styles/global.cssに記述しており、またTailwindcssもこのファイルで読み込ませて、どのページからもtailwindのクラスを利用できるようにしているはずです。global.cssをStorybookに読み込ませる設定を行います。

まず、次のコマンドで公式のアドオンをインストールします。

npm install --save-dev @storybook/addon-postcss

Storybookの設定ファイルに以下を追記します。

./storybook/main.js
  addons: [
    {
      name: "@storybook/addon-postcss",
      options: {
        postcssLoaderOptions: {
          implementation: require("postcss"),
        },
      },
    },
  ],
./storybook/preview.js
import "../styles/globals.css";

設定結果

私の環境における設定結果を参考に以下に示します。

./storybook/main.js
module.exports = {
  stories: [
    "../stories/**/*.stories.mdx",
    "../stories/**/*.stories.@(js|jsx|ts|tsx)",
+    "../components/**/*.stories.@(js|jsx|ts|tsx)",
  ],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
+    "storybook-css-modules-preset",
+    {
+     name: "@storybook/addon-postcss",
+      options: {
+        postcssLoaderOptions: {
+          implementation: require("postcss"),
+        },
+      },
+    },
  ],
  framework: "@storybook/react",
  core: {
    builder: "@storybook/builder-webpack5",
  },
};

./storybook/preview.js
+ import "../styles/globals.css";

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
};

StoryBooksの起動

次のコマンドでStorybookを起動します。

npm run storybook

Storybookの起動後、ブラウザからhttp://localhost:6006/にアクセスするとStoryboookの画面が表示されます。EXAMPLEとして最初から登録されている、ButtonやHeaderなどのコンポーネントが確認できると思います。

自作のコンポーネントを登録してみる。

自作の汎用ボタンコンポーネントに対してStoryファイルを作成し、Storybookの画面上に表示されるまでの例を示します。

サンプルコード

  • まずはコンポーネント本体です
Button.tsx
import { ReactNode } from "react";
import styles from "./Button.module.css";

type Props = {
  children: ReactNode;
  disabled?: boolean;
  styleType: "primary" | "secondary" | "danger" | "disabled";
  onclick?: () => void;
};

/**
 * 共通Buttonコンポーネント
 * @param children コンポーネントで内包している子要素
 */
const Button = (props: Props) => {
  const { onclick, children, disabled, styleType } = props;

  // カラー切替
  let style = styles.primary;
  if (styleType === "secondary") {
    style = styles.secondary;
  } else if (styleType === "danger") {
    style = styles.danger;
  } else if (styleType === "disabled") {
    style = styles.disabled;
  }

  return (
    <button className={style} onClick={onclick} disabled={disabled}>
      {children}
    </button>
  );
};

export default Button;
  • cssModuleによるスタイルです
    Tailwindcssでがっつりスタイル付けしています。
Button.module.css
.primary {
  @apply inline-block py-2 px-10 text-sky-500 hover:text-gray-50 bg-gray-50 hover:bg-sky-500 border-2 border-sky-500 rounded-full shadow-sm font-semibold transition duration-300;
}

.secondary {
  @apply inline-block py-2 px-10 text-indigo-400 hover:text-gray-50 bg-gray-50 hover:bg-indigo-400 border-2 border-indigo-400 rounded-full shadow-sm font-semibold transition duration-300;
}

.danger {
  @apply inline-block py-2 px-10 text-red-500 hover:text-gray-50 bg-gray-50 hover:bg-red-500 border-2 border-red-500 rounded-full shadow-sm font-semibold transition duration-300;
}

.disabled {
  @apply inline-block py-2 px-10 text-gray-400  bg-gray-50 border-2 border-gray-400 rounded-full shadow-sm font-semibold transition duration-300;
}

  • コンポーネントに対するStoryファイルです。
    Storyファイルの記述方法についてはGoogleで検索すると多くの良記事が出てきますので、ここでは割愛します。
Button.stories.tsx
import { ComponentMeta, ComponentStoryObj } from "@storybook/react";
import Button from "./Button";

export default {
  title: "Molecules/Button",
  component: Button,
} as ComponentMeta<typeof Button>;

export const Primary: ComponentStoryObj<typeof Button> = {
  args: {
    children: "button text",
    disabled: false,
    styleType: "primary",
  },
};

export const Secondary: ComponentStoryObj<typeof Button> = {
  args: {
    children: "button text",
    disabled: false,
    styleType: "secondary",
  },
};

export const Danger: ComponentStoryObj<typeof Button> = {
  args: {
    children: "button text",
    disabled: false,
    styleType: "danger",
  },
};

export const Disabled: ComponentStoryObj<typeof Button> = {
  args: {
    children: "loading ...",
    disabled: true,
    styleType: "disabled",
  },
};

デモ

上記サンプルコードの動作デモになります。

まとめ

Next.js + Tailwindcss + cssModule の開発環境にStoryBookを導入する手順についてまとめました。
StorybookにTailwindcssとcssModuleを読み込ませる方法がやや難しいポイントでした。Googleで検索するといろいろな対処方法が出てくるのですが、これが一番簡単な方法かと思います。

バージョン

本記事執筆時の関連ライブラリのバージョンを貼っておきます。

"next": "12.2.3",
"tailwindcss": "^3.1.6",
"@storybook/addon-actions": "^6.5.10",
"@storybook/addon-essentials": "^6.5.10",
"@storybook/addon-interactions": "^6.5.10",
"@storybook/addon-links": "^6.5.10",
"@storybook/addon-postcss": "^2.0.0",
"@storybook/builder-webpack5": "^6.5.10",
"@storybook/manager-webpack5": "^6.5.10",
"@storybook/react": "^6.5.10",
"@storybook/testing-library": "^0.0.13",

参考文献

https://fwywd.com/tech/next-storybook-install

https://reffect.co.jp/html/storybook

Discussion