🐰

Next.js で MSW をセットアップする方法

2023/04/23に公開

この記事では、Next.js で MSW (Mock Service Worker) をセットアップする方法を備忘録を兼ねて解説します。Next.js はブラウザとサーバーサイドの両方で実行されるため、それぞれの環境でセットアップが必要です。セットアップ方法はvercelのサンプル[1]を参考にしています。

MSWのためディレクトリ作成

設定に入る前にMSW で必要なコード群のためのディレクトリを作成します。

$ mkdir src/mocks

ハンドラーの用意

ハンドラーはモックAPIのエンドポイントに対するリクエストを処理するための関数です。
ハンドラーの設定方法はここでは割愛します。公式のドキュメント[2]を参照してください。

src/mocks/handlers.ts
import { rest } from 'msw'

export const handlers = [
  // ...
]

ブラウザとサーバーのインスタンス作成

次に、ブラウザとサーバーそれぞれの環境用にインスタンスを作成します。
まずブラウザ環境ではではワーカーインスタンスが必要なので、setupWorker関数を用いて用意したハンドラーでインスタンスを作成します。

src/mocks/browser.ts
import { setupWorker } from 'msw'
import { handlers } from './handlers'

export const worker = setupWorker(...handlers)

サーバー環境ではsetupServer関数を用いてサーバーインスタンスを作成します。

src/mocks/server.ts
import { setupServer } from 'msw/node'
import { handlers } from './handlers'

export const server = setupServer(...handlers)

インスタンスの呼び出し

作成したインスタンスを呼び出す関数を作成します。
実行環境に必要なインスタンス以外を呼び出すとエラーが発生するため、実行環境の判定をtypeof window === 'undefined'で行い、dynamic importにより適切なインスタンスだけが呼び出されるように実装します。

src/mocks/index.ts
async function initMocks() {
  if (typeof window === 'undefined') {
    const { server } = await import('./server')
    server.listen()
  } else {
    const { worker } = await import('./browser')
    worker.start()
  }
}

initMocks()

export {}

_app.tsxでモックを起動

_app.tsx でモックを呼び出す処理を追加します。基本的にモッキングは開発環境や試験環境でのみ行うため、環境変数でモックの有効・無効を制御するのが一般的です。
以下ではNEXT_PUBLIC_API_MOCKING という環境変数が用意されている前提でモッキングを制御します。

src/_app.tsx
import { AppProps } from 'next/app'

if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') {
  require('../mocks')
}

export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

単純に、 process.env.NODE_ENV === 'development' などで判定してもよいかと思います。

Service Workerの登録

最後に、ブラウザ環境ではService Workerの登録が必要なためMSW登録用のファイルを自動生成します。

$ npx msw init public/ --save
脚注
  1. https://github.com/vercel/next.js/tree/canary/examples/with-msw ↩︎

  2. https://mswjs.io/docs/getting-started/mocks/rest-api#request-handler ↩︎

Discussion