tree shaking 仅剔除未引用的 export,变量混淆由 terser 在 minimize 阶段通过 mangle 和 compress 实现;usedexports 是 tree shaking 前提,标记未使用导出供 terser 删除,二者职责分明、协同工作。

Tree Shaking 本身不负责变量混淆,它只负责剔除未被引用的导出(export);而变量混淆(如把 userName 变成 _a、_b)属于代码压缩/保护阶段,由 Terser 在 minimize 阶段完成。optimization.usedExports 是 Tree Shaking 的前提条件之一,但它和混淆没有直接因果关系——二者协同工作,但职责分明。
要实现“高级的变量混淆与剔除”,关键在于分清两个层次:
✅ 先靠 usedExports 标记哪些 export 真正被用到 → 让 Terser 知道哪些代码可安全删除;
✅ 再靠 Terser 的 mangle 和 compress 配置做变量重命名、死代码移除、控制流简化等混淆动作。
1. usedExports 是 Tree Shaking 的基础开关
它让 Webpack 分析每个模块的 export 是否被其他模块 import,并标记为 “used” 或 “unused”。只有标记为 unused 的 export,后续 Terser 才有机会删掉。
- 默认在 production 模式下启用(无需手动设
true); - 若你关闭了它(比如
usedExports: false),即使代码写了export const unused = 1,也不会被剔除; - 它不处理未导出的局部变量(如
const tmp = 2),这类变量是否保留,取决于 Terser 的compress.dead_code。
// utils.js
export const used = () => 'ok';
export const unused = () => 'dead'; // 不会被 import,且 usedExports 开启时会被标记为 dead
// main.js
import { used } from './utils.js';
console.log(used());
→ unused 函数会被标记为未使用,最终在压缩阶段被 Terser 删除。
2. Terser 负责真正剔除 + 混淆
usedExports 只是“打标”,Terser 才是“执行者”。它通过以下配置实现高级效果:
compress: { drop_console: true, dead_code: true, ... }
启用死代码消除(包括usedExports标记的未使用 export)、移除console、折叠常量等。mangle: { toplevel: true, eval: false, reserved: ['Vue', '$'] }
对顶层变量/函数名进行混淆(如function getData()→function a()),同时保留框架关键词。mangleProperties: { regex: /^_/ }
混淆所有以下划线开头的属性名(适合私有字段,如this._cache→this._a)。
示例配置:
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
mode: 'production',
optimization: {
usedExports: true, // ✅ 必须开启,否则 Terser 不知道哪些 export 可删
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.info'],
dead_code: true, // 关键:配合 usedExports 剔除未引用的 export
},
mangle: {
toplevel: true,
reserved: ['require', 'exports', 'module'], // 避免破坏 CommonJS
},
format: { comments: false },
},
}),
],
},
};
⚠️ 注意:mangle 不会混淆 export 的名称本身(如 export const apiHost = '...' 中的 apiHost),因为这是导出标识符,需保持可引用性;但它会混淆该变量在模块内部的局部引用名(如函数体内 const host = apiHost → const a = b),前提是 host 没被导出。
3. 混淆敏感字符串或逻辑?需要额外插件
Terser 原生不支持字符串加密、控制流扁平化等强混淆。如果需求是:
- 把
'https://api.example.com'变成atob('aHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20=') - 或把
if (x > 0) { ... }拆成多层switch+ 无意义表达式
那就要引入专用混淆插件,例如:
-
javascript-obfuscator(Webpack plugin 版本) -
rollup-plugin-obfuscator(Vite 场景更常见) - 或在 Terser 后链式调用(不推荐,因 Terser 输出已是压缩 AST,再混淆易出错)
这类操作已超出 Tree Shaking 和标准 Terser 范畴,属于代码保护层,需单独评估性能开销与调试成本。
4. sideEffects 字段影响的是模块级剔除,不是变量级
你可能看到 package.json 里配 "sideEffects": false 或 ["*.css"] —— 这告诉 Webpack:这个包整体没副作用,整个模块可以被整块摇掉(哪怕它有 export)。它和 usedExports 是不同粒度的优化:
-
sideEffects: false→ 模块级(import './polyfill.js' 整行可删) -
usedExports: true→ 导出级(export const a = 1; export const b = 2;中只删b)
两者配合,才能做到“删得准、删得狠”。
不复杂但容易忽略











