Next.js App router, 컴파일 옵션은 es5(기본으로 세팅되어 있는) 환경 입니다.
$ yarn add -D msw
// @/mocks/apis/study.apis.ts
import { rest } from 'msw'
const getCreatedStudyList = rest.get('/api/study', (_, res, ctx) => {
return res(ctx.status(200), ctx.json({ message: 'success!!' }))
})
// @/mocks/handlers.ts
import * as apis from './apis'
export const handlers = [...Object.values(apis)]
// @/mocks/browser.ts
import { setupWorker } from 'msw'
import { handlers } from './handlers'
export const worker = setupWorker(...handlers)
api 테스트 코드 작성 예정이기에 미리 세팅했습니다.
// @/mocks/server.ts
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
export const server = setupServer(...handlers)
브라우저 환경에서 동작하는지, 서버 환경에서 동작하는지에 따라 다른 인스턴스를 실행합니다.
// @/mocks/index.ts
const initMocks = async () => {
const isServer = typeof window === 'undefined'
if (isServer) {
const { server } = await require('./server')
server.listen({ onUnhandledRequest: 'bypass' }) // 처리되지 않은 요청이라도 통과시키도록
} else {
const { worker } = await require('./browser')
worker.start({ onUnhandledRequest: 'bypass' }) // 처리되지 않은 요청이라도 통과시키도록
}
}
export default initMocks
❓ 처리되지 않은 요청이라도 통과?
환경에 따라 설정을 다르게 해줄 수 있도록 env를 이용했습니다.
env파일에서 바로 enable/disable
해줌에 따라 msw를 구동할 수도 하지 않을 수도 있습니다.
// @/app/providers.tsx
'use client'
import initMocks from '@/mocks'
import { PropsWithChildren } from 'react'
if (process.env.NEXT_PUBLIC_API_MOCKING === 'enable') {
initMocks()
}
const Providers = ({ children }: PropsWithChildren) => {
return <div>{children}</div>
}
export default Providers
// env
NEXT_PUBLICK_API_MOCKING='enable'
$ npx msw init public/
잘 동작하는 것을 확인할 수 있었습니다 👍
Next.js는 서버 사이드에서 렌딩하기 때문에 브라우저의 Service Worker API를 사용하여 네트워크 요청을 가로채고 모의 응답을 제공하는 msw는 서버 사이드에서 제대로 초기화되지 못합니다.
✨ 따라서 Next.js에서는 클라이언트 사이드 컴포넌트에서 초기화되어야 합니다.
그런 이유 때문에 use client
되어 있는 providers 파일에서 init을 했던 겁니다 :)
이번 디버깅 과정을 통해서 브라우저에서 초기화되어야만 하는 특성이 존재함을 알게 되었고, 이를 Next.js에서 반영해주기 위해서는 어떻게 해야하는지를 알게 되었습니다 🙌
그리고 기존에 msw를 세팅할 때 development 환경에서는 msw가 구동되도록 했었습니다. 그래도 개발 환경 중 실제 api의 반영을 확인해야 하는 순간들이 존재합니다. 그럴 때 주석을 했다 풀었다하며 변경 사항이 발생하던 불편함이 있었는데요. 이를 env에서 설정하는 방법 덕분에 해소할 수 있었습니다 😉
app.tsx 파일에서 주석 추가했다가 제거했다가 커밋 내역에는 포함되지 않도록 하려고 신경쓰고 했던 기억이 새록새록하네요 🤔