设计支持 tree shaking 的组件库,核心做法是将所有模块导出为 es module (esm) 格式,并确保代码中不包含任何副作用(side effects)。这意味着在顶层作用域中不能直接执行修改全局变量、注册全局事件或隐式引入其他模块的代码。只要遵循这一规范,打包工具就能通过静态分析识别并剔除未使用的导出。

如何确保代码没有副作用
要消除副作用,必须避免在模块顶层直接调用函数来改变环境状态。例如,不要在文件顶部直接调用 install() 方法,也不要使用 require() 隐式加载依赖。正确的做法是只进行纯函数的定义和常量的声明,将所有的初始化逻辑封装在导出的函数内部,由使用者显式调用。

// utils.js - 无副作用
export function formatDate(date) {
return new Date(date).toLocaleDateString();
}
// index.js - 无副作用
import { formatDate } from './utils';
export const components = {
Button: () => '<button></button>',
};
export { formatDate }; // 显式导出
上述代码中,formatDate 是一个纯函数,没有访问外部状态。在 index.js 中,我们只是定义了对象并导出了它,没有任何立即执行的逻辑。这种结构允许打包工具安全地移除未使用的 Button 组件,同时保留 formatDate。
如何处理需要全局注册的插件
对于需要全局注册的插件,不能直接在顶层执行注册操作,而应该提供一个工厂函数或安装方法。使用者在应用入口显式调用该方法时,才会触发副作用。这样既保留了功能,又符合 Tree Shaking 的要求。
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型

// plugin.js
export function install(app) {
app.config.globalProperties.$myPlugin = true;
}
// main.js
import { install } from './plugin';
import { createApp } from 'vue';
const app = createApp({});
app.use(install); // 显式调用
在上面的示例中,install 函数被导出,但并未在模块加载时自动执行。只有当开发者在 main.js 中显式调用 app.use(install) 时,全局注册才会发生。如果开发者没有使用这个插件,打包工具会直接忽略整个 plugin.js 文件,从而实现按需加载。
package.json 中的 sideEffects 配置
为了进一步优化 Tree Shaking 效果,需要在 package.json 中明确声明哪些文件包含副作用。如果整个包都没有副作用,可以设置 "sideEffects": false。如果有特定文件(如样式文件或全局脚本)包含副作用,则应列出这些文件的路径。这告诉打包工具可以放心地删除其他未引用的模块,即使它们看起来有潜在影响。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










