이 포스팅은 최신 버전의 Next에 MSW를 적용하고자 시도한 포스팅입니다.
결과적으로 프로젝트에는 적용하지 못하였음을 미리 알려드립니다.
이 포스팅은 NextJS 14에 MSW를 적용하는 과정에 대한 포스팅으로, 올리브영 기술블로그를 기반으로 제작되었습니다.
MSW의 장단점과 이전 버전에서 MSW를 도입하게 되는 과정에 대한 서술은 올리브영 기술블로그를 참고해 주시기 바랍니다.
먼저, 프로젝트에 MSW를 설치해 준다.
npm i -D msw
or
yarn add -D msw
MSW에서 사용할 서비스 워커 파일인 mockserviceworker.js를 생성하기 위해 공식문서의 표를 참고하여, 터미널의 커맨드를 입력해줍니다.
$ npx msw init <PUBLIC_DIR> --save
# next.js일 경우
$ npx msw init public/ --save
명령어를 실행하면 public/mockServiceWorker.js가 생성되며 package.json 파일에 msw.workerDirectory가 추가됩니다. 이 설정을 하는 이유는, 추후에 MSW가 업데이트 되면서 mockServiceWorker 스크립트가 변경되면 이 변경사항을 자동으로 로컬 파일에 반영해주기 위해서 입니다.
// package.json
{...
"msw": {
"workerDirectory": [
"public"
]
}
}
이 부분부터 올리브영 기술블로그의 포스팅과 차이가 있습니다. 올리브영의 포스팅은 NextJS 13으로 pages Router를 이용하고 있습니다. 따라서 앱의 진입점이 pages/_app.tsx이지만, 이 포스팅에서는 NextJS 14의 app Router를 이용하며 진입점이 app/layout.tsx로 바뀌었습니다. 엄밀히 따지자면 둘의 역할이 다르지만, 저는 MSW를 적용하기 위한 진입점으로 이를 채택하였습니다.
export default function RootLayout({children}: LayoutProps) {
if (process.env.NODE_ENV !== "production") {
initMSW();
}
return <Layout>{children}</Layout>;
}
이 부분은 올리브영의 코드와 동일하게 작성하였습니다. 단, MSW의 버전에 따른 setupWorker의 위치가 다르며, jest를 이용하지 않아 __mocks__ 폴더 대신 app/mocks폴더 아래에 폴더와 핸들러를 구분하여 작성해 주었습니다.
// app/mocks/browser.ts
import { setupWorker } from "msw/browser";
import handlers from "./handlers";
export const worker = setupWorker(...handlers);
// app/mocks/server.ts
import { setupWorker } from "msw/node";
import handlers from "./handlers";
export const worker = setupServer(...handlers);
// app/mocks/index.ts
async function initMSW() {
if (typeof window === "undefined") {
const { server } = await import("./server");
server.listen(필요한옵션);
} else {
const { worker } = await import("./browser");
worker.start(필요한옵션);
}
}
export { initMSW };
// app/mocks/handlers.ts
import commonHandlers from "./common/handler.ts";
let handlers = [...commonHandlers];
export default handlers;
// app/mocks/common/handler.ts
import { http } from 'msw'
const handler = [
http.get('/posts', () => {
console.log('Captured a "GET /posts" request')
}),
]
export default handler
여기까지 작성한 결과, MSW가 실행되는 것은 확인하였으나, AWS S3 인증 등의 문제로 인해 프로젝트에 적용하기에 오버로드가 예상되어 MSW 적용을 포기하고, 원상태로 복구하였습니다.
MSW를 적용하기 위해서 추가 조사한 결과, 일반적으로 위 포스팅까지 구현한 결과, 페이지 이동이나 리로드시 동작이 원활하지 않을 수 있다고 합니다. 그 이유는 MSW의 개발자인 kettanaito에 따르면 Next.js의 초기화 과정이 앱 시작 시 한 번만 실행되며, 이후 변경 사항이 반영되지 않기 때문이라고 합니다.
이러한 문제를 해결하기 위해서 MSW 공식 github의 예제에서는 next.config.mjs의 webpack 설정을 수정하는 방식을 사용하고 있습니다. 그러나 이 방식은 핫 모듈 리로딩을 지원하지 않는다는 단점이 있습니다.
이에 대한 해결책으로 참고한 블로그에서는 NextJS에 내장된 Express 서버를 이용하는 방식을 사용했습니다.
추가로 올리브영에서 NextJS에 MSW를 적용하며 발생한 문제는 API호출이 서버와 클라이언트에서 다르다는 점과, 프리픽스로 인한 workerDirectory를 찾을 수 없는 문제였습니다. 이는 자체적으로 주소를 변경하는 MockingClient를 만들고, setupWorker의 옵션을 설정해주어 해결할 수 있었습니다.
https://velog.io/@wns450/msw-next-%EC%9D%B4%EC%8A%88
https://oliveyoung.tech/blog/2024-01-23/msw-frontend/
https://github.com/mswjs/msw/issues/1644