Files
2nd/10_Wiki/Topics/Frontend/Bundle Size Optimization.md
T
koriweb d8a80f6272 chore(wiki): dangling 링크 canonical 정규화 (768파일/1200건)
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해
끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은
과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업.
도구: Datacollect/scripts/link_reconcile_apply.mjs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:24:15 +09:00

4.9 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-bundle-size-optimization Bundle Size Optimization 10_Wiki/Topics verified self
JS Bundle Optimization
Web Bundle Reduction
none A 0.9 applied
bundle
performance
webpack
vite
tree-shaking
2026-05-10 pending
language framework
JavaScript/TypeScript 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

// 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)

import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));

<Suspense fallback={<Skeleton />}>
  <Dashboard />
</Suspense>

Dynamic import for rare path

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

// 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

// 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

// 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)

import compression from 'vite-plugin-compression2';

export default defineConfig({
  plugins: [
    compression({ algorithm: 'brotliCompress', exclude: [/\.(br)$/, /\.(gz)$/] })
  ]
});

Server: strip locales from dayjs

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

🤖 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