Webpack 4对包含sideEffects的包的期望是什么:false

Und*_*ion 35 javascript side-effects bundler webpack package.json

Webpack 4增加了一项新功能:它现在支持捆绑的模块中的sideEffects标志package.json.

来自Webpack 4:今天发布

在过去的30天里,我们与每个框架密切合作,以确保他们已准备好在各自的cli等支持webpack 4.即使像lodash-es这样的流行库,RxJS也支持sideEffects标志,所以通过使用他们的最新版本版本,您将看到即时捆绑尺寸减少开箱即用.

来自Webpack文档

"sideEffects":big-module的package.json中的false标志表示包的模块没有副作用(评估时)并且只暴露导出.这允许像webpack这样的工具优化再出口.

虽然第二个链接显示了使用该标志的结果,但它没有清楚地解释什么构成副作用.ES6包含了此处概述的模块副作用的概念,但这与Webpack考虑的副作用有何关系.

sideEffects标志的上下文中,模块需要避免在sideEffects:false没有问题的情况下使用什么,或者对话,模块需要做什么才能sideEffects:false无问题地使用.

为了完整起见,尽管@ SeanLarkin在下面给出了可靠的答案,但我想对以下内容进行澄清:

  1. 显然,副作用意味着fp特有的东西,包括日志记录(控制台或其他地方)和抛出错误.我假设在这种情况下这些是完全可以接受的吗?

  2. 模块是否可以包含循环引用并仍然使用sideEffects: false

  3. 有没有办法验证或模块是否能够验证模块是否可以sideEffects: false超越试图追踪由其误用造成的错误?

  4. 是否还有其他因素会妨碍模块的使用sideEffects: false

Sea*_*kin 57

来自webpack团队的肖恩!我会尽力代替我们仍在进行中的文档来回答您的问题!

根据ECMA模块规范(我不打算尝试找到链接所以你必须在这里相信我,因为它被埋没了),

每当一个模块再出口(如果无论使用或不使用的)中的所有出口需要进行评估,并在这些出口中的一个创建与另一个副作用的情况下执行.

例如,我创建了一个带有照片的小方案,以更好地可视化案例:

在这张照片中我们可以看到,3个独立模块与单个导入,导入到一个单独的模块,然后采用这些默认出口,重导出该模块的他们:

Reexported模块没有副作用的示例

你可以在这里看到,没有一个reexport会受到彼此影响,因此(如果给webpack一个信号),我们可以省略导出b,c甚至可以跟踪或使用(大小和构建时间性能优势).

在此输入图像描述

然而,在这种情况下,我们看到出口c被"影响",由当地国家的变化,因为它被重新分配给的总和ba.因此,(这就是为什么该规范要求这一点),我们需要两者都包括ba及其任何依赖的成捆.

我们选择"sideEffects:false"作为节省编译时间和构建大小的方法,因为这允许我们立即修剪(显式)开发人员/库作者知道的副作用是免费的(以牺牲属性为代价) package.json,或2-3行配置).

虽然从技术上讲这个例子非常原始,但是当你开始处理Frameworks或Libraries,它们为开发者体验(Three.js,Angular,lodash-es等)重新出口一堆模块时,那么性能提升是显着的. (如果它们是sideEffect free module exports)你以这种方式标记它们.

其他说明:

  1. 显然,副作用意味着fp特有的东西,包括日志记录(控制台或其他地方)和抛出错误.我假设在这种情况下这些是完全可以接受的吗?

在这是试图解决的情况下,是的.只要对模块出口产生的影响不受其他会导致修剪不可接受的影响.

  1. 模块是否可以包含循环引用并仍然可以使用 sideEffects: false?

理论上应该这样.

  1. 有没有办法验证或模块能够使用sideEffects: false除了试图追踪由其误用造成的错误?

不是我所知道的,但这将是一个很好的工具.

  1. 是否还有其他因素会妨碍模块的使用sideEffects: false

如果属性未在package.json或未定义module.rules,或未mode: production设置(利用优化).

  • 谢谢。我已将其作为附录添加到您的答案中,以便于发现。 (2认同)
  • 只需在配置文件中设置`mode:none`设置webpack,就可以看到我们制作的注释,显示我们正在跟踪的内容.我们利用其中一些. (2认同)

asd*_*ads 10

sideEffects设置非常模糊,在文档中没有充分描述.文档大多是"有一个sideEffects没有任何副作用的模块的标志".

大家一致认为,"没有副作用"的短语可以被解除为"不与顶层模块外部的事物交谈".

我目前的理解是,这个sideEffects标志仅用于"再出口","再出口"是:

export { a } from './lib/a'
export { b } from './lib/b'
Run Code Online (Sandbox Code Playgroud)

在某处<npm-package>/index.js(或其中的任何其他文件<npm-package>).

如果的WebPack检测应用程序只导入a<npm-package>,并没有导入b任何地方,然后可以的WebPack简单地丢弃export { b } from './lib/b'从线<npm-package>/index.js导致不包括 './lib/b.js'在生成的包文件(这使得它的尺寸更小的'./lib/b.js'文件).

现在,如果'./lib/b.js'有一些顶级代码行做一些"副作用",即如果'./lib/b.js'做了类似的事情:

  • window.jQuery = ...
  • if (!global.Set) global.Set = require('babel-polyfill').Set
  • new XmlHttpRequest().post('/analytics', data)

然后'./lib/b.js'会说它有"副作用",因为它的顶级代码(执行时import './lib/b')会影响'./lib/b.js'文件范围之外的内容.

同时,只要'./lib/b.js'顶级代码没有到达该*.js文件之外,它就没有任何"副作用":

let a = 1
a = a + 1 + computeSomeValue()
export default a
export const b = a + 1
export const c = b + 1
Run Code Online (Sandbox Code Playgroud)

这些都不是"副作用".

还有最后的问题:如果一个npm包有任何*.css文件,用户可以import这些*.css文件都是"副作用",因为:

import 'npm-package/style.css'
Run Code Online (Sandbox Code Playgroud)

没有分配给import它的变量,这实际上意味着"这个导入的模块不会在应用程序的任何地方使用"用于Webpack.因此,'npm-package/style.css'如果npm-packagesideEffects: false标志,Webpack只会丢弃捆绑中的文件作为"树摇动"过程的一部分.所以,而不是写sideEffects: false总是写"sideEffects": ["*.css"].即使你的npm软件包没有导出任何CSS文件,它也可能会在将来发布,这样可以防止上述"CSS文件未包含"错误.