For

2023.1.31

Next.jsプロジェクトにStorybookとTailwindを導入してStorybookにTailwindのクラスによるスタイルを適用しStorybookのテストを通す

概要

Storybookを立ち上げてコンポーネントをブラウザで確認するとき、Tailwindのスタイルを適用する方法を公開します。
Storybook公式ドキュメントの Integrate Tailwind CSS and Storybook にTailwindとStorybookの連携方法がありますが、内容が古くてそのままでは動作しないところもあるため、記事にしておこうと思います。
最終的には @storybook/test-runner まで導入し、StorybookのInteraction testsを通すところまで実装します。

Next.jsプロジェクトの作成

今回はせっかくなのでNext.jsのプロジェクトを作成するところからやりたいと思います。

bash_____terminal_____$ npx create-next-app --typescript

Ok to proceed? (y) y
✔ What is your project named? … next-tailwind-storybook
✔ Would you like to use ESLint with this project? … No / Yes
✔ Would you like to use `src/` directory with this project? … No / Yes
✔ Would you like to use experimental `app/` directory with this project? … No / Yes
✔ What import alias would you like configured? … @/*
Creating a new Next.js app in /Users/kobayashi/files/projects/io-kobayashiii/next-tailwind-storybook.

Using npm.

Installing dependencies:
- react
- react-dom
- next
- @next/font
- typescript
- @types/react
- @types/node
- @types/react-dom
- eslint
- eslint-config-next

added 270 packages, and audited 271 packages in 28s

102 packages are looking for funding


終わったら作成したプロジェクトのディレクトリに移動して yarn or npm i しておきます。
またこの記事ではyarnを利用するので package-lock.json は削除しておきます。

Tailwindの導入

bash_____terminal_____yarn add -D tailwindcss postcss autoprefixer


bash_____terminal_____npx tailwindcss init -p

Created Tailwind CSS config file: tailwind.config.js
Created PostCSS config file: postcss.config.js


上記で生成された tailwind.config.js を以下のように編集します。

JavaScript_____tailwind.config.js_____/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
};


続いて globals.css を以下のように編集します。

css_____globals.css_____@tailwind base;
@tailwind components;
@tailwind utilities;


これで yarn dev をして適当なタグに bg-gray-200 などクラスを付与して適用されれば導入完了です。

Storybookの導入

bash_____terminal_____npx storybook init


bash_____terminal_____yarn storybook


ブラウザで以下のような画面で npx storybook init で作成されたサンプルのコンポーネントなどが確認できればOKです。


TailwindとStorybookの統合

bash_____terminal_____yarn add -D concurrently


続いて package.json のscriptsに以下を追加します。
※scriptsに追加する部分だけ記載します。

json_____package.json_____{
  // ...,
  "scripts": {
    // ...,
    "build-storybook": "concurrently \"yarn:build:*\"",
    "build:css": "npx tailwindcss -i ./src/styles/globals.css -o ./public/globals.css",
    "build:storybook": "build-storybook",
    "watch-storybook": "concurrently \"yarn:watch:*\"",
    "watch:css": "npx tailwindcss -i ./src/styles/globals.css -o ./public/globals.css --watch",
    "watch:storybook": "start-storybook -p 6006"
  },
  // ...
}


続いて以下のファイルを作成します。

html_____./storybook/preview-head.html_____<link href="/globals.css" rel="stylesheet" />


そして yarn watch-storybook を実行し、最後に src/stories/Button.tsx{lable} となっているところを試しに <span className="text-green-700">{label}</span> としてみて、ブラウザで立ち上がっているStorybookの画面をリロードして文字が緑になっていればOKです。
リロードしなければいけないのは、現状でTailwindのクラスをあとからコンポーネントに付与してStorybookをホットリロードする方法がわからないためです。
2023/01/31時点で調べてみて見つかりませんでした。

Storybookのtest-runnerを導入

bash_____terminal_____yarn add -D @storybook/test-runner @storybook/addon-coverage


.storybook/main.js のaddonsに @storybook/addon-coverage を追加します。

JavaScript_____.storybook/main.js_____module.exports = {
  stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
    '@storybook/addon-coverage', // <- here
  ],
  framework: '@storybook/react',
  core: {
    builder: '@storybook/builder-webpack5',
  },
}; 


続いて package.json のscriptsに以下を追加します。

json_____package.json_____{
  // ...,
  "scripts": {
    // ...,
    "test-storybook": "test-storybook --coverage"
  },
  // ...
}


最後に yarn test-storybook でテストが通過したら完了です。

bash_____terminal_____yarn test-storybook
yarn run v1.22.19
$ test-storybook --coverage
 PASS   browser: chromium  src/stories/Header.stories.tsx
 PASS   browser: chromium  src/stories/Page.stories.tsx
 PASS   browser: chromium  src/stories/Button.stories.tsx

Test Suites: 3 passed, 3 total
Tests:       8 passed, 8 total
Snapshots:   0 total
Time:        3.292 s
Ran all test suites.
Coverage file (8762 bytes) written to .nyc_output/coverage.json
------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |   81.81 |      100 |   66.66 |   81.81 |                   
Button.tsx |     100 |      100 |     100 |     100 |                   
Header.tsx |     100 |      100 |     100 |     100 |                   
Page.tsx   |   66.66 |      100 |      50 |   66.66 | 18-19             
------------|---------|----------|---------|---------|-------------------
✨  Done in 5.27s.