开启Tree Shaking需先让代码“可摇”:转ES Module、清理动态导入、关闭干扰Babel插件、声明sideEffects,并通过未压缩产物和可视化工具验证剔除效果。

重构旧项目时开启 Tree Shaking,关键不是“加功能”,而是系统性地扫清阻碍静态分析的障碍。旧项目往往混合 CommonJS、动态 require、顶层副作用代码,直接开 production 模式不会自动删掉无用函数——得先让代码变得“可摇”。
把 CommonJS 模块逐步转成 ES Module
Tree Shaking 只对 import/export 生效,require/module.exports 会被整个模块保留。不要一步重写全部,优先处理高频引用的工具模块:
- 将
utils.js中的module.exports = { foo, bar }改为export { foo, bar } - 对应调用处把
const { foo } = require('./utils')改成import { foo } from './utils.js' - 避免混用:同一文件里不要同时出现
import和require,否则构建工具可能降级处理整块依赖
清理动态导入和运行时拼接路径
任何 import() 表达式(如 import(`./pages/${name}.js`))或 require('path/' + var) 都会让构建工具放弃对该模块的导出分析,视为“可能被用到”。
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
- 把条件加载逻辑上提到配置层,例如用
if (env === 'admin') import('./admin.js')替代字符串拼接 - 对必须动态加载的模块,接受它无法被 shake 的事实,单独打包或标记为异步 chunk
- 检查 Babel 插件(如
@babel/plugin-transform-commonjs)是否意外把import编译回require,关闭该插件或限定作用范围
显式声明副作用,避免误删
即使代码转成了 ES Module,如果模块顶层有 console.log、localStorage.setItem、document.createElement 等操作,Webpack 默认不敢删——因为不确定你是否依赖它的执行时机。
立即学习“Java免费学习笔记(深入)”;
- 在
package.json根目录添加"sideEffects": false,表示所有 JS 文件都只做导出,无额外行为 - 如有例外(比如
polyfill.js或引入 CSS 的文件),改用数组形式:"sideEffects": ["./src/polyfill.js", "**/*.css"] - 对纯工具函数文件,确保没有顶层语句;若有初始化逻辑,封装进函数并导出,由业务层显式调用
验证是否真正生效
别只看打包体积下降——那可能是压缩导致的。要确认死代码被剔除,得看实际输出内容:
- 临时关闭 Terser 压缩(Webpack 中设
optimization.minimize: false),查看未压缩产物中是否还存在未引用的函数名 - 用
webpack-bundle-analyzer打开可视化报告,展开某个模块,观察其导出项哪些被标灰(即未被引用) - 在源码中加一个明显但未使用的导出,如
export const __DEBUG_ONLY__ = 'dead',构建后搜索产物里是否还存在该字符串

















