Code splitting chia bundle thành nhiều chunk nhỏ — initial load nhẹ hơn, phần còn lại tải on demand. Nền tảng là dynamic import(): trả về Promise, bundler tự tách chunk riêng.
Các chiến lược:
- Route-based — mỗi route một chunk (React Router + React.lazy()); chiến lược nên làm đầu tiên.
- Component-based — lazy-load component nặng (rich text editor, PDF viewer, 3D) chỉ khi cần.
- Vendor splitting — tách node_modules thành chunk riêng (ít thay đổi hơn app code → cache lâu hơn). Webpack: SplitChunksPlugin. Vite: cấu hình thủ công qua build.rollupOptions.output.manualChunks — auto vendor-split đã bị bỏ từ Vite 2.9, plugin opt-in splitVendorChunkPlugin cũng đã deprecated.
- Shared chunks — code dùng chung nhiều route tách riêng, tránh duplicate trong nhiều chunk.
- Prefetch/preload — <link rel='prefetch'> cho navigation kế tiếp (lúc browser idle); Webpack magic comment: import(/ webpackPrefetch: true / './NextPage').
Phân tích: webpack-bundle-analyzer, vite-bundle-visualizer, source-map-explorer.
Lưu ý: quá nhiều chunk nhỏ có thể tệ hơn một chunk lớn do overhead request — HTTP/2 multiplexing giảm nhưng không xóa hẳn vấn đề.