LoginSignup
1
2

More than 3 years have passed since last update.

Next.js(React) × TypeScript × Storybook の環境構築

Last updated at Posted at 2021-02-12

■ 概要

・背景

アトミックデザイン指向を考慮した、Next.jsとStyleBookを組み合わせた環境構築に少し手間取ったので、ここにその構築手順を記します。
※ Storybookは最低限のアドオンしか入れません。色々便利なアドオンがあるのでぜひ調べてみてください
=>リンク

・技術要件

技術 雑な説明 URL
React SPAフレームワーク。ほかにVue.jsやAngular.jsなどがある リンク
Next.js ReactでSSR/SSG(ISR)などを使えたりより使いやすくしたもの
(Vue.jsでいうNuxt.jsのようなもの)
リンク
TypeScript MSで開発された型安全なJavaScript言語 リンク
Storybook 既存のSPAコンポーネントをベースに
スタイルガイドを作成できるドキュメント生成ツール
リンク
アトミックデザイン フロントのプログラム設計手法の一つ。原子、分子、有機体、
テンプレ、ページと組み合わせていくことで設計する手法。
リンク
CSS Modules
CSS Loader
Style Loader
CSS Modulesは各モジュール単位でCSSを使えるようにしたもの。
Next.jsでは特定バージョン以降ビルトインされている。
CSS LoaderとStyle LoaderはStorybookにてそれを実現するためのもの
リンク

・前提

次がインストールされていること
  • npm(npx, yarn)
  • node.js

■ 手順

1. システム環境(React、Next.js、TypeScript)をインストールする

1-1. 下記コマンドをたたいてインストールする
$ npm init
$ npm install react react-dom next typescript

2. ドキュメント環境(Storybook)をインストールする。

1-1. 下記コマンドをたたいてインストールする
$ npm install -d @storybook/cli
1-2. 下記コマンドをたたいてStorybookのベースを生成する
$ npx -p @storybook/cli sb init
1-3. 下記コマンドをたたいて、サンプルを起動してみる
$ start-storybook -p 6006

3. アトミックデザインをベースに、コンポーネントを作成する

  • 名前は***.modules.cssにすること。また、構成は以下を想定。
  • サンプルはプロジェクト外に退避する(または削除する)
├─ .storybook
│  ├─ main.js
│  └─ preview.js
├─ components
│  ├─ atoms
│  │  └─ Button
│  │     ├─ Button.module.css
│  │     ├─ Button.tsx
│  │     └─ Button.stories.tsx
│  ├─ molecules
│  ├─ organisms
│  └─ templates
└─pages
   └─ buttonPage.tsx

1-1. 下記のファイルを作成する
components/atoms/Button/Button.module.css
.ukButtonKai {
    padding: 3.5px 10px 7px;
    border-radius: 3px;
    background-color:black;
    color:white;
}
components/atoms/Button/Button.tsx
import React from 'react';
import styles from './Button.module.css';

export interface ButtonProps {
    /** className */
    classNameString?: string;
    /** Index contents */
    label: string;
    /** Optional click handler */
    onClick?: () => void;
}

/**
 * Primary UI component for user interaction
 */
export const Button: React.FC<ButtonProps> = ({label, classNameString, ...props}) => {
    return (
        <a
            className={"uk-button uk-button-default " + styles.ukButtonKai + " " + classNameString}
            {...props}
        >
            {label}
        </a>
    );
};

pages/buttonPage.tsx
import React from "react";
import {Button} from "../components/atoms/Button/Button";
import Head from "next/head";

class buttonPage extends React.Component{
    render(){
        return (
            <>
                <Head>
                    <title>デモ</title>
                    {/* 例としてUIKitライブラリを入れている */}
                    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.5.5/css/uikit.min.css"/>
                </Head>
                <Button label={"Button"} />
            </>
        );
    }
}
export default buttonPage;
1-2. 下記コマンドをたたいてnextアプリを起動する
$ set NODE_ENV=production && npx next build && npx next start

=> http://localhost:3000/buttonPage

4. Storybookに読み込めるようにする

1-1. 下記コマンドをたたいて、CSS Module群のパッケージをインストールする
$ npm install -d style-loader css-loader
1-2. 下記のファイルを作成,修正
storybook/main.js
const path = require('path');

module.exports = {
  "stories": [
    //"../src/components/**/**/*.stories.mdx",
    "../components/**/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    '@storybook/addon-links',
    "@storybook/addon-essentials",
  ],

  webpackFinal: async (config) => {
    // remove default css rule from storybook
    config.module.rules = config.module.rules.filter((f) => f.test.toString() !== '/\\.css$/');

    config.module.rules.push({
      test: /\.css$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            modules: true,
          },
        },
      ],
    });

    return config;
  },
}
preview-head.html
<!-- 例としてUIKitライブラリを入れている -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.5.5/css/uikit.min.css" />
components/atoms/Button/Button.stories.tsx
import React from 'react';
// also exported from '@storybook/react' if you can deal with breaking changes in 6.1
import { Story, Meta } from '@storybook/react/types-6-0';
import {Button, ButtonProps} from "./Button";

export default {
    title: 'Components/Atoms/Button',
    component: Button
} as Meta;

const Template: Story<ButtonProps> = (args) => <Button {...args} />;

export const Sample = Template.bind({});
Sample.args = {
    classNameString: 'uk-text-small',
    label: 'ボタン',
};
1-3. 下記コマンドをたたいて、サンプルを起動してみる
$ start-storybook -p 6006

=> http://localhost:6006

■ ほか

・静的出力

next.config.js
module.exports = {
    basePath: '/', // コンテキストパス
}
# アプリ出力
$ npx build-storybook -o 出力先 -c .storybook --quiet
# Storybook出力
$ set NODE_ENV=production && npx next build && npx next export -o 出力先

・デモ

-- アプリサンプル
-- ドキュメントサンプル

・リファレンス

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2