动态导入和静态导入应按场景选择:静态导入适用于首屏必需、体积小、调用确定的核心模块;动态导入适用于延迟加载、重型依赖、低频使用且构建支持分包的模块,需兼顾类型、缓存与错误处理。

动态导入和静态导入不是“选哪个更好”,而是“在什么位置用哪个更合适”。关键看模块是否参与首屏渲染、是否高频使用、是否携带重型依赖,以及构建和运行时的协同成本。
看模块是否影响首屏性能
静态导入适合所有启动即需的代码:路由配置、状态管理初始化、核心 UI 组件、基础工具函数。这些模块体积小、调用确定、无副作用,提前加载反而更高效。
动态导入则用于明确延迟加载的场景:
- 用户点击后才出现的弹窗或面板(如“导出报表”按钮触发 ECharts 加载)
- 仅特定角色可见的功能(如管理员专属设置页)
- 首屏完全不涉及的后台能力(如离线缓存同步、日志上报增强模块)
看依赖体积与使用频率
一个模块是否该动态导入,不能只看文件大小,而要看它的“单位价值比”——即它带来的功能增益,是否值得占用一次网络请求和 Promise 开销。
例如:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 含 pdf-lib 或 ffmpeg.wasm 的模块:体积超 500KB,且 95% 用户从不触发,必须动态导入
- 仅导出两个工具函数的 dateUtils.js:体积 2KB,全站多处调用,静态引入更合理
- 中等体积但低频使用的 QRCodeScanner:可动态,但建议配合预加载(
import('./qrcode.js').then(...)前加link rel="prefetch")
看构建与运行时是否真正受益
动态导入的价值,只有在构建工具能生成独立 chunk、浏览器能缓存并复用时才成立。否则只是把同步阻塞变成异步等待。
要确认三点:
- Vite 或 Webpack 是否将
import()正确识别为分割点(查看 dist 目录下是否生成了xxx.xxxxxx.js独立文件) - 模块路径是否为静态字符串(
import(`./${name}.js`)不被支持,会退化为全量打包) - 是否配套处理了加载状态与错误兜底(比如 loading 骨架、fallback 提示、重试机制),否则白拆包也伤体验
看类型与工程约束是否兼容
TypeScript 项目中,动态导入返回的是 Promise<typeof module></typeof>,需注意类型推导是否完整:
- 命名导出需显式解构:
const { renderChart } = await import('./chart') - 默认导出需访问
.default:const Chart = (await import('./chart')).default - 建议配合
/* @ts-ignore */或定义declare module '*.js'避免类型报错
若项目已启用严格 Tree Shaking,还要留意动态导入的模块是否意外保留了未使用的导出——因为构建工具无法在编译期判断哪些命名导出会被运行时用到。










