MSW 설정하면서 번들사이즈다 2배가 된 문제가 발생했습니다. 원래 보통 300kb 정도되는 번들 사이즈가 600정도로 커졌습니다.
원래 MSW는 개발하면서 백엔드를 mocking하는 것입니다. 그래서 개발하는 동안에만 있어야 하고 build에는 포함되면 안됩니다. 이 문제를 해결하는 글입니다.
참고로 일반적으로 권장하는 번들 사이즈는 500kb 미만입니다.
문제: 번들사이즈 2배 이벤트
MSW를 설정하면 번들사이즈가 2배가 됩니다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { ThemeProvider } from '@emotion/react';
import theme from './styles/theme.ts';
import queryClient from './libs/queryClient.ts';
import { worker } from './mocks/worker.ts';
if (process.env.NODE_ENV === 'development') {
/**
* 실제 DB랑 통신을 확인하고 싶으면 아래 worker를 주석처리
* api가 안정화 되면 아래 설정 {onUnhandledRequest: 'bypass'}은 해제
* @see https://stackoverflow.com/questions/68024935/msw-logging-warnings-for-unhandled-supertest-requests
*/
worker.start({ onUnhandledRequest: 'bypass' });
}
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
<ReactQueryDevtools />
</QueryClientProvider>
</React.StrictMode>
);
개발하는 동안 MSW를 활성화하는 설정입니다.
vite v4.3.9 building for production...
✓ 633 modules transformed.
dist/index.html 0.72 kB │ gzip: 0.39 kB
dist/assets/index-103ff5dd.js 0.08 kB │ gzip: 0.09 kB
dist/assets/PageHeading-858f23b9.js 0.13 kB │ gzip: 0.13 kB
dist/assets/index-8b0137af.js 0.32 kB │ gzip: 0.29 kB
dist/assets/index-87bbd3d1.js 0.65 kB │ gzip: 0.46 kB
dist/assets/index-32e984bf.js 0.91 kB │ gzip: 0.51 kB
dist/assets/index-d8a3b847.js 1.25 kB │ gzip: 0.67 kB
dist/assets/index-e552a5ba.js 1.29 kB │ gzip: 0.75 kB
dist/assets/index-7c7fe7b8.js 1.57 kB │ gzip: 0.99 kB
dist/assets/index-a90939a3.js 3.12 kB │ gzip: 1.42 kB
dist/assets/index-f613d10c.js 3.52 kB │ gzip: 1.69 kB
dist/assets/Input-8c62094b.js 4.51 kB │ gzip: 1.82 kB
dist/assets/react-error-boundary.esm-37156e7c.js 17.20 kB │ gzip: 5.85 kB
dist/assets/index-11b4e058.js 645.95 kB │ gzip: 201.37 kB
문제가 되는 번들 사이즈입니다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { ThemeProvider } from '@emotion/react';
import theme from './styles/theme.ts';
import queryClient from './libs/queryClient.ts';
import { worker } from './mocks/worker.ts';
if (process.env.NODE_ENV === 'development') {
/**
* 실제 DB랑 통신을 확인하고 싶으면 아래 worker를 주석처리
* api가 안정화 되면 아래 설정 {onUnhandledRequest: 'bypass'}은 해제
* @see https://stackoverflow.com/questions/68024935/msw-logging-warnings-for-unhandled-supertest-requests
*/
worker.start({ onUnhandledRequest: 'bypass' });
}
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
<ReactQueryDevtools />
</QueryClientProvider>
</React.StrictMode>
);
개발하는 동안 MSW를 활성화하는 설정입니다.
vite v4.3.9 building for production...
✓ 359 modules transformed.
dist/index.html 0.72 kB │ gzip: 0.39 kB
dist/assets/index-103ff5dd.js 0.08 kB │ gzip: 0.09 kB
dist/assets/PageHeading-2d3c7743.js 0.13 kB │ gzip: 0.13 kB
dist/assets/index-76e731ac.js 0.32 kB │ gzip: 0.29 kB
dist/assets/index-5977a381.js 0.65 kB │ gzip: 0.46 kB
dist/assets/index-5302ca3b.js 0.91 kB │ gzip: 0.51 kB
dist/assets/index-a077f0df.js 1.25 kB │ gzip: 0.67 kB
dist/assets/index-364e022a.js 1.29 kB │ gzip: 0.75 kB
dist/assets/index-9eabc667.js 1.57 kB │ gzip: 0.99 kB
dist/assets/index-19083c5b.js 3.12 kB │ gzip: 1.42 kB
dist/assets/index-c7499265.js 3.52 kB │ gzip: 1.69 kB
dist/assets/Input-85139c49.js 4.51 kB │ gzip: 1.82 kB
dist/assets/react-error-boundary.esm-5a8d437e.js 17.20 kB │ gzip: 5.85 kB
dist/assets/index-dcf1326b.js 305.53 kB │ gzip: 101.05 kB
시도: MSW Tree shaking을 위한 여정
검색: Tree shaking does not work in vite library mode
- 별로 도움 안되었습니다.
rollup-plugin-visualizer 설치
직접 도움되는 것은 아니였지만 유용한 라이브러입니다. 일단 남겨두겠습니다.
import { defineConfig, type PluginOption } from 'vite';
export default defineConfig({
plugins: [visualizer() as PluginOption],
});
/// <reference types="vitest" />
/// <reference types="vite/client" />
import react from '@vitejs/plugin-react-swc';
import { defineConfig, loadEnv, type PluginOption } from 'vite';
import { visualizer } from 'rollup-plugin-visualizer';
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
const { VITE_PORT } = loadEnv(mode, process.cwd(), '');
return {
plugins: [react(), visualizer() as PluginOption],
server: { port: parseInt(VITE_PORT) },
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['./src/setup.ts'],
},
};
});
이렇게 설정했습니다. state.html
이 출력됩니다. 파일 구경하면 번들 사이즈별로 볼 수 있습니다.
검색: Mock Service Worker Tree shaking
다시보면 이 방법이 해결에 제일 가까웠습니다.
Mock Service Worker로 만드는 모의 서버
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
// 개발 환경에서만 실행되도록 환경 변수를 확인하는 과정이 필요하다.
if (process.env.NODE_ENV === 'development') {
const { worker } = require('./mocks/worker');
worker.start();
}
ReactDOM.render(<App />, document.getElementById('root'));
검색: msw not being tree shaken from client bundle (dead code elimination bug)
{
// 생략
"browser": {
"./.msw": false
}
}
별로 도움 안되었습니다.
해결: 동적으로 import하기
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { ThemeProvider } from '@emotion/react';
import theme from './styles/theme.ts';
import queryClient from './libs/queryClient.ts';
/**
* 실제 DB랑 통신을 확인하고 싶으면 아래 worker를 주석처리
* api가 안정화 되면 아래 설정 {onUnhandledRequest: 'bypass'}은 해제
* @see https://stackoverflow.com/questions/68024935/msw-logging-warnings-for-unhandled-supertest-requests
* import는 비동기 함수이기 때문 async await와 즉시 실행함수가 필요함
*/
(async function () {
if (process.env.NODE_ENV === 'development') {
// tree shaking을 위해 await import 활용
const { worker } = await import('./mocks/worker.ts');
worker.start({ onUnhandledRequest: 'bypass' });
}
})();
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
<ReactQueryDevtools />
</QueryClientProvider>
</React.StrictMode>
);
당황스럽게 간단했습니다. 테스트는 성공적으로 동작하고 번들사이즈 2배 이벤트는 종료되 었습니다.
즉시 실행함수에 async await도 적용해서 비동기로 동작하는 import로 worker를 가져옵니다.
vite v4.3.9 building for production...
✓ 635 modules transformed.
dist/index.html 0.72 kB │ gzip: 0.39 kB
dist/assets/index-103ff5dd.js 0.08 kB │ gzip: 0.09 kB
dist/assets/PageHeading-d6ffa854.js 0.13 kB │ gzip: 0.13 kB
dist/assets/index-2e281901.js 0.32 kB │ gzip: 0.29 kB
dist/assets/index-21727d9f.js 0.65 kB │ gzip: 0.46 kB
dist/assets/index-f13856c9.js 0.91 kB │ gzip: 0.51 kB
dist/assets/index-327db79f.js 1.25 kB │ gzip: 0.67 kB
dist/assets/index-e0d49bcb.js 1.29 kB │ gzip: 0.75 kB
dist/assets/index-02c71055.js 1.60 kB │ gzip: 1.01 kB
dist/assets/index-e90ed05b.js 3.12 kB │ gzip: 1.42 kB
dist/assets/index-ecd6e71f.js 3.52 kB │ gzip: 1.69 kB
dist/assets/Input-a9c99b9d.js 4.51 kB │ gzip: 1.82 kB
dist/assets/react-error-boundary.esm-e555e35f.js 17.20 kB │ gzip: 5.85 kB
dist/assets/index-e38efc25.js 305.50 kB │ gzip: 101.04 kB
원래 보여야 하는 번들 사이즈입니다. 이거로 번들사이즈 2배 이벤트는 끝났습니다.
How to make your JavaScript Bundle Smaller
예전에 본 튜토리얼인데 다시봐도 유용합니다.
학습: lazy 이외 다른 tree shaking
오늘도 자바스크립트는 저를 실망시키지 않습니다.
vite에서는 top level await를 사용할 수 있지만 브라우저에서는 지원하지 않습니다.
(async function () {
if (process.env.NODE_ENV === 'development') {
const { worker } = await import('./mocks/worker.ts');
worker.start({ onUnhandledRequest: 'bypass' });
}
})();
이런 패턴으로 tree shaking합니다. 개발할 때만 실행하기 때문에 build할 때 무시합니다.
vite의 강력함 같습니다.