[Next.js] Storybook V7

[Next.js] Storybook V7

2023-05-29 hit count image

TypeScriptをベースにしたNext.jsのプロジェクトにStorybookのV7を使ってコンポーネント主導開発をやってみましょう。

概要

今期あのブログポストではTypeScriptをベースにしたNext.jsプロジェクトでStorybookを使ってコンポーネント主導開発(Component Driven Development)をしてみます。

今回のブログポストではStorybookV7バージョン(next)を使う方法を調べる予定です。V6バージョンを使う方法については次のリンクを確認してください。

ここで紹介するソースコードは下記のリンクで確認できます。

TypeScriptベースNext.jsプロジェクト生成

TypeScriptが適用されたNext.jsStorybookを使うため、次のコマンドを実行してTypeScriptが適用されたNext.jsプロジェクトを生成します。

npx create-next-app --typescript start-storybook-v7

Storybookのインストール

TypeScriptが適用されたNext.jsプロジェクトでStorybookを使ってコンポーネント主導開発をするためにはStorybookをインストールする必要があります。下記のコマンドを実行してStorybookをインストールします。

# cd start-storybook-v7
npm install --save-dev [email protected]

Storybookの初期化

Storybookを使うためにはStorybookを初期化して必要なライブラリをインストールする必要があります。次のコマンドを実行してStorybookを初期化します。

そしたら、次のように自動でStorybookが初期化せれることが確認できます。

  storybook init - the simplest way to add a Storybook to your project.

 • Detecting project type. ✓
 • Adding Storybook support to your "Next" app

added 318 packages, and audited 1125 packages in 54s

226 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
. ✓
 • Preparing to install dependencies. ✓

最後の下記のような質問が出ますが。

? Do you want to run the 'eslintPlugin' migration on your project? › (Y/n)

ESLintを使ってコードを検査する場合、yを押して進めます。逆に使ってない場合nを押して進めます。このブログポストではyを押して進めました。

その後、次のようにStorybookが自動で必要なライブラリをインストールし、Storybookを実行するスクリプトを自動で追加することが確認できます。

Storybook V7 configuration automatically
{
   ...
   "scripts": {
    ...
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  },
  ...
  "devDependencies": {
    "@storybook/addon-essentials": "^7.0.0-rc.8",
    "@storybook/addon-interactions": "^7.0.0-rc.8",
    "@storybook/addon-links": "^7.0.0-rc.8",
    "@storybook/blocks": "^7.0.0-rc.8",
    "@storybook/nextjs": "^7.0.0-rc.8",
    "@storybook/react": "^7.0.0-rc.8",
    "@storybook/testing-library": "^0.0.14-next.1",
    "eslint-plugin-storybook": "^0.6.11",
    "storybook": "^7.0.0-rc.8"
    ...
  }
}

また、次のようにStorybookを使う方法を教えるため、サンプルコードが一緒に生成されることが確認できます。

  • ./.storybook/...: Storybookに関する設定ファイル
  • ./stories/...: Storybookのサンプルコード

ESLintを使うように設定したので、.eslintrc.jsonファイルを開くと下記のように変更されたことが確認できます。

{
  "extends": [
    "next/core-web-vitals",
    "plugin:storybook/recommended"
  ]
}

publicフォルダ設定

Next.jspublicフォルダにあるstaticファイル(イメージ)をStorybookで認識できるようにするためmain.tsファイルを開いて下記のように修正します。

import type { StorybookConfig } from '@storybook/nextjs'
const config: StorybookConfig = {
  ...
  docs: {
    autodocs: 'tag',
  },
  staticDirs: ['../public'],
}
export default config

Storybookの実行

今まで設定したStorybookを実行して、Storybookがうまくインストールされたか確認してみましょう。次のコマンドを実行してStorybookを実行します。

npm run storybook

そしたらブラウザでhttp://localhost:6006/が自動で開けて、下記のような画面が確認できます。

Storybook V7 first screen

当該画面は./stories/Introduction.mdxファイルが表示された画面になります。

Storybook確認

実行されたStorybookの左メニューのButton > Primaryを選択すると次のような画面が確認できます。

Storybook V7 button sample

この画面は./stories/Button.stories.tsファイルが表示された画面です。

サンプルコード確認

もっと詳しく調べるためサンプルコードを確認してみましょう。Buttonコンポーネント(./stories/Button.tsx)は次のようです。

import React from 'react';
import './button.css';

interface ButtonProps {
  primary?: boolean;
  backgroundColor?: string;
  size?: 'small' | 'medium' | 'large';
  label: string;
  onClick?: () => void;
}

export const Button = ({
  primary = false,
  size = 'medium',
  backgroundColor,
  label,
  ...props
}: ButtonProps) => {
  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
  return (
    <button
      type="button"
      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}
      {...props}
    >
      {label}
      <style jsx>{`
        button {
          background-color: ${backgroundColor};
        }
      `}</style>
    </button>
  );
};

Buttonコンポーネントはprimary, backgroundColorなど色んなPropsを持ってることが確認できます。次はStorybookファイル(./stories/Button.stories.ts)の内容を確認してみましょう。

import type { Meta, StoryObj } from '@storybook/react';

import { Button } from './Button';

const meta: Meta<typeof Button> = {
  title: 'Example/Button',
  component: Button,
  tags: ['autodocs'],
  argTypes: {
    backgroundColor: {
      control: 'color',
    },
  },
};

export default meta;
type Story = StoryObj<typeof Button>;

export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
  },
};

export const Secondary: Story = {
  args: {
    label: 'Button',
  },
};

export const Large: Story = {
  args: {
    size: 'large',
    label: 'Button',
  },
};

export const Small: Story = {
  args: {
    size: 'small',
    label: 'Button',
  },
};

まず、Storybookの画面構成に必要な情報を準備します。

import type { Meta, StoryObj } from '@storybook/react';

import { Button } from './Button';

const meta: Meta<typeof Button> = {
  title: 'Example/Button',
  component: Button,
  tags: ['autodocs'],
  argTypes: {
    backgroundColor: {
      control: 'color',
    },
  },
};

export default meta;
type Story = StoryObj<typeof Button>;
...

metaStorybookで表示する基本情報を設定します。metaに設定したtitleStorybookの左メニューに表示される名前を表れて、/を使ってグループを作ることができます。サンプルコードではExampleグループの下にButtonと言う名前で表示されることが確認できます。

Storybook V7 meta information

metacomponentはこのStorybookで表示するコンポーネントを指定します。サンプルではButtonコンポーネントを指定しました。

tags: ['autodocs']は自動でドキュメント(Document)を作成する新しい機能です。この値を設定すると上のイメージようにExample/Buttonメニュー下にDocsが自動で生成されることが確認できますし、ここでStorybookファイルで作成した内容がドキュメント形で確認できます。

このように画面構成に必要な情報を設定したら、次は実際画面に表示されるStoryを作成します。次のようにコンポーネントのPropsを設定したり、変更したがらStoryを作成することができます。

...
export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
  },
};

export const Secondary: Story = {
  args: {
    label: 'Button',
  },
};

export const Large: Story = {
  args: {
    size: 'large',
    label: 'Button',
  },
};

export const Small: Story = {
  args: {
    size: 'small',
    label: 'Button',
  },
};

Storybookの設定

現在はStorybookを作成するためには./storiesフォルダで作成する必要があります。しかし、普通はコンポーネントは./componentsフォルダを作って管理するようにします。

このようにStorybookを他のフォルダで作成するためには./.storybook/main.tsファイルを修正する必要があります。./.storybook/main.tsファイルを開いて下記のように修正します。

import type { StorybookConfig } from '@storybook/nextjs';
const config: StorybookConfig = {
  stories: [
    '../@(stories|components)/**/*.mdx',
    '../@(stories|components)/**/*.stories.@(js|jsx|ts|tsx)',
  ],
  ...
};
...

次はstoriesフォルダ以外にcomponentsフォルダでも.stories.tsファイル名を持ってれば、Storybookがこれを認識して画面に表示するようになります。これを確認するため./components/SampleButtonフォルダを生成して次のファイルをコピーします。

  • ./stories/button.css > ./components/SampleButton/index.css
  • ./stories/Button.stories.ts > ./components/SampleButton/index.stories.ts
  • ./stories/Button.tsx > ./components/SampleButton/index.tsx

そして./components/SampleButton/index.tsxファイルを開いて下記のように修正します。

...
import './index.css';
...
export const SampleButton = ({
   ...
}: ButtonProps) => {
   ...
};

そして./components/SampleButton/index.stories.tsファイルを開いて下記のように修正します。 파일을 열어서 다음과 같이 수정합니다.

...
import { SampleButton } from '.';

const meta: Meta<typeof SampleButton> = {
  title: 'Sample/Button',
  component: SampleButton,
  ...
};

export default meta;
type Story = StoryObj<typeof SampleButton>;
...

Storybookの設定を変更したらこれを反映するため、現在実行してるStorybookを終了させて再び実行します。 Storybookが再び実行されると下記のように私たちが作ったSampleButtonがうまく表示されることが確認できます。

Storybook V7 SampleButton

完了

今回のブログポストではTypeScriptをベースにしたNext.jsプロジェクトでコンポーネント主導開発をするためStorybook V7を設定する方法についてみてみました。以前のバージョンより使いやすくなって、もっと直感的に変更されたことが確認できました。以前のバージョンのStorybookを設定して使う方法については次のリンクを確認してください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。

Posts