JavaScript代码分割核心是动态import()语法,配合路由拆分、第三方库轻量化、预加载策略及打包分析优化,实现按需加载以减少首屏体积。

JavaScript 实现代码分割、按需加载模块,核心是利用现代打包工具(如 Webpack、Vite)的动态 import() 语法,配合合理的路由或功能划分,把大体积的 JS 拆成小块,在真正需要时才加载,从而显著减少首屏资源体积和解析时间。
用 import() 动态导入替代静态 import
静态 import 会在构建时被提前打包进主 bundle,而 import() 是一个返回 Promise 的函数,Webpack/Vite 能自动识别并将其单独拆包:
- ❌ 静态导入(全量加载):
import { utils } from './utils.js'; - ✅ 动态导入(按需加载):
const { utils } = await import('./utils.js');或import('./utils.js').then(module => {...})
注意:动态 import() 只支持在函数作用域内调用(不能在模块顶层直接写),适合放在事件回调、条件分支或组件挂载逻辑中。
结合路由做页面级代码分割(推荐)
单页应用中,不同路由对应不同视图,天然适合按路由拆分。以 React Router + Vite 为例:
立即学习“Java免费学习笔记(深入)”;
- 定义异步路由组件:
const Home = () => import('@/pages/Home.vue'); - Vue Router 中使用:
{ path: '/', component: () => import('@/pages/Home.vue') } - React Router v6.4+:
element:+loader: () => import('./About').then(m => ({ Component: m.default }))
打包后每个页面会生成独立 chunk(如 Home.abc123.js),访问 / 时只加载首页代码,跳转到 /about 才拉取对应 chunk。
对第三方库做条件性加载或轻量化替代
有些大型依赖(如 moment、lodash、monaco-editor)占体积大但可能只用其中一两个方法:
- 改用更小的替代库:用
date-fns替代moment,用lodash-es+ 按需导入:import startOfToday from 'date-fns/startOfToday'; - 延迟加载重型组件:比如编辑器、图表库,封装成异步组件,仅在用户点击“编辑”按钮后才加载:
if (isEditing) await import('monaco-editor'); - 利用打包工具的
externals或 CDN:将 jQuery、React 等稳定依赖外置,避免重复打包。
配合 webpackPrefetch / webpackPreload 提升体验
在动态 import() 后添加魔法注释,可控制预加载策略:
-
import(/* webpackPrefetch: true */ './ReportModule.js'):空闲时预取(适合用户**很可能后续访问**的模块,如“导出报表”按钮后的模块) -
import(/* webpackPreload: true */ './Header.js'):与当前导航并行加载(适合**当前路由即将用到**的模块,如首屏 Header 中的搜索框逻辑)
Vite 中对应的是 /* @vite-ignore */ + 插件支持,或直接用 import.meta.webpackContext(旧版);新版 Vite 更推荐用 import('./mod.js').then(...) + 构建配置中的 build.rollupOptions.output.manualChunks 精细分包。
不复杂但容易忽略:别只盯着 JS 拆分,记得检查拆出的 chunk 是否有公共依赖重复打包(用 webpack-bundle-analyzer 分析)、是否启用了 Gzip/Brotli 压缩、以及是否设置了 HTTP 缓存头。真实优化效果,得看 Lighthouse 的 “Reduce JavaScript payloads” 和 “Eliminate render-blocking resources” 两项指标。











