专栏名称: 前端外刊评论
最新、最前沿的前端资讯,最有深入、最干前端相关的技术译文。
目录
相关文章推荐
商务河北  ·  经开区“美•强•优”三重奏 ·  13 小时前  
前端早读课  ·  【第3453期】圈复杂度在转转前端质量体系中的应用 ·  23 小时前  
51好读  ›  专栏  ›  前端外刊评论

Webpack 中的 sideEffects 到底该怎么用?

前端外刊评论  · 公众号  · 前端  · 2018-07-25 06:30

正文

@kuitos,伪前端伪架构师 / mobxjs team member,原教旨主义,强迫症唯标准论,偏 MIT Approach 设计哲学,web 开发者。

webpack v4 开始新增了一个 sideEffects 特性,通过给 package . json 加入 sideEffects 声明该 包/模块 是否包含 sideEffects(副作用),从而可以为 tree-shaking 提供更大的优化空间。

先看张图感受一下:

https://twitter.com/jdalton/status/893109185264500737

注:v4 beta 版时叫 pure module , 后来改成了 sideEffects

基于我们对 side effect 的常规理解,我们可以认为,只要我们确定当前包里的模块不包含副作用,然后将发布到 npm 里的包标注为 sideEffects : false ,我们就能为使用方提供更好的打包体验。原理是 webpack 能将标记为 side-effects-free 的包由 import { a } from xx 转换为 import { a } from 'xx/a' ,从而自动修剪掉不必要的 import,作用同 babel-plugin-import。

于是很愉快的我给我的几个库都加上了这个配置(确定都不含副作用)。

直到我几个月前看到

@Sean Larkin

给 vue 提交了这样一个 pr:chore(package.json): Add sideEffects: false field in package.json, 当时我就有点疑惑,依我对 vue 的了解,代码里的副作用挺多啊,比如很多函数都有对 Vue . prototype 的引用甚至修改,应该不能设置 sideEffects : false 才对啊。然而事实是我被打脸了,因为尤大很快的合并了这个 pr。。这直接导致我不敢给 mobx 加上这个配置,因为已经完全不明白 webpack 的这个 sideEffects 指的是什么了。。

直到前两天有人给 mobx-utils 提了 issue 说可以加上这个配置帮助 tree shaking,疑惑中我想起了 vue 的那个 pr 又翻出来看了一下,发现在 pr 下已经有人跟我提了一样的疑问:

Hy Sean! Could you please specify what you mean by "vue's original source files"? I looked at the index.js file in the src/core folder and to my knowledge there are plenty sideeffects that would be prune away by tree shaking. (e.g Object.defineProperty) I hope you can help me understand how this works.

Sean 原来的 pr 里是这样写的:

This PR adds the "sideEffects" : false property in vue's package . json file. This allow's webpack (for those who want to opt-in to requiring vue's original source files (instead of the flattened esm bundles) and want to remove flow type through a babel-transform, then this will allow webpack to aggressively ignore and treeshake unused exports throughout the module system.

Sean 的意思是当你选择性引入 vue 的源码文件而不是打包的 bundle 时,webpack 能帮助你做更好的 tree shaking。比如你这样引用 vue 中的模块: import Vue from 'vue/src/core'

Sean 又说此副作用非彼副作用(fp 中的),然后给了一个他在 stackoverflow 上的回答来解释 webpack 里的这个 sideEffects,中心思想是:

whenever a module reexports all exports (regardless if used or unused) need to be evaluated and executed in the case that one of those exports created a side-effect with another. 每当一个模块重导出了所有导出(无论是否会被用) 需要被计算和执行时,其中一个导出就对其他的导出产生了副作用。

老实讲还是没懂。。有兴趣的看原答案:what-does-webpack-4-expect-from-a-package-with-sideeffects-false

翻完 官方文档 跟 官方 example,只是了解到有了 sideEffects 后 bundle 的变化,依然无法解释 webpack sideEffects 跟 fp 中的 sideEffect 有什么区别,进而也无法解释为什么 vue 明明很多副作用依然能配置 sideEffects : false ?

毛主席教导我们:自力更生,丰衣足食。

Tree Shaking 与副作用

Tree Shaking 的背景就不介绍了想必很多人都了解,webpack 的 tree shaking 的作用是可以将未被使用的 exported member 标记为 unused 同时在将其 re-export 的模块中不再 export。说起来很拗口,看代码:

  1. // a.js

  2. export function a() {}

  3. // b.js

  4. export function b(){}

  5. // package/index.js

  6. import a from './a'

  7. import b from './b'

  8. export { a, b }

  9. // app.js

  10. import {a} from 'package'

  11. console.log(a)

当我们以 app.js 为 entry 时,经过摇树后的代码会变成这样:

  1. // a.js

  2. export function a() {}

  3. // b.js 不再导出 function b(){}

  4. function b() {}

  5. // package/index.js 不再导出 b 模块

  6. import a from './a'

  7. import b from './b'

  8. export { a }

  9. // app.js

  10. import {a} from 'package'

  11. console.log(a )

配合 webpack 的 scope hoisting 和 uglify 之后,b 模块的痕迹会被完全抹杀掉。

但是如果 b 模块中添加了一些副作用,比如一个简单的 log:

  1. // b.js

  2. export function b(v) { reutrn v }

  3. console.log(b(1))

webpack 之后会发现 b 模块内容变成了:

  1. // b.js

  2. console.log(function (v){return v}(1))

虽然 b 模块的导出是被忽略了,但是副作用代码被保留下来了。由于目前 transformer 转换后可能引入的各种奇怪操作引发的副作用(参考:你的Tree-Shaking并没什么卵用),很多时候我们会发现就算有了 tree shaking 我们的 bundle size 还是没有明显的减小。而通常我们期望的是 b 模块既然不被使用了,其中所有的代码应该不被引入才对。

这个时候 sideEffects 的作用就显现出来了:如果我们引入的 包/模块 被标记为 sideEffects : false 了,那么不管它是否真的有副作用,只要它没有被引用到,整个 模块/包 都会被完整的移除。以 mobx-react-devtool为例,我们通常这样去用:

  1. import DevTools from 'mobx-react-devtools';

  2. class MyApp extends React.Component {

  3.  render() {

  4.    







请到「今天看啥」查看全文