■ 概要
・背景
アトミックデザイン指向を考慮した、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
■ ほか
・静的出力
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 出力先
・デモ
-- アプリサンプル
-- ドキュメントサンプル