docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를 Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류. - 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로 자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거, 동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거. - 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming, Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business, Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로, 나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는 title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백). 원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지. - 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서. - 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는 지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지. - Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경. - 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
---
|
||||
id: perf-bundle-analysis
|
||||
title: JS Bundle Analysis — Tree-shake / Split / Size budget
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [performance, bundle, vite, webpack, vibe-coding]
|
||||
tech_stack: { language: "TS / Vite / Webpack", applicable_to: ["Frontend"] }
|
||||
applied_in: []
|
||||
aliases: [bundle analysis, tree shake, code split, dynamic import, size limit, source map explorer]
|
||||
---
|
||||
|
||||
# Bundle Analysis
|
||||
|
||||
> 1MB+ JS bundle = 모바일 3G = 10초+ load. **분석 → tree-shake → split → lazy → size budget**. CI 가 회귀 차단.
|
||||
|
||||
## 📖 핵심 개념
|
||||
- Tree-shake: 안 쓴 export 제거.
|
||||
- Code split: route / component 별 chunk.
|
||||
- Dynamic import: 사용 시 로드.
|
||||
- Size budget: CI gate.
|
||||
|
||||
## 💻 코드 패턴
|
||||
|
||||
### Vite — visualizer
|
||||
```bash
|
||||
yarn add -D rollup-plugin-visualizer
|
||||
```
|
||||
|
||||
```ts
|
||||
// vite.config.ts
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
|
||||
plugins: [
|
||||
visualizer({ open: true, gzipSize: true, brotliSize: true }),
|
||||
];
|
||||
```
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
# stats.html 자동 open — sunburst chart
|
||||
```
|
||||
|
||||
### Source map explorer
|
||||
```bash
|
||||
npx source-map-explorer dist/assets/*.js
|
||||
```
|
||||
|
||||
→ 각 module 의 byte 시각화.
|
||||
|
||||
### Webpack — bundle analyzer
|
||||
```bash
|
||||
yarn add -D webpack-bundle-analyzer
|
||||
```
|
||||
|
||||
```js
|
||||
// webpack.config.js
|
||||
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||
plugins: [new BundleAnalyzerPlugin({ analyzerMode: 'static' })];
|
||||
```
|
||||
|
||||
### Next.js
|
||||
```bash
|
||||
ANALYZE=true yarn build
|
||||
```
|
||||
|
||||
```ts
|
||||
// next.config.js
|
||||
const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true' });
|
||||
module.exports = withBundleAnalyzer({});
|
||||
```
|
||||
|
||||
### Tree-shake 깨지는 패턴
|
||||
```ts
|
||||
// ❌ default export + barrel
|
||||
import lib from 'lib'; // 모든 거 import
|
||||
import { fn } from 'lib'; // 더 좋음 — but lib 가 sideEffects 인지
|
||||
|
||||
// ❌ side effects (top-level)
|
||||
console.log('module loaded'); // tree-shake 차단
|
||||
|
||||
// ❌ require (dynamic)
|
||||
const x = require(`module-${name}`);
|
||||
|
||||
// ✅ Named ESM imports + sideEffects: false
|
||||
```
|
||||
|
||||
```jsonc
|
||||
// package.json — library publishing
|
||||
{
|
||||
"sideEffects": false // 또는 ["./styles.css"]
|
||||
}
|
||||
```
|
||||
|
||||
→ Bundler 가 안전하게 제거.
|
||||
|
||||
### Dynamic import (route split)
|
||||
```tsx
|
||||
// React lazy
|
||||
const Heavy = lazy(() => import('./Heavy'));
|
||||
|
||||
<Suspense fallback={<Spinner />}>
|
||||
<Heavy />
|
||||
</Suspense>
|
||||
```
|
||||
|
||||
```ts
|
||||
// 일반 dynamic
|
||||
button.onclick = async () => {
|
||||
const { default: heavy } = await import('./heavy');
|
||||
heavy.run();
|
||||
};
|
||||
```
|
||||
|
||||
### Route-level split (Vite)
|
||||
```tsx
|
||||
// react-router 6+
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: '/admin',
|
||||
lazy: async () => {
|
||||
const { AdminPage } = await import('./AdminPage');
|
||||
return { Component: AdminPage };
|
||||
},
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
### Manual chunks
|
||||
```ts
|
||||
// vite.config.ts
|
||||
build: {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
react: ['react', 'react-dom'],
|
||||
query: ['@tanstack/react-query'],
|
||||
editor: ['@tiptap/core', '@tiptap/react'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
### Library swap (큰 → 작은)
|
||||
```
|
||||
moment (200KB) → date-fns (modular, ~10KB used)
|
||||
lodash (full) → lodash-es / specific imports
|
||||
react-icons (모두) → 단일 svg 또는 lucide-react (tree-shake)
|
||||
material-ui (?? KB) → headless UI + Tailwind
|
||||
```
|
||||
|
||||
```ts
|
||||
// ❌
|
||||
import _ from 'lodash'; // 모두
|
||||
|
||||
// ✅
|
||||
import debounce from 'lodash/debounce';
|
||||
// 또는 lodash-es
|
||||
import { debounce } from 'lodash-es';
|
||||
```
|
||||
|
||||
### CDN / external (큰 lib)
|
||||
```ts
|
||||
// vite.config — 일부 lib 외부화
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: ['react', 'react-dom'],
|
||||
output: {
|
||||
globals: { react: 'React', 'react-dom': 'ReactDOM' },
|
||||
},
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
```html
|
||||
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
||||
```
|
||||
|
||||
→ Bundle 작아짐 + CDN cache.
|
||||
|
||||
### Modern build (Vite 자동)
|
||||
- ES module syntax 그대로 (browser native).
|
||||
- 옛 browser 만 polyfill (`@vitejs/plugin-legacy`).
|
||||
|
||||
### Size budget (size-limit)
|
||||
```bash
|
||||
yarn add -D size-limit @size-limit/preset-app
|
||||
```
|
||||
|
||||
```jsonc
|
||||
// package.json
|
||||
{
|
||||
"size-limit": [
|
||||
{ "path": "dist/**/*.{js,css}", "limit": "300 KB" },
|
||||
{ "path": "dist/index-*.js", "limit": "150 KB" }
|
||||
],
|
||||
"scripts": {
|
||||
"size": "size-limit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
yarn size
|
||||
# CI 에서 강제
|
||||
```
|
||||
|
||||
### Bundlephobia (NPM 패키지 사이즈)
|
||||
```bash
|
||||
# 새 lib 추가 전
|
||||
# https://bundlephobia.com/package/<lib>
|
||||
```
|
||||
|
||||
→ 의존 추가 결정.
|
||||
|
||||
### Gzip / Brotli compression
|
||||
```nginx
|
||||
gzip on;
|
||||
gzip_types text/css application/javascript application/json;
|
||||
gzip_min_length 1024;
|
||||
|
||||
brotli on;
|
||||
brotli_types text/css application/javascript application/json;
|
||||
```
|
||||
|
||||
→ 30-70% 추가 절감.
|
||||
|
||||
### Async lib (dynamic only)
|
||||
```ts
|
||||
// 무거운 lib = 사용자 인터랙션 시만
|
||||
let echarts: typeof import('echarts') | null = null;
|
||||
|
||||
async function showChart() {
|
||||
if (!echarts) echarts = await import('echarts');
|
||||
echarts.init(...);
|
||||
}
|
||||
```
|
||||
|
||||
### Image vs JS
|
||||
```
|
||||
JS 100KB → parse + execute = 실제 시간 큼.
|
||||
Image 100KB → 그냥 바이트.
|
||||
|
||||
→ JS 가 비용 더 높음. 줄이기 우선.
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준
|
||||
| 작업 | 도구 |
|
||||
|---|---|
|
||||
| 분석 | Vite visualizer / Source map explorer |
|
||||
| Route split | React.lazy / loader |
|
||||
| 큰 lib → 작은 | bundlephobia 비교 |
|
||||
| Library export 검사 | sideEffects: false |
|
||||
| CI 회귀 | size-limit |
|
||||
| Modern stack | Vite/Rollup (vs Webpack legacy) |
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **모든 거 한 bundle**: 첫 load 큼.
|
||||
- **`import * as`**: tree-shake 어려움.
|
||||
- **CSS-in-JS 큰 lib**: runtime 비용. Tailwind 또는 vanilla extract.
|
||||
- **모든 component lazy**: waterfall — 첫 paint 느림.
|
||||
- **Polyfill 모든 browser**: 작은 점유율 위해 큰 cost.
|
||||
- **Bundle analysis 안 함**: 큰 lib 모름.
|
||||
- **Source map prod 노출**: 코드 leak. 또는 sentry 만.
|
||||
|
||||
## 🤖 LLM 활용 힌트
|
||||
- Vite visualizer 매 빌드 + size-limit CI.
|
||||
- Route lazy + manual chunks.
|
||||
- 큰 lib = bundlephobia + 작은 alternative.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[Web_Performance_Core_Vitals]]
|
||||
- [[React_Code_Splitting]]
|
||||
- [[TS_Build_Bundler_Patterns]]
|
||||
Reference in New Issue
Block a user