Tree Shaking 能安全移除未使用代码的前提是代码满足静态可分析条件,必须使用 ES 模块语法、避免动态导出/导入、保持纯静态引用,并通过 sideEffects 字段正确声明副作用。

Tree Shaking 能安全移除未使用的代码,前提是代码满足“静态可分析”条件——即构建工具(如 Webpack、Rollup、Vite)能在不执行代码的前提下,准确判断哪些导出和导入被实际使用。关键不在于“怎么写得更炫”,而在于**避免破坏静态分析的模式**。
使用 ES 模块语法(必须)
CommonJS(require/module.exports)是运行时动态加载,无法静态推断依赖关系,Tree Shaking 会失效。
- ✅ 正确:用
export和import - ❌ 错误:混用
require或module.exports(尤其在同一个包中) - ⚠️ 注意:即使你写了 ES 模块,若依赖的第三方库发布的是 CommonJS 版本(如很多老 npm 包),它的代码仍无法被 shake —— 这时需检查其
package.json中的"type": "module"或"exports"字段是否支持 ESM
避免动态导出与动态导入
任何让导出名或导入路径变成运行时计算的行为,都会切断静态分析链。
- ❌ 不要这样写导出:
export const [key] = value(动态属性名)、export * from './utils'(除非确定所有成员都被用到,否则 Rollup/Webpack 通常保守保留) - ❌ 不要这样导出:
const obj = { a: 1 }; export default obj—— 对象字面量默认导出会阻碍对内部属性的追踪;应改为具名导出:export const a = 1 - ❌ 避免动态
import()的路径拼接:import(`./${name}.js`)—— 这属于代码分割范畴,Tree Shaking 不处理
保持导出与导入的“纯静态引用”关系
构建工具靠“谁导入了什么”来反向追溯哪些导出存活。一旦引用被间接化,就会失效。
立即学习“Java免费学习笔记(深入)”;
- ❌ 不要通过中间变量解构再导出:
import { foo, bar } from './math';<br> const utils = { foo, bar };<br> export default utils;
→ 构建工具无法知道utils.foo是否被外部使用 - ✅ 推荐直接具名导出:
export { foo, bar } from './math'或export { foo as calculate } from './math' - ❌ 不要在导出前做副作用操作:
console.log('init'); export const x = 1—— 即使x未被使用,日志仍会执行(因为模块初始化逻辑不可被移除);应确保导出语句本身无副作用
标记副作用(重要但易忽略)
如果模块**没有导出,但有顶层副作用**(如修改全局对象、注册事件、调用 localStorage.setItem),构建工具可能误删它。这时需在 package.json 中声明:
-
"sideEffects": false:表示整个包无副作用,所有未引用模块均可安全删除(最激进,适合纯工具函数库) -
"sideEffects": ["*.css", "*.scss"]:仅声明哪些文件有副作用,其余 JS 模块仍可 shake -
"sideEffects": true(默认):关闭 Tree Shaking 优化,所有模块都保留


















