Open9

Next.js + TailwindcssのプロジェクトにStorybookを導入

hirotakahirotaka

Next.js + Tailwindcss + Typescripで構築しているプロジェクトにStorybookを導入します。Next.jsでプロジェクトを作成して、Vercelで公開するまでをまとめます。

技術スタックは下記の通りです。

  • Next.js
  • Tailwindcss
  • Storybook
  • Typescript
hirotakahirotaka

Next.jsのセットアップ

nextjsでアプリを作成します。

npx create-next-app --ts --use-npm nextjs-tailwindcss-storybook

Typescript化します。

cd nextjs-tailwindcss-storybook
npm install --save-dev typescript @types/react
touch tsconfig.js

Next.jsを起動します。

npm run dev

https://localhost:3000をブラウザで開いて、Next.jsのウェルカムページがでればOK。

hirotakahirotaka

Tailwindcssのセットアップ

tailwindcssをセットアップします。

npm install --save-dev tailwindcss postcss autoprefixer

設定ファイルを生成します。

npx tailwindcss init -p

tailwind.config.jsを編集します。

tailwind.config.js
module.exports = {
-  purge: [],
+ purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

styles/global.cssを下記の内容に書き換えます。

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

pages/index.jsstyles/Home.module.cssは削除します。

pages/index.tsxを作成して、内容は下記の通りにします。

pages/index.tsx
export default function Home() {
  return (
    <div>
      <h1 className="text-red-500">Hello, World!</h1>
    </div>
  );
}

「Hello, World!」が赤文字で出力できればセットアップ完了です。

hirotakahirotaka

Storybookのセットアップ

Storybookをセットアップします。

必要なパッケージ類をインストールします。

npm install --save-dev @storybook/addon-actions @storybook/addon-essentials @storybook/addon-links @storybook/react @storybook/addon-postcss

.storybook/main.jsというファイル名で設定ファイルを作成します。

.storybook/main.js
module.exports = {
  stories: ["../stories/**/*.stories.@(js|mdx|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-postcss",
  ],
};

公式のドキュメントでは、pagesと同じ階層に.stories.tsxをおくのが慣習のようですが、Next.jsだとこれだとビルド時に問題があるので別のディレクトリにいれるようにしています。

先ほど設定した、Next.jsとは別の仕組みでコンポーネントを表示するので、Storybookに表示するためのファイルを作成します。

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

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
};

Storybookを起動するためのスクリプトを、package.jsonに追加します。

package.json
"scripts": {
  "dev": "next dev",
  "build": "next build",
-  "start": "next start"
+  "start": "next start",
+  "storybook": "start-storybook -s public -p 6006",
+  "storybook:build": "build-storybook -s public"
},

試しに、ホームページのストーリーを作成します。

stories/pages/index.stories.tsx
import Home from "./index";

export default {
  title: "pages/Home",
  component: Home,
};

const Template = () => <Home />;

export const Default = Template.bind({});
Default.args = {};

Stoybookを起動します。

npm run storybook

http://localhost:6006に接続して、Storybookで内容を確認できます。

hirotakahirotaka

HTMLのソースの表示

コードを表示するのに、公式がだしているStorysourceというアドオンがあります。

https://storybook.js.org/addons/@storybook/addon-storysource

ただ、Tailwindcssの場合、ストーリーのソースよりも、TaiwindUIみたいにReactのソースをコピペできると便利なんだけどな。それっぽいアドオンは見当たらない。

とりあえず、HTMLのソースが@whitespace/storybook-addon-htmlがよさそう。

npm install --save-dev @whitespace/storybook-addon-html

.storybook/main.jsにアドオンを追加します。

.storybook/main.js
module.exports = {
  stories: ["../pages/**/*.stories.@(js|mdx|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-postcss",
    "@storybook/addon-postcss",
+    "@whitespace/storybook-addon-html",
  ],
};

「HTML」というタブが表示されて、コードを参照できるようになります。

hirotakahirotaka

Storysourseアドオンの追加

ストーリーでコードを表示できるようにStorysourceアドオンを追加。

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

TypescriptだとStorysourceでソースが表示できないの、webpackの設定を追加。

.storybook/main.js
addons: [
 ...
  "@storybook/addon-storysource",
],
webpackFinal: async (config) => {
  // remove existing source-loader in place
  config.module.rules.splice(6, 1);
  config.module.rules = [
    ...config.module.rules,
    {
      test: /\.stories\.[jt]sx?$/,
      loaders: [
        {
          loader: require.resolve("@storybook/source-loader"),
          options: { parser: "typescript", injectStoryParameters: false },
        },
      ],
      enforce: "pre",
    },
  ];
  return config;
},
hirotakahirotaka

画像の表示

Next.jsでpublicに入れた画像を表示する場合、Storybookでも表示するには、起動オプションで指定します。

下記のようにオプションを追加します。

package.json
 "storybook": "start-storybook -s public -p 6006"
hirotakahirotaka

next/imageの表示

next/imageを使っていると、Storybookで表示できないので、下記をpreview.jsに追加する。

.storybook/preview.js
import * as NextImage from 'next/image'

const OriginalNextImage = NextImage.default
Object.defineProperty(NextImage, 'default', {
  configurable: true,
  value: (props) => <OriginalNextImage {...props} unoptimized />,
})

参考

https://github.com/vercel/next.js/issues/18393#issuecomment-783269086

hirotakahirotaka

vercelにデプロイ

GitHubなどにコミットしておきます。

Vercelのダッシュボードから新しくプロジェクトを作成して、リポジトリの一覧から該当のリポジトリを選択します。

それぞれの欄に下記を参考に入力します。

  • PROJECT NAME
    デフォルトでリポジトリ名になるので、そのままでよければそのままで、アプリ自体もVercelで公開する場合は、名前が被ってしまうので何か別の名前を入力します
  • FRAMEWORK PRESET
    「Other」を選択します

「Build and Output Settings」には下記を入力します。

  • BUILD COMMAND: npm run storybook:build
  • OUTPUT DIRECTORY: storybook-static
  • INSTALL COMMAND: npm install

以上で「Deploy」ボタンを押して、デプロイを開始します。