es模块在混合打包中易因tree-shaking误删html或全局调用的函数,需显式export并挂载window、配置preserveentrysignatures、设置modulesideeffects、混淆时保留标识符,以及html协同声明确保保留。

ES 模块(ESM)在混合打包策略下容易因 tree-shaking 机制被误删核心逻辑,尤其当函数仅被 HTML 中的 onclick 或全局作用域调用时。关键不是“禁用 tree-shaking”,而是让打包器明确识别这些导出/引用关系。
显式导出并标记为外部可访问
ESM 默认是封闭作用域,未 export 的函数即使挂载到 window,也会被 Terser 或 Rollup 当作死代码移除。必须主动暴露:
- 在模块末尾添加
export { functionA, appendHtml };—— 即使不被其他 JS 导入,也要导出,确保打包器保留该符号 - 若需兼容 HTML 直接调用,再加一句
window.functionA = functionA;,形成双重声明:既满足 ESM 规范,又向全局环境“注册” - Rollup 中启用
preserveEntrySignatures: 'exports-only',避免入口模块因无 import 被整块丢弃
配置打包器跳过对特定模块的 tree-shaking
对已知会被 HTML 或运行时动态调用的核心模块,可绕过静态分析判断:
- Rollup:在
external或preserveModules基础上,配合treeshake.moduleSideEffects设为false,或为该文件单独设置moduleSideEffects: true - Webpack:在
module.rules中为该 JS 文件指定parser.sideEffects: true,或通过/*#__PURE__*/注释反向控制(但慎用,仅用于副作用明确的调用) - Vite 构建时(底层 Rollup)可在
vite.config.ts的build.rollupOptions.treeshake中加入onwarn拦截并保留可疑导出
混淆前加固调用链可见性
混淆工具(如 javascript-obfuscator)可能进一步破坏引用关系,需提前固化入口:
- 在混淆配置中启用
keepIdentifiers: ['functionA', 'appendHtml'],防止重命名导致 HTML 中的字符串调用失效 - 避免开启
deadCodeInjection或controlFlowFlattening等强干扰选项——它们会掩盖函数定义位置,加剧打包器误判 - 若使用 Terser,关闭
compress.drop_unused或设为false,并在compress.unused中排除关键函数名
HTML 与 JS 的协同声明
单纯靠 JS 端处理不够,HTML 层也要辅助传递“此函数不可删”的语义:
- 在
<script></script>标签中添加data-entry="true"自定义属性,配合自定义插件扫描并注入 side-effects 声明 - 改用
import('./core.js').then(m => window.functionA = m.functionA)动态导入,明确建立模块依赖路径,比直接 script 标签更易被打包器追踪 - 对多文件场景(如 a.js + b.js),用 Rollup 的
input: ['a.js', 'b.js']多入口,而非单入口再 import,避免解析中断
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











