docs(10_Wiki): Topic_Business/General/Graphic/Programming을 Topics/ 하위로 이동
최상위 10_Wiki/Topic_*였던 4개 카테고리 폴더를 10_Wiki/Topics/Topic_* 로 재배치. 콘텐츠 변경 없음(순수 폴더 이동) — Topics/ 하위 나머지 폴더는 이미 지난 커밋에서 전부 정리된 상태(잔존 항목은 에이전트 운영 상태 및 사용자가 보존을 요청한 업데이트0615/무제 3.canvas 뿐).
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
---
|
||||
id: wiki-2026-0508-code-splitting
|
||||
title: Code Splitting
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Bundle Splitting, Dynamic Import]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [bundling, performance, webpack, vite, frontend]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: Vite / Webpack / Next.js
|
||||
---
|
||||
|
||||
# Code Splitting
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 bundle 의 chunk 의 분리, on-demand load 의 first-paint 단축"**. Code Splitting 은 dynamic `import()` + bundler chunking 의 결합 의 매 monolithic JS bundle 의 분해. 2026 Vite/Rspack/Turbopack 시대 에 route-level + component-level + vendor split 의 매 표준.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 splitting 의 axis
|
||||
- **Route-based**: 각 page 의 separate chunk — 매 SPA / Next.js 의 default
|
||||
- **Component-based**: heavy component 의 lazy (Modal, Chart, Editor)
|
||||
- **Vendor**: `node_modules` 의 separate chunk — long-term cache
|
||||
- **Dynamic feature**: locale, A/B variant 의 conditional load
|
||||
|
||||
### 매 mechanism
|
||||
- **Dynamic `import()`**: ECMAScript spec — Promise 의 return
|
||||
- **Bundler 의 split point detection**: `import()` 호출 의 chunk boundary
|
||||
- **Manifest**: hashed filename 의 mapping
|
||||
- **Preload / prefetch**: `<link rel="preload/prefetch">` hint
|
||||
|
||||
### 매 cost trade-off
|
||||
- **Pro**: initial bundle 의 작아짐 → faster TTI
|
||||
- **Con**: extra HTTP request, waterfall 위험 — preload 의 mitigate
|
||||
|
||||
### 매 응용
|
||||
1. Route-level lazy (React Router, Next.js).
|
||||
2. Modal / dialog (open 시 load).
|
||||
3. Heavy editor (Monaco, CodeMirror).
|
||||
4. Chart library (Recharts, ECharts).
|
||||
5. i18n locale chunk.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### React.lazy + Suspense
|
||||
```tsx
|
||||
import { lazy, Suspense } from 'react';
|
||||
|
||||
const Settings = lazy(() => import('./Settings'));
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Suspense fallback={<Spinner />}>
|
||||
<Settings />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Next.js dynamic
|
||||
```tsx
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const Chart = dynamic(() => import('@/components/Chart'), {
|
||||
loading: () => <p>Loading chart...</p>,
|
||||
ssr: false, // browser-only
|
||||
});
|
||||
|
||||
export default function Dashboard() {
|
||||
return <Chart data={data} />;
|
||||
}
|
||||
```
|
||||
|
||||
### Route-level (React Router v6)
|
||||
```tsx
|
||||
import { lazy } from 'react';
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{ path: '/', lazy: () => import('./routes/Home') },
|
||||
{ path: '/about', lazy: () => import('./routes/About') },
|
||||
{ path: '/admin/*', lazy: () => import('./routes/Admin') },
|
||||
]);
|
||||
|
||||
export default function App() {
|
||||
return <RouterProvider router={router} />;
|
||||
}
|
||||
```
|
||||
|
||||
### Vite의 manualChunks
|
||||
```ts
|
||||
// vite.config.ts
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
react: ['react', 'react-dom'],
|
||||
ui: ['@radix-ui/react-dialog', '@radix-ui/react-tabs'],
|
||||
charts: ['recharts', 'd3'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Webpack magic comment
|
||||
```ts
|
||||
const Editor = () => import(
|
||||
/* webpackChunkName: "editor" */
|
||||
/* webpackPrefetch: true */
|
||||
'./Editor'
|
||||
);
|
||||
```
|
||||
|
||||
### Conditional import (locale)
|
||||
```ts
|
||||
async function loadLocale(lang: string) {
|
||||
const messages = await import(`./locales/${lang}.json`);
|
||||
return messages.default;
|
||||
}
|
||||
```
|
||||
|
||||
### Preload critical chunk
|
||||
```html
|
||||
<link rel="modulepreload" href="/assets/Settings-abc123.js">
|
||||
```
|
||||
|
||||
```tsx
|
||||
// React: preload on hover
|
||||
<Link
|
||||
to="/settings"
|
||||
onMouseEnter={() => import('./Settings')}
|
||||
>
|
||||
Settings
|
||||
</Link>
|
||||
```
|
||||
|
||||
### Module Federation (micro-frontend)
|
||||
```ts
|
||||
// host webpack.config.js
|
||||
new ModuleFederationPlugin({
|
||||
remotes: {
|
||||
checkout: 'checkout@https://cdn/checkout/remoteEntry.js',
|
||||
},
|
||||
});
|
||||
|
||||
// usage
|
||||
const Checkout = lazy(() => import('checkout/Cart'));
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| SPA, multi-page | Route-based split |
|
||||
| Heavy modal / editor | `lazy()` + Suspense |
|
||||
| Vendor lib stable | manualChunks vendor split |
|
||||
| SSR + browser-only | `dynamic({ ssr: false })` |
|
||||
| Independent deploy | Module Federation |
|
||||
| Hover-triggered | preload on intent |
|
||||
|
||||
**기본값**: route-based + heavy-component lazy + vendor chunk.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Web Performance]]
|
||||
- 변형: [[Module Federation]]
|
||||
- 응용: [[Lazy-Loading-Strategies|Lazy Loading]]
|
||||
- Adjacent: [[Vite]] · [[Next.js]] · [[Suspense]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: route lazy, heavy component 의 split, vendor chunking 코드 generation.
|
||||
**언제 X**: 매 small app (10kb 의 split 의 overhead 가 더 큼).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **너무 fine-grained split**: 100개 chunk → request flood — 매 ~10-30 chunk 의 sweet spot.
|
||||
- **Waterfall**: A → B → C 의 sequential — 매 parallel preload.
|
||||
- **Vendor chunk 의 무한 growth**: dependency 추가 시 cache invalidation — 매 stable lib 만 vendor.
|
||||
- **Suspense 의 boundary 누락**: error / blank screen.
|
||||
- **`ssr: false` 의 abuse**: SEO 손실.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Vite docs, Webpack docs, Next.js docs, React 19).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — splitting strategies + bundler config + MF |
|
||||
Reference in New Issue
Block a user