认识sideEffects与tree-shaking 12

avatar

引子

前段时间开发UI组件库,目的之一为了替代掉NutUI,减小微信小程序主包体积。初版完成后,尝试接入小程序,猛然发现包体积不减反增,主包没有用到的组件也全部打入了主包中。研究后发现在package.json中加入一行sideEffects的配置,就能解决问题,效果拔群。那什么是sideEffects

sideEffects

sideEffects是一个package.json中的一个字段,用于告诉打包工具哪些模块文件是有副作用的。在JavaScript中,副作用指的是执行某个操作时,除了返回值之外,还会对程序状态产生影响的行为。例如,修改全局变量、进行网络请求、写入文件系统等。

package.json中,sideEffects可以是一个布尔值或一个数组。具体配置如下:

  1. 布尔值:
    • false:表示整个项目中的所有模块都没有副作用,可以安全地进行 tree-shaking。
    • true:表示项目中有部分模块有副作用,需要手动指定哪些模块有副作用。
  1. 数组:
    • 列出有副作用的模块文件路径。例如:
{
  "sideEffects": ["./src/some-side-effectful-file.js"]
}

tree-shaking

tree-shaking是一种优化技术,用于消除未使用的代码,从而减小最终打包文件的体积。它主要依赖于ES6模块的静态结构特性。当打包工具进行构建时,会分析模块的导入和导出关系,识别出哪些代码是未被引用的,并将其从最终的打包文件中移除。

感兴趣可以进一步阅读webpack官方文档中有关tree-shaking的部分【webpack.js.org/guides/tree…】。

sideEffects与tree-shaking的关系

在100%ES6模块世界中,识别副作用非常简单。但是,我们还没有做到这一点,所以我们有必要向打包工具提供有关代码“纯度”的提示。因此,sideEffects标识符对于tree-shaking至关重要。如果一个模块被标记为有副作用,打包工具就不会对其进行tree-shaking,即使该模块中的某些部分未被使用。这是因为这些副作用可能会导致程序行为的变化,删除它们可能会引发错误。

例如,假设你有一个模块utils.js,其中包含一些辅助函数和一些副作用代码:

console.log('This is a side effect');

export function add(a, b) {
  return a + b;
}

如果你在package.json中将utils.js标记为有副作用:

{
  "sideEffects": ["./src/utils.js"]
}

那么即使你在项目中只使用了add函数,console.log语句也会被保留,因为它是有副作用的。

实践案例

回到我的组件库开发过程中,我最初没有考虑sideEffects的问题,导致所有组件都被打包进了主包中。通过在package.json中添加sideEffects配置,我指定了哪些文件是有副作用的,从而让Webpack能够更准确地进行tree-shaking,实现按需编译。

总结

sideEffectstree-shaking是现代前端开发中非常重要的优化手段。通过合理配置sideEffects,我们可以帮助打包工具更准确地识别和移除未使用的代码,从而显著减小最终打包文件的体积,提升应用的性能。希望本文能帮助你更好地理解和应用这些技术。