名字来自「摇晃树让枯叶掉下」。原理是 ES Module 的静态结构:import/export 在编译期就能确定模块的导出树,未被任何地方引用的导出被标记为「死代码」安全删除。所以它只对 ESM 有效——CommonJS 的 require 是运行时函数,无法静态分析哪些导出有用。
常见失效场景:副作用代码(模块顶层执行的语句,如往原型/window 上挂东西)打包器不敢删,副作用标记(package.json "sideEffects": false)就是为了声明「本包可放心摇」。只 import 一个工具却引入了整个 polyfill 库(如 lodash 全量引入),要用按需引入(lodash/xx 或 lodash-es + 插件)摇掉。
// math.js —— ESM 才能被摇树 export function add(a, b) { return a + b; } export function unused() { console.log('永远没人调我'); } // main.js import { add } from './math.js'; console.log(add(1, 2)); // unused 会被摇掉(dead code) // ---- 经典反例:全量引入 ---- import _ from 'lodash'; // ✗ 引入整个 lodash(数十 KB) import debounce from 'lodash/debounce'; // ✓ 只引一个函数 // ---- 副作用挡住摇树 ---- // polyfill.js: window.foo = 1; ← 顶层执行,打包器不敢删 // 库的 package.json 声明 {"sideEffects": false} 后摇树才彻底