[Next 14] MSW 연동 이슈 해결

Jinny·2024년 12월 11일
0

next.js

목록 보기
6/7
post-thumbnail

배경

프로젝트를 하면서 백엔드 쪽 API가 나오기 전까지 와이어 프레임 작업만 하다가 나올 때 까지 기다리면서 작업을 하고 있었다.

멘토님의 피드백으로 백엔드 API를 기다리는 것보다 mocking api를 통해 응답 데이터 타입을 정해서 UI 상에 뿌려주는 작업을 미리 하는 것이 업무의 효율성을 높여준다고 말씀해주셨다. 이번에 Mocking API 라이브러리인 MSW에 대해 알아보기로 했다.

MSW란?

MSW는 서버없이 HTTP 요청을 가로채고 모킹된 응답을 반환하기 위해 사용된다. 네트워크 요청이 발생하기 전에 가로채어 모킹된 응답을 보여줄 수 있다. 다양한 시나리오를 통해 성공, 실패 시 어떤 오류 응답을 보여줄 지 시뮬레이션을 할 수 있다는 장점이 있다.

MSW 설치

npm install msw --save-dev

로컬 public 폴더에 mockSevericeWorker 생성

서비스 워커를 등록하기 위해서는 스크립트를 호스팅하고 제공하여야하기 때문에 public폴더 위치에 서비스 워커를 등록한다. 실제 서버로 보내는 요청이 있으면 morkServiceWorker가 가로채서 응답을 준다. 마치 실제 서버에게 요청하는 것처럼 보이게 동작한다.

npm msw init public/ --save

MSW 세팅하기

Next.js는 서버와 클라이언트에서 동작하기 때문에 SSR 동작을 할 때 서버에서도 MSW가 동작해야 한다. 즉 MSW가 서버와 클라이언트에서 동작해야하기 때문에 browser.ts는 클라이언트 환경, http.ts는 서버 환경으로 각각 작성해야 한다.

src/mocks/broswer.ts 생성

넥스트 14에서는 브라우저 msw가 안 돌아가는 문제가 있다.

import { handlers } from './handlers';
import { setupWorker } from 'msw/browser';

export const worker = setupWorker(...handlers);

src/mocks/http.ts

http.ts는 서버 컴포넌트에서 서버로 요청을 보낼 때 next 서버에서의 요청을 모킹하기 위해 사용된다. 그러나 setUpSever로 설정하는 경우, 서버 컴포넌트에서 msw가 제대로 적용되지 않는 문제가 있다. 실제로 Next 14는 MSW 연동이 매끄럽지 않다고 한다. 현재 Next 15는 msw 연동이 잘 동작한다고 한다. 서버 환경에서 msw가 제대로 동작시키기 위해 추가적인 설정이 필요하다.

import { handlers } from './handlers';
import { setupServer } from 'msw/node';

export const server = setupServer(...handlers);

msw로 서버 사이드 mocking은 가능하지만 서버 재시작을 하지 않으면 핸들러가 업데이트 되지 않는 문제도 있다고 한다. 이를 해결하기 위해 독립적인 express 서버를 구축하고 Next에서 api 요청을 보낼 때 middleware를 사용하여 요청을 가로채면 위 문제가 해결된다고 한다.
또다른 해결 방안으로 next.js의 instrumentation가 있었는데 추천하지 않는 방식이라고 한다. 나같은 경우는 따로 설치 없이 하고 싶어서 next.js의 instrumentation 방식으로 시도했다.

MSW 컴포넌트 만들기

우선 Next 프론트엔드 쪽을 설정해줘야 햐는데 MSW를 사용할 수 있게 해주는 컴포넌트를 만들어야 한다. 여기서 window가 undefined가 아닌 경우는 window가 존재한다는 뜻이며, 클라이언트 환경 즉 브라우저 환경에서 돌아가게끔 보장된다.

'use client';

import { useEffect } from 'react';

export default function MSWComponent() {
  useEffect(() => {
    if (typeof window !== 'undefined') {
      if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') {
        import('@/mocks/browser');
      }
    }
  }, []);

  return null;
}

.env.local 파일 생성

MSW는 개발 환경에서만 사용하면 되기 때문에 .env.local 파일에 환경 변수를 선언하면 개발 환경일 때만 해당 환경 변수가 유효하다.

NEXT_PUBLIC_API_MOCKING=enabled  //enabled일 때만 msw 동작

MSW 컴포넌트 적용

// src\app\layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang='ko'>
      <body>
        <MSWComponent />
        <QueryProvider>
          <div id='modal'></div>
          {children}
        </QueryProvider>
      </body>
    </html>
  );
}

첫 번째 시도한 방식 : Next.js의 instrumentation으로 시도 ❌

루트 위치에 instumentation.ts을 생성해 아래 코드와 같이 작성한다. next에서 제공하는 instrumentation 기능을 사용한다. 이때 next.js의 서버 인스턴스가 시작될 때 한 번 호출된다.

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

next.config.js 수정
instrumentation 을 활성화 하기 위해 experimental: { instrumentationHook: true }을 넣어준다. 그 다음 webpack 설정을 추가한다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  experimental: { instrumentationHook: true },
  webpack(config, { isServer }) {
    if (isServer) {
      // 서버 환경에서 'msw/browser'를 비활성화
      config.externals.push('_http_common'); // Treat _http_common as an external module
    }
    return config; // 수정된 config 반환
  },
};

module.exports = nextConfig;

그러나 여전히 브라우저 환경에서 msw 연동이 잘 안되는 것을 볼 수 있다.

해결방법 : middleware와 express 서버 설치 ✔️

@mswjs/http-middleware 설치 및 express 서버 등 설치

msw로 mock server를 만들기 위해 필요한 라이브러리를 설치한다.

npm i -D @mswjs/http-middleware express cors @types/express @types/cors

MSW 서버 실행 명령어 추가하기

package.json에 서버 실행 명령어를 추가한다.
여기서 watch는 핸들러가 변경되면 서버가 자동으로 재시작된다.

"scripts": {
  "dev": "next dev",
  "build": "next build",
  "start": "next start",
  "lint": "next lint",
  "mock": "npx tsx watch ./src/mocks/http.ts"
},

새로운 터미널 창을 열어서 아래와 같이 명령어를 입력하면 msw 서버가 나온다.

npm run mock

Mock 서버가 실행되면 터미널 창에 아래와 같은 문구가 나온다.

이제 다른 터미널에서 npm run dev로 실행하면 된다.

🔗 Reference

MSW browser 셋업 공식문서
MSW 세팅 참고
Next.js의 instrumentation으로 시도한 방식 참고
FormData 전송 관련 MSW 공식문서

0개의 댓글