Closed15

next.jsにstorybookを導入したいんじゃ

sori883sori883

参考読んでる

やること

  • Next.jsの既存プロジェクトにStorybookを導入する
  • テストはUI、インテグレーション、a11yを予定
  • Chromaticでホスティング
  • ChromaticにはGiuhub Actionとかで自動デプロイ

その他気になるアドオンを試しつつ

sori883sori883

取り敢えずinit
monorepoでもいい感じに入った

cd packages/web
npx storybook init
sori883sori883

テンプレ通りにstories.tsxを作って確認してみる

component
import TagIcon from '@mui/icons-material/Tag';
import Chip from '@mui/material/Chip';
import Stack from '@mui/material/Stack';

type Props = {
  tagsOnArticles: string[];
}


export default function TagChip({tagsOnArticles}: Props): JSX.Element {
  return (
    <>
      <Stack direction="row" spacing={1}>
        {
          tagsOnArticles.map((tag) => (
            <Chip size='small' key={tag} icon={<TagIcon />} label={tag} />
          ))
        }
      </Stack>
    </>
  );
}
story.tsx
import { ComponentMeta, ComponentStory } from '@storybook/react';

import TagChip from './tagChip';

export default {
  title: 'Example/TagChip',
  component: TagChip,
} as ComponentMeta<typeof TagChip>;

const Template: ComponentStory<typeof TagChip> = (args) => <TagChip {...args} />;

export const single = Template.bind({});
single.args = {
  tagsOnArticles: ['tag1']
};

export const many = Template.bind({});
many.args = {
  tagsOnArticles: ['tag1','tag2','tag3']
};
sori883sori883

test runnerをつかってみようと思ったけどChromaticでいい気がする

Use it locally and Chromatic on your CI.
Use Chromatic for visual and interaction tests and run other custom tests using the test runner.

https://storybook.js.org/docs/react/writing-tests/test-runner#whats-the-difference-between-chromatic-and-test-runner

わかりやすい解説
https://zenn.dev/makotot/articles/b0729488282148

@storybook/test-runnerがテストするのは、play関数を持たないStoryであればStoryがエラーなくレンダリングされるかどうかをテストする。
play関数を持つStoryの場合はそのStoryがエラーなくレンダリングされるかどうかに加えてplay関数でエラーが発生しないこととアサーションをパスすることのよう。
https://zenn.dev/kyo9bo/articles/9909ba89c42a77

sori883sori883

コンポーネントでpublicRuntimeConfigを使用してるとエラーが出る

Cannot read property 'publicRuntimeConfig' of undefined

対処
https://dev.to/justincy/publicruntimeconfig-undefined-when-using-storybook-with-next-js-5ea9
addonもある
https://storybook.js.org/addons/storybook-addon-next#runtime-config

今回はaddonを採用
1個前でやったbaseUrlを反映させるのもやってくれるらしい

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
  ...,
  webpackFinal: async (config, { configType }) => {
       config.resolve.plugins = [new TsconfigPathsPlugin()];<-- this line
       return config;
  }
};
sori883sori883

muiのthemeを適用するにはpreview.jsで読み込む
_app.tsxで読み込むCSSとかもpreview.jsで適用する

import {ThemeProvider} from '@mui/material/styles'
import CssBaseline from '@mui/material/CssBaseline'
import theme from '../src/mui/theme'
import 'styles/globals.css';

export const decorators = [
    (Story) => {
      return (
        <ThemeProvider theme={theme}>
          <CssBaseline />
          <Story />
        </ThemeProvider>
      )
    },
]

https://zenn.dev/enish/articles/ff678649ecb6d9#3-2.-1つのthemeをすべてのファイルに適用したい場合

sori883sori883

emotionを設定したらReact is not definedになった
公式のFAQに対処法が乗ってた
https://storybook.js.org/docs/react/faq#i-see-referenceerror-react-is-not-defined-when-using-storybook-with-nextjs

Next automatically defines React for all of your files via a babel plugin. In Storybook, you can solve this either by:
1.Adding import React from 'react' to your component files.
2.Adding a .babelrc that includes babel-plugin-react-require

import React from 'react'を書きたくないので2を採用する

yarn add -D babel-plugin-react-require

main.jsに以下を追加

main.js
  babel: async (options) => ({
    ...options,
    presets: [...options.presets, '@emotion/babel-preset-css-prop'],
    plugins: ['react-require'] // 追加:React is not definedの対処
  }),
sori883sori883

現状のmain.js全体

main.js
const path = require('path')
module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    {
      name: 'storybook-addon-next',
      options: {
        nextConfigPath: path.resolve(__dirname, '../next.config.js')
      }
    }
  ],
  "framework": "@storybook/react",
  "core": {
    "builder": "@storybook/builder-webpack5"
  },
  babel: async (options) => ({
    ...options,
    presets: [...options.presets, '@emotion/babel-preset-css-prop'],
    plugins: ['react-require']
  }),
}
sori883sori883

public配下の画像表示するためにmain.jsに以下追加

main.js
staticDirs: ['../public'],
sori883sori883

Github Actionsで自動デプロイする
mainに対するプルリクのみにした

# Workflow name
name: 'Chromatic'

# Event for the workflow
on:
  pull_request:
    branches:
      - main

# List of jobs
jobs:
  chromatic-deployment:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Install dependencies
        run: yarn
      - name: Publish to Chromatic
        uses: chromaui/action@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} # Github Secretにトークンを登録する
          exitZeroOnChanges: true
このスクラップは2022/12/11にクローズされました