프론트에서 API를 mocking 할때 msw를 항상 사용했는데 초기 설정을 하고 작성한 api를 테스트하면 항상 첫 요청이 실행되지 않는 문제가 자주 있었다. 최근에는 vite를 사용하면서 api를 테스트하려고 했는데 같은 문제가 발생했는데 해결방법을 찾아서 포스팅한다.
보통 msw 초기 설정을 할때 index.js
나 main.js
에 react render 코드 보다 위에 실행 코드를 작성한다. 공식사이트에서는 기본 권장 설정으로 아래와 같이 권하고 있다.
if (process.env.NODE_ENV === 'development') {
const { worker } = require('./mocks/browser')
worker.start()
}
worker 시작은 비동기 작업이며, 마운트 시 요청을 만드는 애플리케이션과 경쟁 조건을 생성할 수 있습니다. 이 경우 작업자가 준비되었을 때 애플리케이션 마운트를 시행하려면 지연된 마운트 방법을 참조하십시오.
하지만 서비스 워커 등록은 비동기 프로세스로 이루어지기 때문에 기본 권장 설정시 API를 호출하는 앱과 경쟁상태를 일으켜 문제를 일으킬 수 있기 때문에 지연된 마운트라는 해결방법을 권장하고 있었다.
원인은 렌더링이 서비스 워커 등록보다 먼저 시작된 것이었다.
해결방법은 생각보다 간단했다. 말그대로 비동기이기 때문에 promise
를 사용하여 서비스 워커와 렌더링의 순서를 정해주면 되었다.
// src/index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from './App'
function prepare() {
if (process.env.NODE_ENV === 'development') {
const { worker } = require('./mocks/browser')
return worker.start()
}
return Promise.resolve()
}
prepare().then(() => {
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
})
또는 ES2022에 추가된 Top-level await
와 IIFE를 통해 간단하게 작성 할 수도 있다.
// src/index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
if (process.env.NODE_ENV === "development") {
await (async () => {
const { worker } = await import("./mocks/browser");
worker.start();
})();
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
사실 msw 공식문서에 부연 설명으로 해당 문제에 대해서 경고했고, 해결할 수 있는 방법도 따로 문서로 제공하였지만 사용하는데 급급해서 제대로 확인을 못한 잘못이었다. 앞으로는 조금 더 꼼꼼히 학습할 필요성을 느꼈다.