JavaScript代码分割核心是按需拆分大文件以减少首屏加载量,关键在于加载时机、粒度控制与用户体验;主要手段包括动态import()、路由级懒加载、SplitChunks提取公共依赖、预加载/预获取及合理分包策略。

JavaScript 实现代码分割,核心是把大块的打包文件(如 bundle.js)按需拆成更小的、独立加载的模块,避免用户首次访问时下载大量无用代码。关键不在于“怎么拆”,而在于“什么时候拆、拆成什么粒度、如何让加载过程对用户无感”。
用动态 import() 按需加载模块
这是现代前端最常用、标准且无需额外配置的方式。它返回 Promise,天然支持异步加载和错误处理。
- 替代静态
import:把原本在模块顶部写的import { Chart } from './charts.js',改成运行时按需调用import('./charts.js').then(({ Chart }) => {...}) - 常用于路由级或组件级分割:比如 React 中配合
React.lazy加载页面组件;Vue 中用defineAsyncComponent - 支持 webpack / Vite / esbuild 等构建工具自动识别并生成独立 chunk,文件名通常带 hash,便于长期缓存
结合路由做懒加载(Route-based Splitting)
用户一次只看一个页面,没必要一上来就加载所有页面逻辑。按路由拆分是最自然、收益最高的策略。
- React Router v6 示例:
→ 改为} /> element={,并在 }AdminPage内部用React.lazy(() => import('./pages/AdminPage')) - 确保 fallback 状态合理:加骨架屏或 loading 提示,避免白屏卡顿
- 注意 SSR 或服务端渲染场景下需配合服务端同步加载,否则 hydration 失败
提取公共依赖与运行时(SplitChunks + Runtime)
光靠动态 import 不够——重复的第三方库(如 lodash、react-dom)可能被多次打包进不同 chunk,导致总体积不降反升。
立即学习“Java免费学习笔记(深入)”;
- Webpack 中开启
splitChunks.chunks: 'all',自动提取多处引用的模块到vendor或commonchunk - 把 webpack 运行时逻辑单独抽离(
runtimeChunk: 'single'),避免业务代码变更导致 vendor chunk 的 hash 变化,提升缓存命中率 - Vite 默认已启用智能分割,但可通过
build.rollupOptions.output.manualChunks手动控制,例如把vue和lodash-es单独成包
预加载与预获取(Preload & Prefetch)优化体验
代码分割后,资源加载时机很重要。默认的动态 import 是“需要时才发起请求”,但有时可以更早准备。
-
import(/* webpackPrefetch: true */ './ReportModal.js'):空闲时后台加载,适合用户**可能进入**但非立即需要的模块(如设置页里的高级导出功能) -
import(/* webpackPreload: true */ './CriticalChart.js'):和当前模块同优先级并行加载,适合**紧接下一步就会用到**的资源(如首页按钮点击后立刻展示的图表) - Vite 中对应语法为
/* @vite-ignore */+ 注释指令,或使用import.meta.preload()API
不复杂但容易忽略:代码分割不是越多越好,过度拆分会增加 HTTP 请求次数、压缩/解析开销,甚至触发浏览器并发限制。建议以用户行为路径为单位(如登录流、编辑流、报表流)做聚类拆分,并用 Lighthouse 或 WebPageTest 验证首屏时间、可交互时间(TTI)、最大内容绘制(LCP)是否真实改善。











