NextJS 14 - MSW, TanStack Query
MSW 세팅과 버전 업그레이드
1. 설치하기
npx msw init public/ --save
npm install msw --save-dev
2. public에 파일이 생성됨
실제로 어떤 서버 주소로 요청을 보내는데 이때 MSW가 가로채준다.
그래서 마치 실제 서버에 요청을 하는 것 같지만
사실은 MSW에서 응답을 해주는 것이다.
옛날에는 process.env.NODE_ENV가 production이면 배포주소, development면 개발 주소로 분기처리를 해줘야 했다.
하지만 MSW를 사용하면 분기처리없이 실제 서버주소로 요청을 보내도 상관없다.
개발상황에서 억지로 에러를 발생시킨다거나 로그인을 안해도 되게끔하거나 등
가능하다.
즉 백엔드에게 부탁하지 않아도 에러상황을 만들어 낼 수 있다.
3. src에 mocks라는 폴더 생성 후 환경 세팅
일단 먼저 NextJS에서 MSW사용이 애매한게
NextJS는 서버에서도 돌아가고, 클라이언트에서도 돌아간다.
서버에서는 서버사이드 렌더링을 할 때도 MSW가 돌아야된다.
그리고 브라우저 클라이언트 환경에서도 한번 더 MSW가 돌아야한다.
지금 정확하게는 서버쪽에서 MSW를 자연스럽게 돌리는 그 방식이 아직 안나왔다.
그래서 우리는 임시로 노드서버를 조금 활용해야한다.
코드는 일단 복사 붙여넣기 해준다.
http.ts
import { createMiddleware } from '@mswjs/http-middleware';
import express from 'express';
import cors from 'cors';
import { handlers } from './handlers';
const app = express();
const port = 9090; // 노드 서버 포트 번호
// 로컬 포트번호는 쓰고있는 포트번호 작성
app.use(cors({ origin: 'http://localhost:3000', optionsSuccessStatus: 200, credentials: true }));
app.use(express.json());
app.use(createMiddleware(...handlers));
app.listen(port, () => console.log(`Mock server is running on port: ${port}`));
Browser.ts
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'
// This configures a Service Worker with the given request handlers.
const worker = setupWorker(...handlers)
export default worker;
현재는 1.x 에서 2.x로 업데이트 된 상황
아래와 같이 바뀌었다.
그래서 마이그레이션을 한 상황이다.
만약에 import부분에 에러가 뜨면 라이브러리를 설치해준다.
npm i -D
npm i --save-dev @types/express @types/cors
그리고 두 파일이 공통으로 쓰는 handlers.ts도 만들어줘야한다.
실제로 코딩은 이 handlers.ts에서 모두 작성한다.
export const handlers = [
http.post('/api/login', () => {
console.log('로그인');
return HttpResponse.json(User[1], {
headers: {
'Set-Cookie': 'connect.sid=msw-cookie;HttpOnly;Path=/'
} //쿠키 넣어주고
})
}),
http.post('/api/logout', () => {
console.log('로그아웃');
return new HttpResponse(null, {
headers: {
'Set-Cookie': 'connect.sid=;HttpOnly;Path=/;Max-Age=0'
} //쿠키 지워주는 것
})
}),
...
];
위 예제 처럼 서버 API 로그인으로 Post 요청을 할 때
실제 서버가 아니라 위 핸들러에서 대신 응답을 보내준다.
그래서 API별로 어떤 응답을 보내주는지는 우리가 직접 코딩해야한다.
이제 만들어준 http 백엔드 서버는 따로 실행을 해줘야한다.
pakage.json에 명령어를 추가해준다.
그래서 터미널을 하나 더 띄워주고 실행시켜줘야한다.
이제 Next앱에서 언제 MSW를 적용하고 언제 적용하지 않을지 판단시켜줘야 함
컴포넌트를 하나 만들어야한다.
어떤 컴포넌트든 모두 공통적으로 적용되는 컴포넌트다.
MSWComponent.tsx
"use client";
import { useEffect } from "react";
export const MSWComponent = () => {
useEffect(() => {
if (typeof window !== 'undefined') {
if (process.env.NEXT_PUBLIC_API_MOCKING === "enabled") {
require("@/mocks/browser"); // browser는 클라이언트 환경일 때 MSW가 가로챈다.
}
}
}, []);
return null;
};
typeof window !== 'undefined' => undefined를 "" 로 감싸줘야 한다!
MSW 2버전에서 추가된 것이다.
window가 undefined가 아니라는 것은 window가 존재한다는 것이고
window가 존재할 때는 클라이언트 환경, 즉 브라우저라는 뜻이다.
그래서 이게 브라우저에서만 돌아간다는 것을 보장하는 것이다.
MSWComponent를 쉽게 설명하자면 brower인 클라이언트 환경에서는 API 요청을 가로채서
우리가 만든 http.ts 서버로 보내버린다.
이 컴포넌트를 모든 컴포넌트에 적용해야하기 때문에
전체 레이아웃을 담당하고 있는 최상위 layout.tsx의 body안에 넣어준다.
...
type Props = {
children: React.ReactNode,
};
export default function RootLayout({
children,
}: Props) {
return (
<html lang="en">
<body className={inter.className}>
<MSWComponent />
{children}
</AuthSession>
</body>
</html>
)
}
그리고 개발 환경일 때와 배포환경일 때의 구분을 위해 .env를 생성해서
MSWComponent의 아래 부분을 위한 환경변수를 만들어야한다.
보통은 .env에 만들어서
해당 환경변수를 enabled하면 개발환경,
다른 값이면 배포환경을 뜻하게 한다.
근데 이것마저도 귀찮다면 .env.local이라는 파일을 만들어서 해당 환경변수를 enabled로 넣어준다.
개발을 하는 도중에는 .env와 .env.local이 모두 실행되고,
배포상태에서는 .env만 실행된다.
추가설명하자면
NEXT_PUBLIC을 붙이면 브라우저에서 접근이 가능하다
그래서 이 변수를 소스폴더에서 접근을 할 수 있다.
없다면 서버에서만 접근할 수 있다.(유출여부를 처리할 수 있다)