Dynamic import() tạo chunk riêng — route-based splitting với React.lazy() là chiến lược đầu tiên; dùng / webpackPrefetch: true / để load trong idle time; chunks nên ít nhất 20-30KB gzipped để tránh HTTP overhead.
Dynamic import() là foundation của code splitting — trả về Promise, bundler tự tạo chunk file riêng. Route-based splitting (phổ biến nhất): React Router với React.lazy: const Dashboard = React.lazy(() => import('./pages/Dashboard')) wrapped trong <Suspense fallback={<Spinner/>}>. Next.js App Router tự động code split theo route — không cần config thêm. Component-based splitting — heavy components: const RichEditor = lazy(() => import('@/components/RichEditor')) cho TipTap, Quill editor (~500KB). Library splitting — chart libraries: const ChartComponent = dynamic(() => import('./ChartWrapper'), { ssr: false }) trong Next.js với ssr: false cho browser-only libraries. Prefetching để reduce latency: Webpack magic comments: import(/ webpackPrefetch: true / './HeavyPage') — browser load trong idle time khi user hovering link; / webpackPreload: true / cho resources cần ngay. Named chunks để caching: import(/ webpackChunkName: 'admin' / './AdminDashboard') → admin.abc123.js — caching tốt hơn 1.abc123.js. Granular imports: import('@sentry/browser').then(sentry => sentry.init(...)) — load Sentry sau khi app render xong (không block LCP). Lưu ý: quá nhiều chunks nhỏ tăng HTTP round-trips; HTTP/2 multiplexing giảm nhưng không eliminate overhead — chunks nên ít nhất 20-30KB gzipped.
Dynamic import() creates a separate chunk — route-based splitting with React.lazy() is the first strategy; use / webpackPrefetch: true / to load during idle time; chunks should be at least 20-30KB gzipped to avoid HTTP overhead.
Dynamic import() is the foundation of code splitting — it returns a Promise and bundlers automatically create a separate chunk file. Route-based splitting (most common): React Router with React.lazy: const Dashboard = React.lazy(() => import('./pages/Dashboard')) wrapped in <Suspense fallback={<Spinner/>}>. Next.js App Router automatically code-splits by route — no extra config needed. Component-based splitting for heavy components: const RichEditor = lazy(() => import('@/components/RichEditor')) for TipTap, Quill editors (~500KB). Library splitting for chart libraries: const ChartComponent = dynamic(() => import('./ChartWrapper'), { ssr: false }) in Next.js with ssr: false for browser-only libraries. Prefetching to reduce latency: Webpack magic comments: import(/ webpackPrefetch: true / './HeavyPage') — browser loads during idle time while user is hovering a link; / webpackPreload: true / for resources needed immediately. Named chunks for caching: import(/ webpackChunkName: 'admin' / './AdminDashboard') → admin.abc123.js — better caching than 1.abc123.js. Granular imports: import('@sentry/browser').then(sentry => sentry.init(...)) — load Sentry after the app renders (doesn't block LCP). Pitfall: too many small chunks increases HTTP round-trips; HTTP/2 multiplexing reduces but doesn't eliminate overhead — chunks should be at least 20-30KB gzipped.