前端打包构建工具
大约 3 分钟
前端打包构建工具
- 出现原因
- 现代前端不再写一个大文件,而是拆成大量
JS/TS模块 - 而部分新标准和扩展语法可能有浏览器不支持,需要转义
- 生产环境需要压缩代码,去除无用的代码
- 现代前端不再写一个大文件,而是拆成大量
- 前端打包构建工具可以帮助解决以上问题,用于打包、转义、压缩代码
Tree Shaking
- Tree Shaking是指在编译或打包时,通过分析模块之间的依赖关系,确定哪些代码是实际被使用的,然后将那些未被引用、无用的代码自动剔除("摇掉"),使最终输出的代码更精简,它允许开发人员仅打包出用到的代码,从而减少代码体积
- 要求:
- 使用
ES Modules导入导出 - 打包工具有静态分析能力,对
Tree Shaking有支持,即能够解析ES模块依赖,根据使用情况删除未使用的导入,输出优化后的代码
- 使用
- 打包内容的规则
- 未使用和导出的函数不会打包
- 未使用的文件不会被打包
- 使用到的文件的全局操作会被保留
- 模块导出的函数和变量会被保留
- 被导出函数调用的函数会被保留
- 要求:
实现
- ES Modules 的优势
- Tree shaking 依赖于 ES6 模块的静态结构,因为 ES Modules 在编译时就能明确确定每个导入和导出的关系
相比之下,CommonJS 模块依赖运行时确定,难以进行静态分析
- 例如,当你使用 ES Modules 的具名导出时,打包工具能精确地检测到哪些导出的函数或变量被实际引用了,从而剔除未使用的部分
- Tree shaking 依赖于 ES6 模块的静态结构,因为 ES Modules 在编译时就能明确确定每个导入和导出的关系
- 打包工具的优化
- 工具如 Webpack、Rollup 或 Vite 会在打包时对代码进行静态分析,然后进行所谓的"dead-code elimination"(死代码消除)
- 只要你的代码没有产生副作用(side effects),打包工具就能更安全地将其移除,从而优化最终的包体积
- 书写要求:使用 ES Modules(import/export)书写代码,而不是 CommonJS;模块内部文件无副作用。如果某个模块中存在全局副作用代码,这些内容会被导入,可能会影响 tree shaking 的效果
副作用是指模块在引入时会自动执行一些会影响外部环境或产生可观察行为的代码
常见副作用示例:
// 顶层变量初始化 let obj = {} const db = new DB() // 有引入立即执行的全局操作 (function(){ ... })() // 创建立即执行函数 fetch('/api/data') console.log('plugin loaded') window.addEventListener('resize', onResize)解决方法:避免在顶层执行有副作用的代码,将它们封装在函数或不同文件中
// 非所有函数共用的变量懒初始化 let obj export function f1() { // 需要使用之前在函数中初始化 if(!obj) obj = {} // 正常函数操作 } // 通过文件或函数分离不是都需要的全局操作 // 将需要相同全局操作的模块放入一个单独的文件 // 或在文件中将顶层操作放入单独的函数中,延迟执行可以在 package.json 中通过 "sideEffects": false 告诉打包工具该模块没有副作用,或 "sideEffects": ["init.js"] 告诉打包工具该模块中的 init.js 文件有副作用
不在模块顶层产生可观察行为、将所有副作用包装在函数或显式调用中,打包器就能安心地 Tree Shake 未使用代码
