ywc.life
Development 4분 읽기

Next.js 15에 MSW(Mock Service Worker) 설치하기

작성자:
Next.js 15에 MSW(Mock Service Worker) 설치하기

새로운 프로젝트에 들어가면서 백엔드 API가 만들어지기 전 프론트개발을 진행하기 위해 Mock API를 도입해서 사용해봤어요.

MSW(Mock Service Worker)라는 자바스크립트를 위한 Mocking 라이브러리를 알게되었고, 공식문서와 구글링을 하며 여러 뻘짓과 시행착오를 겪고 난 후 가장 쉽게 MSWNext.js 15+ 에 설치하는 방법을 정리했어요.

MSW(Mock Service Worker)란?

프론트엔드 개발을 하면서 API가 준비되지 않아 개발이 지연되거나, API가 자주 변경되어 곤란했던 경험이 있나요? 혹은 테스트 환경을 구축하는 데 어려움을 겪은 적이 있나요? 이런 상황에서 유용하게 사용할 수 있는 도구가 바로 MSW(Mock Service Worker)예요.

MSW는 브라우저와 Node.js 환경에서 실제 서버 API 없이도 네트워크 요청을 가로채 가상(mock) 응답을 제공하는 라이브러리예요. MSW는 Service Worker라는 브라우저 기술을 활용하여 브라우저 레벨에서 네트워크 요청을 처리하기 때문에, 별도의 코드 수정 없이도 마치 실제 API가 존재하는 것처럼 프론트엔드 개발과 테스트를 진행할 수 있게 해줘요.

공식문서에서 MSW의 특징으로는 애플리케이션의 코드가 어떤 것이 Mocking되었는지 알지 못하게 하고, 동일한 프로덕션 리소스를 요청하고 애플리케이션의 실제 동작을 테스트할 수 있다고 해요. 또한, Express 와 같은 라우팅 구문으로 request를 만들기 때문에 친숙하다고 표현해요.

설치법

Next.js 15.2.1 버전과 pnpm으로 진행했어요.

pnpm add msw@latest --save-dev

이 후 Service Worker를 설치해주어야 해요.

MSW에서는 서비스 워커를 public 디렉토리에 빠르게 생성해주는 CLI를 제공해 줘요.

npx msw init <PUBLIC_DIR> —save에 맞게 public 디렉토리를 입력해주면 돼요.

pnpx msw init public/ --save

실행 후 public 디렉토리에 *mockServiceWorker.js가 잘 생성될 거예요. 또한 package.json엔 아래 코드가 추가 되어있을 거예요!

{
  "msw": {
    "workerDirectory": ["public"]
  }
}

이제 Integration을 해주어야 해요. intergration 방법 중 Browser integration과 Node.js integration 모두 사용해야 해요. 왜냐하면 Next.js의 RSC는 Node.js 환경에서 실행되기 때문이에요.

먼저 mocks디렉토리를 app폴더와 같은 위치에 있도록 만들어요. 그 후 아래 파일과 코드들을 작성해줘요.

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

export const worker = setupWorker(...handlers);
// /src/mocks/server.ts
import { setupServer } from "msw/node";
import { handlers } from "./handlers";

export const server = setupServer(...handlers);
// src/mocks/handlers.ts
import { http, HttpResponse } from "msw";

export const handlers = [
  http.get("https://example.com/resource", () => {
    return HttpResponse.json({
      name: "ywc",
    });
  }),
];

테스트용 가짜 api를 만들어 줘요. 자세한 Mock API를 만들려면 공식문서를 참조하세요.

// src/mocks/MSWInitializer.tsx 또는 components 디렉토리
"use client";

import { useEffect } from "react";

export function MSWInitializer() {
  useEffect(() => {
    async function initMocks() {
      if (typeof window === "undefined") {
        const { server } = await import("../mocks/server");
        server.listen();
      } else {
        const { worker } = await import("../mocks/browser");
        await worker.start();
      }
    }
    initMocks();
  }, []);
  return null;
}

각각 브라우저와 Node.js 환경에서 요청을 가로채기 위한 설정들을 초기 실행하기 위해 MSWInitializer 컴포넌트를 만들어요.

이후 루트 레이아웃에서 개발 환경에서만 실행되게 해줘요.

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="ko">
      <body>
        {process.env.NODE_ENV === "development" && <MSWInitializer />}
        {children}
      </body>
    </html>
  );
}

이후 instrumentation.ts를 이용하여 Next.js가 서버 사이드 렌더링(Server-side Rendering) 또는 RSC(React Server Components)를 Node.js 환경에서 처리할 때 MSW 서버를 활성화해서, 서버에서 발생하는 네트워크 요청을 가로채고 mock 응답을 반환할 수 있도록 해요.

과거 Next.js 버전에서는 네트워크 요청을 가로채고(mocking), 개발 및 테스트 환경을 구성할 때 별도의 실험적 옵션(experimental)을 활성화하여 MSW의 네트워크 요청 가로채기 기능이 정상 작동하게 해줘야 했어요.

그러나 Next.js 15 이상부터는 기본적으로 요청을 가로채는 Service Worker 관련 기능을 내부적으로 지원하여, 별도의 실험적 옵션(instrumentationHook: true)을 켜지 않아도(next.config.ts에 옵션을 주지 않아도) MSW가 제공하는 instrumentation.ts와 같은 설정파일만 있으면 바로 동작해요.

// src/instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    const { server } = await import("./mocks/server");
    server.listen();
  }
}

여기까지 설정을 다 하고 브라우저 콘솔을 보면 아래 메시지가 떴다면 성공이에요.

MSW Success

이후 fetch하고 log를 찍어보려고 하면 안 되실 거예요! 왜냐하면 서버를 재시작해줘야 하기 때문이에요…

서버를 재시작해주면 정상적으로 Mock API가 작동하는 것을 볼 수 있어요.

MSW Result

MSW를 사용해보면서, Mock API를 수정할 때마다 서버를 재시작해야 한다는 매우 큰 단점이 있었어요… HMR(Hot Module Replacement)를 지원을 안 하는 것인지 제가 못찾는건지 공식문서에서는 찾아볼 수 없어서 매우매우 아쉬웠어요. 아니면 제가 설정을 잘못했는지…?

마무리하며

Next.js에 MSW를 설치하는 법을 알아봤어요. 저도 공식문서와 여러 회사의 기술블로그의 도움과 여러 시행착오를 겪어 MSW를 설치하는데 성공했어요. Next.js에 MSW를 도입하시는 분들께 도움이 되었으면 좋겠어요.

댓글