かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

React+Tailwind CSS+Storybook のプロジェクトを作成する

概要

記事一覧はこちらです。

ユーティリティーファーストとTailwind CSSのススメ の記事を読んで React+Tailwind CSS の組み合わせに興味を持ったのでサンプルプロジェクトを作成してみます。作成した Component を確認できるよう Storybook も入れてみます。

Typescript は導入せず Javascript で記述する想定です。

Node.js、npm、yarn は以下のバージョンを使用しています(Node.js と npm のバージョンが古いな。。。とは思いつつ今回はこのままでいきます)。

f:id:ksby:20210417130823p:plain

参照したサイト・書籍

  1. ユーティリティーファーストとTailwind CSSのススメ
    https://qiita.com/Takazudo/items/5180f5eb6d798a52074f

  2. Tailwind CSS
    https://tailwindcss.com/

  3. tailwindlabs / tailwindcss-forms
    https://github.com/tailwindlabs/tailwindcss-forms

  4. postcss / postcss - PostCSS 8 for end users
    https://github.com/postcss/postcss/wiki/PostCSS-8-for-end-users

    • ツールの PostCSS 8 の対応状況が表示されています。
  5. Install Tailwind CSS with Create React App
    https://tailwindcss.com/docs/guides/create-react-app

  6. gsoft-inc / craco
    https://github.com/gsoft-inc/craco

  7. Installation
    https://tailwindcss.com/docs/installation

  8. Configuration
    https://tailwindcss.com/docs/configuration

    • tailwindcss init コマンドの -p flag の説明はここに記述されていました。
  9. Storybook
    https://storybook.js.org/

  10. Install Storybook
    https://storybook.js.org/docs/react/get-started/install

  11. Introduction to Storybook for React
    https://storybook.js.org/docs/react/get-started/introduction

  12. Integrating React, Tailwind and Storybook
    https://johnclarke73.medium.com/integrating-react-tailwind-and-storybook-3ae124aff0d9

  13. Storybook-tailwind. How should I add tailwind to storybook
    https://stackoverflow.com/questions/65495912/storybook-tailwind-how-should-i-add-tailwind-to-storybook

目次

  1. create-react-app で react-taiwindcss-storybook-sample プロジェクトを作成する
  2. Tailwind CSS をインストールする
  3. CRACO をインストール・設定する
  4. npx tailwindcss init -p コマンドを実行して tailwind.config.js、postcss.config.js を作成する
  5. src/index.css を変更する
  6. src/App.css、src/App.js を変更して Tailwind CSS が利用できることを確認する
  7. npx sb init コマンドを実行して Storybook をインストールする
  8. babel-loader が 8.2.2 にバージョンアップされて yarn start 実行時にエラーが出るので 8.1.0 にバージョンダウンする
  9. .storybook/preview.js、.storybook/main.js を変更する
  10. src/stories を削除する
  11. component のサンプルを作成して Storybook 上に表示する

手順

create-react-app で react-taiwindcss-storybook-sample プロジェクトを作成する

コマンドプロンプトから以下のコマンドを実行し、プロジェクトを作成します。

  • cd /d/project-react/
  • npx create-react-app react-taiwindcss-storybook-sample
  • cd react-taiwindcss-storybook-sample/
  • yarn test を実行してテストが正常に終了することを確認します。
  • yarn start を実行してブラウザに React のロゴが表示されることを確認します。

Tailwind CSS をインストールする

Install Tailwind CSS with Create React App のページを参考に以下のコマンドを実行します。@tailwindcss/forms もインストールします。Tailwind CSS は PostCSS 8 に対応しているのですが create-react-app がまだ対応していないらしく、PostCSS 7 を使うようにする必要があるとのこと。

  • yarn add tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
    ※(2021/04/20追記)postcss、autoprefixer は yarn add -D でインストールした方がよい。
  • yarn add @tailwindcss/forms

f:id:ksby:20210417134455p:plain f:id:ksby:20210417134553p:plain

CRACO をインストール・設定する

引き続き Install Tailwind CSS with Create React App のページを参考に yarn add @craco/craco コマンドを実行して CRACO をインストールします。create-react-app の PostCSS の設定を変更するためにこのツールが必要とのこと。

f:id:ksby:20210417142247p:plain

package.json 内の scripts で react-scriptscraco に変更します。

  "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "craco eject"
  },

プロジェクトのルートディレクトリ直下に craco.config.js を作成し、以下の内容を記述します。

module.exports = {
  style: {
    postcss: {
      plugins: [
        require('tailwindcss'),
        require('autoprefixer'),
      ],
    },
  },
}

npx tailwindcss init -p コマンドを実行して tailwind.config.js、postcss.config.js を作成する

Installation のページを参考に npx tailwindcss init -p コマンドを実行して tailwind.config.js、postcss.config.js を作成します。

f:id:ksby:20210417140215p:plain

tailwind.config.js は以下の内容に変更します。

module.exports = {
  purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [
    require('@tailwindcss/forms'),
  ],
}
  • purgeに './src/**/*.{js,jsx,ts,tsx}', './public/index.html' を追加します。
  • plugins に require('@tailwindcss/forms'), を追加します。

postcss.config.js は作成されたままで何も変更しません。

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

src/index.css を変更する

src/index.css の中身を全てクリアし、以下の内容に変更します。

@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind forms;

src/App.css、src/App.js を変更して Tailwind CSS が利用できることを確認する

Tailwind CSS が利用できるようになっていることを確認します。

src/App.css の中身はどれも使用しないので全てクリアします。

src/App.js を Tailwind CSS を利用して文字列を表示するよう以下の内容に変更します。

import './App.css';

function App() {
  return (
    <div className="pt-4 pl-4 text-red-600 text-4xl font-extrabold">
      React+Tailwind CSS
    </div>
  );
}

export default App;

yarn start を実行すると、

f:id:ksby:20210417152746p:plain

ブラウザに以下のように表示されました。問題なく利用できるようになっています。

f:id:ksby:20210417152542p:plain

npx sb init コマンドを実行して Storybook をインストールする

Install Storybook のページを参考に npx sb init コマンドを実行して Storybook をインストールします。

f:id:ksby:20210417154911p:plain .......... f:id:ksby:20210417155013p:plain

yarn storybook コマンドを実行して、

f:id:ksby:20210417160145p:plain .......... f:id:ksby:20210417160243p:plain

Storybook の画面が表示されることを確認します。

f:id:ksby:20210417160941p:plain

babel-loader が 8.2.2 にバージョンアップされて yarn start 実行時にエラーが出るので 8.1.0 にバージョンダウンする

Storybook をインストールした後に yarn start を実行すると "babel-loader": "8.1.0" が必要とのエラーが出ます。

f:id:ksby:20210417161614p:plain

yarn.lock を見ると babel-loader が 8.2.2 になっていました。yarn add -D babel-loader@8.1.0 を実行してバージョンダウンします。

バージョンダウン後、再度 yarn start を実行すると今度は画面が表示されました。

.storybook/preview.js、.storybook/main.js を変更する

Tailwind CSS が適用されるよう .storybook/preview.js、.storybook/main.js を変更します。

.storybook/preview.js を以下のように変更します。

import '../src/index.css';

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
}
  • import '../src/index.css'; を追加します。

.storybook/main.js を以下のように変更します。Integrating React, Tailwind and StorybookStorybook-tailwind. How should I add tailwind to storybook を見てコピペしました。

const path = require('path');

module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/preset-create-react-app"
  ],
  webpackFinal: async (config) => {
    config.module.rules.push({
      test: /\,css&/,
      use: [
        {
          loader: 'postcss-loader',
          options: {
            ident: 'postcss',
            plugins: [
              require('tailwindcss'),
              require('autoprefixer')
            ]
          }
        }
      ],
      include: path.resolve(__dirname, '../'),
    })
    return config
  }
}
  • const path = require('path'); を追加します。
  • webpackFinal: async (config) => { ... } を追加します。

src/stories を削除する

src/stories に Storybook のサンプルが作成されていますが、不要なので削除します。

component のサンプルを作成して Storybook 上に表示する

src/components/sample ディレクトリを作成し、その下に ListItem.js、List.js の2つの component を作成します。

まずは ListItem.js から。以下の内容を記述します。

import React from 'react';

const ListItem = ({image, title, author}) => (
  <article className="p-2 flex space-x-4">
    <img className="flex-none w-16 h-16 rounded-lg" src={image} alt=""/>
    <div>
      <dl>
        <div>
          <dt className="sr-only">Title</dt>
          <dd className="text-2xl font-bold">{title}</dd>
        </div>
        <div className="mt-0.5">
          <dt className="sr-only">Author</dt>
          <dd className="text-sm font-semibold text-indigo-500">By {author}</dd>
        </div>
      </dl>
    </div>
  </article>
);

export default ListItem;

同じ階層に ListItem.stories.js を作成し、以下の内容を記述します。

import React from 'react';

import ListItem from './ListItem';
import dog from './dog.jpg';

export default {
  title: 'sample/ListItem',
  component: ListItem,
};

const Template = (args) => <ListItem {...args}/>;

export const Default = Template.bind({});
Default.args = {
  image: dog,
  title: 'サンプルブック1',
  author: '作者は犬',
};

Storybook で ListItem component を表示すると以下のように表示されました。

f:id:ksby:20210417214246p:plain

次は List.js。以下の内容を記述します。

import React from 'react';

import ListItem from "./ListItem";

const List = ({items}) => (
  <ul className="divide-y divide-gray-600">
    {items.map(item => (
      <ListItem key={item.title} {...item}/>
    ))}
  </ul>
);

export default List;

同じ階層に List.stories.js を作成し、以下の内容を記述します。

import React from 'react';

import List from './List';
import dog from './dog.jpg';
import cat from './cat.jpg';
import tiger from './tiger.jpg';

export default {
  title: 'sample/List',
  component: List,
};

const Template = (args) => <List {...args}/>;

export const Default = Template.bind({});
Default.args = {
  items: [
    {
      image: dog,
      title: 'サンプルブック1',
      author: '作者は犬',
    },
    {
      image: cat,
      title: 'サンプルブック2',
      author: '作者は猫',
    },
    {
      image: tiger,
      title: 'サンプルブック3',
      author: '作者はトラ',
    },
  ]
};

Storybook で List component を表示すると以下のように表示されました。

f:id:ksby:20210417214843p:plain

履歴

2021/04/17
初版発行。
2021/04/20
* yarn add babel-loader@8.1.0yarn add -D babel-loader@8.1.0 に変更しました。
* <ListItem {...item}/><ListItem key={item.title} {...item}/> に変更しました。