--- id: wiki-2026-0508-bundle-size-optimization title: Bundle Size Optimization category: 10_Wiki/Topics status: verified canonical_id: self aliases: [JS Bundle Optimization, Web Bundle Reduction] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [bundle, performance, webpack, vite, tree-shaking] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: JavaScript/TypeScript framework: Vite/Rollup/Webpack --- # Bundle Size Optimization ## 매 한 줄 > **"매 byte 매 less 매 user time 매 less"**. Bundle size optimization은 production JS/CSS payload를 줄여 LCP/INP/TBT 개선 + mobile-first user 의 perceived speed 개선. 2026 standard tooling: Vite + Rollup tree-shaking, modern bundle analysis (Bundle Buddy, esbuild-visualizer), bundle budgets enforcement. ## 매 핵심 ### 매 4 lever - **Tree shaking**: ESM only, sideEffects:false, no re-export wildcards. - **Code splitting**: route / component lazy import. - **Compression**: brotli > gzip; precompress at build. - **Dependency surgery**: heavy lib → lighter alt or self-implement. ### 매 측정 우선 - Bundle visualizer (rollup-plugin-visualizer, source-map-explorer). - Bundle budget in CI (e.g., size-limit, bundlesize). - Real device testing (slow 3G profile). ### 매 응용 1. Lazy-load route chunks. 2. Remove unused locales (date-fns, moment). 3. Replace lodash with native / lodash-es. ## 💻 패턴 ### Vite + visualizer ```ts // vite.config.ts import { defineConfig } from 'vite'; import { visualizer } from 'rollup-plugin-visualizer'; export default defineConfig({ plugins: [ visualizer({ filename: 'stats.html', gzipSize: true, brotliSize: true }) ], build: { rollupOptions: { output: { manualChunks: { react: ['react', 'react-dom'], vendor: ['date-fns', 'zustand'] } } } } }); ``` ### Route-level code split (React) ```tsx import { lazy, Suspense } from 'react'; const Dashboard = lazy(() => import('./Dashboard')); }> ``` ### Dynamic import for rare path ```ts async function exportToPDF(data: Item[]) { const { jsPDF } = await import('jspdf'); const doc = new jsPDF(); doc.text(JSON.stringify(data), 10, 10); doc.save('out.pdf'); } ``` ### Replace heavy lib ```ts // X moment (~290KB) import moment from 'moment'; moment().format('YYYY-MM-DD'); // O Intl (built-in, 0KB) new Intl.DateTimeFormat('en-CA').format(new Date()); // O date-fns/format (tree-shakeable, ~3KB) import { format } from 'date-fns/format'; format(new Date(), 'yyyy-MM-dd'); ``` ### sideEffects flag ```json // package.json — library author 측 { "name": "my-lib", "type": "module", "sideEffects": false, "exports": { ".": { "import": "./dist/index.mjs", "types": "./dist/index.d.ts" } } } ``` ### size-limit budget enforcement ```json // package.json { "scripts": { "size": "size-limit" }, "size-limit": [ { "path": "dist/index.js", "limit": "50 KB" }, { "path": "dist/vendor.js", "limit": "120 KB" } ] } ``` ### Compression at build (brotli) ```ts import compression from 'vite-plugin-compression2'; export default defineConfig({ plugins: [ compression({ algorithm: 'brotliCompress', exclude: [/\.(br)$/, /\.(gz)$/] }) ] }); ``` ### Server: strip locales from dayjs ```ts import dayjs from 'dayjs'; import 'dayjs/locale/ko'; // 매 필요한 것만 dayjs.locale('ko'); ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Initial bundle > 200KB | route split + lazy load | | Single heavy lib | replace 또는 dynamic import | | Multi-tenant build | per-tenant treeshake config | | Library publish | ESM + `sideEffects:false` | | Edge runtime | bundle ≤ 1MB 가까이 strict budget | **기본값**: measure first → split → compress → swap heavy deps. ## 🔗 Graph - 부모: [[Frontend Performance]] - 변형: [[Code Splitting]] - 응용: [[Core Web Vitals Optimization (INP, LCP 개선)|Core Web Vitals]] · [[LCP]] - Adjacent: [[Vite]] · [[Rollup]] · [[esbuild]] ## 🤖 LLM 활용 **언제**: webpack/vite config audit, lib alternative suggestion, bundle analyzer interpretation. **언제 X**: 매 production 매 swap deploy — actual measurement 필수. ## ❌ 안티패턴 - **CommonJS lib import**: tree shaking blocked — ESM 사용. - **`import * as foo`**: bundler 매 mark 매 모든 export used. - **Polyfill 전체**: target browser baseline + browserslist으로 narrow. - **Single chunk all**: SPA → 매 long initial — split per route. - **Dev source maps in prod**: ship source map only via separate URL or skip. ## 🧪 검증 / 중복 - Verified (web.dev bundle size guide, Vite docs, size-limit GitHub). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — bundle optim 4 lever + Vite/size-limit pattern |