見出し画像

Next.js に Storybook を導入のためにやったことと得たこと

雑食系エンジニアの TNK です。

サーバーサイドに比べて牧歌的だったフロントエンドも2021年の現在では高度に発展しており、 config がプロジェクトの全てを決める気がします。

この度 Next.js に Storybook を導入しました。
Storybook を導入する主な目的としては、下記の通りでした。

* レビューの負担軽減 
* 開発者以外の確認 -> 修正のサイクルを早くする

今の開発サイクルでは、ローカル環境か Staging 環境しか用意しておらず、まだβフェーズでデプロイサイクルが比較的長いため、 Staging にデプロイするまで開発者以外の確認ができないことがネックになっていました。

コードジェネレーターを導入

決まった書式を繰り返すため、hygen を導入しました。

hygen で作成されるファイルは以下の通りです。

* [component].tsx
* [component].test.tsx
* [component].stories.tsx
* style.modules.css

Atomic Design を導入

これは最後まで導入するか迷いました。

Storybook で Templates を確認できるようになると圧倒的に捗るという予想だったのですが、 Atomic Design の設計に関してWeb上であまり言及されてはおらず、 Redux と接続するコンポーネントをどこに配置するか迷ったからです。

それでも導入した主な理由は、独自ルールを採用しないことで、開発メンバーが別のプロジェクトに移動した時にジョインしやすくするです。

現在のところの考え方としては、 Atomic design + Redux に関しては下記を原則としています。

* Atoms、Molecules では Redux とは接続しない
* Redux と接続する場合は Organisms として扱う

Redux と接続する時点で、Redux に依存した Organisms になっているのであまり迷うことではなかったのかもしれません。

Tailwindcss + CSS Modules の設定を追加

postcss.config.jstailwind.config.js は Next.js と共通のものを使えるのですが、webpack の設定は Storybook に別途必要です。

   newConfig.module.rules.find(
     (rule) => rule.test.toString() === '/\\.css$/'
   ).exclude = /\.module\.css$/;
   // Then we tell webpack what to do with CSS modules
   newConfig.module.rules.push({
     test: /\.module\.css$/,
     include: path.resolve(__dirname, '../src/components'),
     use: [
       'style-loader',
       {
         loader: 'css-loader',
         options: {
           // modules: true,
           importLoaders: 1,
           modules: {
             localIdentName: '[name]__[local]--[hash:base64:5]',
           },
         },
       },
       {
         loader: 'postcss-loader',
         options: {
           postcssOptions: {
             sourceMap: true,
             config: path.resolve(__dirname, '../postcss.config.js'),
           },
         },
       },
     ],
   });

画像ファイルを共通化

実行・ビルドスクリプトでNext.js のアセットディレクトリを指定するだけです。

"storybook": "start-storybook -s ./public -p 6006",
"build-storybook": "build-storybook -s ./public",

Redux を接続

Next.js で定義した Store を使えるようにしました。

Reducer のモックを注入することでログイン前/ログイン後の状態などを Storybook で再現でき、確認が捗ります。オススメです。

export const createMock = (state: Partial<State>) => {
 return {
   ...store,
   getState: () => {
     return { ...store.getState(), ...state };
   },
 };
};
export const userStore = createMock({
 account: [account1],
});
export const anonymousStore = createMock({
 account: [],
});
export const User = (args: Props) => (
 <Provider store={userStore}>
   <Header {...args} />
 </Provider>
);

i18n を接続

Next.js で定義した i18n を読み込むようにしました。
i18n のためにもアセットディレクトリの読み込みが必要です。

"storybook": "start-storybook -s ./public -p 6006",
"build-storybook": "build-storybook -s ./public",

PR 毎に S3 にデプロイするように設定

GitHub Actions で PR 毎に Storybook をデプロイするようにしました。
便利です。

まとめ

Storybook を導入する主な目的は確認フローの効率化だったのですが、 Atomic design を導入したことにより、コンポーネント設計で迷うことが減り、さらに Redux の状態を Storybook で再現しながら開発できるため開発効率もあがりました。

この記事が気に入ったら、サポートをしてみませんか?
気軽にクリエイターの支援と、記事のオススメができます!
Webサイトを作ったりアプリを作ったりする雑食エンジニアマン。