tree shaking 依赖 es 模块静态结构,要求使用命名导出(如 export const f = ...)和静态导入(如 import { f } from 'x'),禁用默认导出对象、commonjs、动态导入及顶层副作用,确保构建工具在编译期精确分析并剔除未引用代码。

JavaScript 的 Tree Shaking 依赖于 ES 模块的静态结构,而解构导出(destructuring export)本身不是合法语法,**不能直接“解构导出”**。但你可能想表达的是:在使用 解构导入(import { a, b } from 'mod')时,如何确保模块仍支持 Tree Shaking;或想通过某种导出写法(如命名导出 + 解构赋值)让未使用的导出不被保留。下面分几种常见场景说明关键点和正确做法。
✅ 正确使用命名导出 + 静态导入
Tree Shaking 能生效的前提是:导出是静态的、可分析的,且导入只引用了其中一部分。
- 模块必须用
export const x = ...、export function f() {...}等命名导出(named exports),而不是export default { a, b }这种对象默认导出——后者会让所有属性被视为一个整体,无法单独剔除。 - 导入端必须用静态解构式导入:
import { foo } from './utils.js',而非先import utils from './utils.js'再const { foo } = utils——后者会强制引入整个模块,破坏摇树。 - 确保构建工具(如 Webpack、Rollup、Vite)启用 Tree Shaking(通常默认开启),且代码未被意外标记为“有副作用”(例如模块顶层有非导出的执行逻辑、或
package.json中设置了"sideEffects": true)。
❌ 避免这些破坏摇树的“伪解构导出”写法
以下看似像“解构导出”,实则会阻断 Tree Shaking:
-
export default { a: 1, b: () => {} }—— 默认导出一个对象,打包器无法判断a和b是否被单独使用。 -
const obj = { a: 1, b: 2 }; export { obj }—— 导出的是引用,不是独立绑定,obj.a不算静态可追踪的命名导出。 - 在导出前做运行时计算:
export const c = Math.random() > 0.5 ? 1 : 2—— 即使没被导入,也可能因潜在副作用被保留(尤其在旧版 Webpack 中)。
✅ 推荐的清晰、可摇树的导出模式
想组织多个相关导出又保持摇树能力?推荐这样写:
- 每个功能/常量独立命名导出:
export const API_URL = 'https://api.example.com';export function fetchUser(id) { ... }export function updateUser(user) { ... } - 需要分组时,用嵌套命名空间(仍为静态导出):
export const api = { URL: API_URL, fetchUser, updateUser };
注意:此时import { api } from 'x'会引入全部,但import { api } from 'x'; const { fetchUser } = api;仍无法摇树;应改为import { fetchUser } from 'x'直接导入目标函数。
? 构建时验证是否摇树成功
别只靠理论——动手确认:
- 在 Vite 或 Rollup 中启用
build.rollupOptions.output.manualChunks或查看生成的.mjs输出,搜索未使用的导出名是否还存在。 - Webpack 可加
stats: { usedExports: true }并看控制台警告(如"export XXX was not used")。 - 用 source-map-explorer 或 webpack-bundle-analyzer 查看实际打包内容。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











