백엔드 쪽에서 API가 개발되기 전까지 프론트 쪽에서는 API Mocking을 하려고 환경을 설정하고 있던 도중, 이상한 이슈가 생겼습니다.
메인 파일에서 MSW을 시작하고 있었어요.
main.tsx
import ReactDOM from 'react-dom/client'; import App from './App.tsx'; import './index.css'; export async function enableMocking(enabled: boolean = true) { if (import.meta.env.PROD || !enabled) { return; } const { worker } = await import('./__mock__/instance.ts'); return worker.start({ onUnhandledRequest: 'bypass', }); } enableMocking().then(() => { ReactDOM.createRoot(document.getElementById('root')!).render(<App />); });
worker의 start() 메서드가 resolve를 반환하면 그 이후에 React를 렌더링하는 코드입니다. 그러므로 이후에 있는 React Router Dom의 loader든 뭐든 당연히 캐치가 되어야겠죠?

하지만 제 예상과는 다르게 loader에서 호출하고 있는 /user에 먼저 접근을 한 뒤, 서비스 워커가 불러와지고 있는 이상한 .. 이슈를 겪었어요.
첫 번째로 의심했던 건 MSW의 start() 메소드였습니다. 서비스 워커를 등록하는 메소드이지만, 서비스 워커를 '활성화'하고 resolve를 하지 않는다는 의심을 했어요. 등록은 완료했지만 서비스 워커가 활성화되기까지는 시간이 걸리니, 그 사이에 리액트가 먼저 렌더를 진행해 loader가 호출되는 것 같았어요.
그래서 다음과 같이 기다려주는 코드를 작성했어요.
활성화될 때까지 기다리기
return new Promise((resolve, reject) => { worker.start({ onUnhandledRequest: 'bypass' }).then(() => { if ('serviceWorker' in navigator) { navigator.serviceWorker.ready.then(resolve) } else { reject() } }) })
ready가 되면 solve를 호출하게끔 했으나,, 결과는 여전히 똑같았어요.
두 번째로 의심한 것은 App.tsx였습니다. 정확하게는 import App from './App.tsx' 구문이었어요.
자바스크립트는 가져오는 모든 종속 모듈들을 평가한 이후 코드를 실행하는 Module Evaluation이라는 개념이 있어요. 자세한 정보는 전에 작성한 포스팅을 참고해주세요. 이걸 이렇게 써먹네
실제로 fetch를 실패한 부분이 아닌, 더 위의 요청을 보면 App이 가져오는 모든 모듈을 먼저 가져오는 걸 확인할 수 있었어요.

그래 이걸 먼저 알아차렸어야 했는데...
그래서 App 파일 역시 모킹이 완료된 후 동적으로 불러오게 변경했습니다.
main.tsx
import ReactDOM from 'react-dom/client'; import './index.css'; export async function enableMocking(enabled: boolean = true) { if (import.meta.env.PROD || !enabled) { return; } const { worker } = await import('./__mock__/instance.ts'); return worker.start({ onUnhandledRequest: 'bypass', }); } enableMocking().then(() => { import('./App.tsx').then((App) => { ReactDOM.createRoot(document.getElementById('root')!).render(<App.default />); }); });

이후 정상적으로 loader에 있는 녀석도 모킹을 할 수 있게 되었어요. 짱이다!
main.tsx 같은 파일은 국룰로 그냥 App.tsx 박고 시작하는 거라 크게 신경을 안 썼고, 파일도 다 import한 뒤 최적화 단계에서 lazy import로 바꿔서 최적화를 했다!는 접근을 하려고 했다보니 놓친 부분이었어요.
그냥 처음부터 lazy를 고려해야겠다 싶기도 하네요... ^~^