6/21 コンポーネント駆動開発、簡易な導入手順まとめ
使うライブラリ・パッケージと概要
- React, TypeScript, Storybook: ReactはJavaScriptライブラリであり、ユーザーインターフェイスの構築を容易にします。TypeScriptはJavaScriptのスーパーセットで、型安全性を提供し、バグを早期に発見し、コードのリーダブル性と保守性を向上します。StorybookはUIコンポーネントの開発とドキュメンテーションを支援するツールです。Storybookを使用すると、各コンポーネントの異なる状態を視覚的に確認することができます。
- Jest: JestはJavaScriptのテストフレームワークで、Reactコンポーネントのテストに特に適しています。Jestはユニットテストと結合テストの両方をサポートしており、モック関数やスナップショットテストなどの機能も提供しています。
- Plop: Plopはボイラープレートコードを生成するためのツールです。あらかじめ定義したテンプレートを元に新しいコンポーネントやテストの雛形を簡単に生成することができます。
- MSW (Mock Service Worker): MSWはブラウザとNode.jsで動作するモック/スパイライブラリです。MSWはネットワークリクエストを補足し、定義したモックレスポンスを返します。これにより、APIの実装が未完成でもフロントエンドの開発やテストを進めることができます。
導入手順
React TypeScriptプロジェクトの作成
npx create-react-app my-app --template typescript
TypeScriptのオプションをつけることで、作成時からTypeScriptの初期設定やファイル名になります。
Storybookのインストール
npx sb init
.storybook
ディレクトリが作成される。
また、既存のデフォルトのストーリーは src/stories
ディレクトリ内に格納される。
Jestのインストール:
Jestは create-react-app
にデフォルトで含まれていますが、追加の設定や型定義が必要な場合は次のコマンドを実行Jestは create-react-app
にデフォルトで含まれていますが、追加の設定や型定義が必要な場合は次のコマンドを実行
Plopのインストールと設定:
npm i -D plop
プロジェクトのルートディレクトリに plopfile.js
ファイルを作成
touch plopfile.js
plopfile.js
module.exports = function (plop) { // コンポーネントジェネレータを作成します plop.setGenerator('component', { description: 'Create a component', prompts: [{ type: 'input', name: 'name', message: 'What is your component name?' }], actions: [ { type: 'add', path: 'src/components/{{pascalCase name}}/{{pascalCase name}}.tsx', templateFile: 'plop-templates/Component.tsx.hbs' }, { type: 'add', path: 'src/components/{{pascalCase name}}/{{pascalCase name}}.stories.tsx', templateFile: 'plop-templates/Component.stories.tsx.hbs' } ] }); };
- Plopの設定ファイルで、このファイルによってPlopがどのように動作すべきかを定義
- このファイル内で、生成されるファイルのタイプや名前、テンプレートとなるファイルへのパス、プロンプトの質問などを設定している
plop-templatesというディレクトリをプロジェクトのルートに作成
その中にテンプレートとなるComponent.tsx.hbs
とComponent.stories.tsx.hbs
という2つのファイルを作成
これらの.hbs
ファイルはHandlebarsテンプレートと呼ばれ、特定の箇所を置換して新しいファイルを生成するために使用される
基本的な例
Component.tsx.hbs
import React from 'react'; export interface {{pascalCase name}}Props { } export const {{pascalCase name}}: React.FC<{{pascalCase name}}Props> = (props) => { return ( <div> {/* Implement your component here */} </div> ); }
Component.stories.tsx.hbs
import React from 'react'; import { {{pascalCase name}}, {{pascalCase name}}Props } from './{{pascalCase name}}'; export default { title: 'Example/{{pascalCase name}}', component: {{pascalCase name}}, }; const Template: React.VFC<{{pascalCase name}}Props> = (args) => <{{pascalCase name}} {...args} />; export const Primary = Template.bind({}); Primary.args = { /* Fill in your default args here */ };
npx plop component
コマンドを実行すると、ファイル名を聞かれるので、例としてbuttonと答えたとすると、Button.tsx
とButton.stories.tsx
がsrc/components/Button/
ディレクトリに作成される
ストーリーブックのテスト設定
ストーリーブックのテストには、@storybook/addon-storyshots
を使用する。これをインストールして、自動的にStorybookのスナップショットテストを作成できる。
npm install --save-dev @storybook/addon-storyshots react-test-renderer
src
ディレクトリにstoryshots.test.js
という新しいファイルを作成
touch src/storyshots.test.js
storyshots.test.js
ファイルに以下の内容を追加
import initStoryshots from '@storybook/addon-storyshots'; initStoryshots();
この設定により、Jestがテストを行うときにStorybookの各ストーリーのスナップショットテストを自動的に行う
テストの実行:
npm test
- start test などは、package.jsonのscriptsに書かれていて、runをつけなくてもいい
- このコマンドでjestのテストが走ります
storybook起動
npm run storybook
- このコマンドをするとブラウザにstorybookが立ち上がるので、現状のstorybook(今回の例だとbuttonコンポーネント)が反映される
mswの設定:
npm install msw
mswを設定します。以下のコードをsrc/mocks/handlers.js
に追加します。
import { rest } from 'msw' export const handlers = [ rest.post('https://example.com/api/submit', (req, res, ctx) => { return res(ctx.json({ message: 'Success' })) }), ]
このハンドラをテスト環境で使用できるように設定します。以下のコードをsrc/mocks/browser.js
に追加します。
import { setupWorker } from 'msw' import { handlers } from './handlers' export const worker = setupWorker(...handlers)
テストのセットアップとクリーンアップでmswサーバーを起動と停止します。以下のコードをsrc/setupTests.js
に追加します。
import { server } from './mocks/server.js' beforeAll(() => server.listen()) afterEach(() => server.resetHandlers()) afterAll(() => server.close())
これでmswがテストで利用可能になりました。
基本的なコード例
import React from 'react' import { render, fireEvent, waitFor } from '@testing-library/react' import { rest } from 'msw' import { server } from './mocks/server' import Button from './Button' test('submits the form when the button is clicked', async () => { server.use( rest.post('https://example.com/api/submit', (req, res, ctx) => { return res(ctx.json({ message: 'Success' })) }) ) const mockOnClick = jest.fn() const { getByText } = render(<Button
コメント
実務でフロントエンドをCDDで開発することになったので、一回自分で小さく動かしてみるために、設定方法を簡単にまとめました。