스마트 창고 시뮬레이션 앱에서 번들링 최적화를 수행한 부분을 정리한 글.
스마트 창고 시뮬레이션 앱은 유독 번들링 크기가 컸다.
SVG 모듈
이미지 파일을 Public 폴더에 저장하는 경우, 해당 파일은 정적으로 서빙되고 트리쉐이킹, 번들링, 압축, gzip 등의 대상이 되지 않는다.
물론 CDN 서버에서 gzip으로 압축하여 보내도록 설정할 수 있지만, 기본적으로는 src 폴더 안에서 같이 번들링되도록 한다.
dist/assets/background-full-BRfTiI_d.svg 573.85 kB │ gzip: 75.08 kB
위와 같이 src/assets에 파일을 넣어두자 573.85kb였던 파일이 75.08kb로 85% 용량이 줄어들었다. SVG는 반복적인 내용이 많아 압축율이 높은 편에 속한다.
이렇게 src 폴더 안으로 SVG파일을 옮겼다면 이를 모듈처럼 import하여 사용해야 하는데, Vite에서 svg 파일을 모듈처럼 인식하여 intelliSense로 자동완성하도록 환경변수를 추가해주어야 타입에러가 나지 않는다.
frontend/src/vite-env.d.ts
/// <reference types="vite/client" />
declare module "*.svg" {
const content: string;
export default content;
}
위는 이미지 파일 등을 모듈로 선언하는 가장 쉬운 방식으로, 해당 모듈 선언에서 content는 "파일의 경로"라는 의미로 string으로 선언한다.
이렇게 선언한 후 아래와 같이 img 태그나 image 태그 안에서 사용하면 된다.
import backgroundFullSvg from "@assets/backgrounds/background-full.svg";
<img
src={backgroundFullSvg}
alt="Background"
/>
lazy를 이용한 code-splitting
React.lazy를 이용하여 특정 컴포넌트나 모듈을 lazy-import 할 수 있다.
const DonutChart = lazy(() =>
import("@/components/ui/donut-chart").then((mod) => ({
default: mod.DonutChart,
}))
);
const ReactMarkdownApp = lazy(() =>
import("@components/markdown/react-markdown-app").then((mod) => ({
default: mod.default,
}))
);
마크다운을 렌더링하는데 필요한 모듈(react-markdown)과 도넛 차트를 렌더링하는데 필요한 모듈(recharts)은 파일 용량에 큰데 비해 실제 사용되는 곳은 한 곳 밖에 없어서 위와 같이 Lazy Import를 하였다. 이렇게 Lazy Import를 하면 청크가 분리된다.
Lazy Import되는 로딩 시간동안 React.Suspense 태그를 통해 fallback을 줄 수 있다.
<Suspense fallback={<Skeleton className="w-[200px] h-[200px]" />}>
<DonutChart data={chartData} width={200} height={200} />
</Suspense>
이제 build를 하면 아래와 같은 결과를 볼 수 있다.
dist/index.html 0.45 kB │ gzip: 0.31 kB
dist/assets/background-full-BRfTiI_d.svg 573.85 kB │ gzip: 75.08 kB
dist/assets/calendar-swMXjLql.js 45.39 kB │ gzip: 14.18 kB
dist/assets/donut-chart-BBwToqWH.js 267.44 kB │ gzip: 83.34 kB
dist/assets/react-markdown-app-tOegX_zF.js 437.73 kB │ gzip: 130.23 kB
dist/assets/index-CaO0Q64m.js 999.02 kB │ gzip: 302.51 kB
svg파일이 gzip으로 압축되었다.
그리고 index.js 청크와는 별개로 달력, 도넛 차트, 리액트 마크다운 컴포넌트 청크가 생겼다.
rollup-plugin-visualizer
vite는 모듈 번들러로 rollup을 사용한다.
따라서 rollup-plugin-visualizer
를 설치하면 청크가 어떻게 나뉘어 있는지 확인할 수 있다.
npm install --save-dev rollup-plugin-visualizer
vite config에는 아래와 같이 플러그인을 추가해준다.
import { visualizer } from "rollup-plugin-visualizer";
export default defineConfig({
plugins: [
react(),
visualizer({
open: true, // 빌드 후 자동으로 브라우저 열기
filename: "dist/stats.html",
gzipSize: true,
brotliSize: true,
}),
],
});
빌드 후에 아래와 같은 화면이 실행된다.
index.js의 크기가 55%만을 차지하도록 줄었다.
react-markdown이 26.6%, 도넛 차트가 14%, 달력이 6.6% 가량을 차지하는 별도의 청크로 분리되었음을 확인할 수 있다.