Files
2nd/10_Wiki/Topics/Frontend/Code Splitting.md
T
2026-05-10 22:08:15 +09:00

5.2 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-code-splitting Code Splitting 10_Wiki/Topics verified self
Bundle Splitting
Dynamic Import
none A 0.9 applied
bundling
performance
webpack
vite
frontend
2026-05-10 pending
language framework
TypeScript 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

import { lazy, Suspense } from 'react';

const Settings = lazy(() => import('./Settings'));

export default function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <Settings />
    </Suspense>
  );
}

Next.js dynamic

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)

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

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

const Editor = () => import(
  /* webpackChunkName: "editor" */
  /* webpackPrefetch: true */
  './Editor'
);

Conditional import (locale)

async function loadLocale(lang: string) {
  const messages = await import(`./locales/${lang}.json`);
  return messages.default;
}

Preload critical chunk

<link rel="modulepreload" href="/assets/Settings-abc123.js">
// React: preload on hover
<Link
  to="/settings"
  onMouseEnter={() => import('./Settings')}
>
  Settings
</Link>

Module Federation (micro-frontend)

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

🤖 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