javascript Webpack 4 对带有 sideEffects 的包有什么期望:false
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/49160752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What Does Webpack 4 Expect From A Package With sideEffects: false
提问by Undistraction
Webpack 4 has added a new feature: it now supports a sideEffectsflag in the package.jsonof the modules it is bundling.
Webpack 4 添加了一个新功能:它现在支持它所捆绑模块的sideEffects标志package.json。
From Webpack 4: released today
Over the past 30 days we have worked closely with each of the frameworks to ensure that they are ready to support webpack 4 in their respective cli's etc. Even popular library's like lodash-es, RxJS are supporting the sideEffects flag, so by using their latest version you will see instant bundle size decreases out of the box.
在过去的 30 天里,我们与每个框架密切合作,以确保它们准备好在各自的 cli 等中支持 webpack 4。即使是流行的库,如 lodash-es、RxJS 也支持 sideEffects 标志,因此通过使用他们最新的版本,您将看到即时捆绑包大小开箱即用。
From Webpack docs
The "sideEffects": false flag in big-module's package.json indicates that the package's modules have no side effects (on evaluation) and only expose exports. This allows tools like webpack to optimize re-exports.
big-module 的 package.json 中的 "sideEffects": false 标志表示包的模块没有副作用(在评估时)并且只公开导出。这允许像 webpack 这样的工具优化重新导出。
Whilst the second link shows the results of using the flag, it doesn't clearly explain what constitutes a side-effect. ES6 includes the concept of side-effects for modules as outlined here, but how does this relate to what Webpack considers side-effects.
虽然第二个链接显示了使用该标志的结果,但它并没有清楚地解释什么构成了副作用。ES6 包括这里概述的模块副作用的概念,但这与 Webpack 考虑的副作用有什么关系。
In the context of the sideEffectsflag, what does a module need to avoid to use sideEffects:falsewithout issues, or conversly, what does a module need to do in order to use sideEffects:falsewithout issues.
在sideEffects标志的上下文中,模块需要避免使用什么sideEffects:false而没有问题,或者相反,模块需要做什么才能正常使用sideEffects:false。
For completeness, despite @SeanLarkin's solid answer below, I would love to get clarification on the following:
为了完整起见,尽管@SeanLarkin 在下面给出了可靠的答案,但我很想澄清以下内容:
Obviously side-effects means something particular in fp and would include logging (console or elsewhere) and the throwing of errors. I'm assuming in this context these are perfectly acceptable?
Can a module contain circular references and still use
sideEffects: false?Is there any way to verify or that a module is able to verify that a module can
sideEffects: falsebeyond trying to track down errors caused by its misuse?Are there any other factors that would prevent a module from being able to use
sideEffects: false?
显然,副作用在 fp 中意味着某些特定的东西,包括日志记录(控制台或其他地方)和抛出错误。我假设在这种情况下这些是完全可以接受的?
模块可以包含循环引用并仍然使用
sideEffects: false吗?sideEffects: false除了试图追踪由其误用引起的错误之外,是否有任何方法可以验证或模块能够验证模块是否可以?是否还有其他因素会阻止模块使用
sideEffects: false?
回答by Sean Larkin
Sean from the webpack Team! I'll do my best in lieu of our documentation still in progress to answer your question here!
来自 webpack 团队的 Sean!我会尽我所能代替我们仍在进行中的文档来回答您的问题!
According to the ECMA Module Spec (I'm not going to try and find the link so you'll have to trust me here because its buried),
根据 ECMA 模块规范(我不会尝试找到链接,因此您必须在这里信任我,因为它已被掩埋),
whenever a module re-exportsall exports, (regardless if used or unused) they need to be evaluated and executed in case one of those exports created a side-effect with another.
每当模块重新导出所有导出时(无论是否使用或未使用),都需要评估和执行它们,以防其中一个导出与另一个导出产生副作用。
For example I've created a small scenario with a photo to better visualize the case:
例如,我创建了一个带有照片的小场景以更好地可视化案例:
In this photo we see three modules imported into a single file. The imported modules are then re-exportedfrom that module:
在这张照片中,我们看到三个模块导入到一个文件中。然后从该模块重新导出导入的模块:
You can see here that none of the re-exports are effected by eachother, therefore (if webpack was given a signal), we could omit exports band cfrom even being traced or used (size and build time performance benefits).
你可以在这里看到,没有任何重新导出是相互影响的,因此(如果给 webpack 一个信号),我们可以省略导出b,c甚至被跟踪或使用(大小和构建时间性能优势)。
However in this case, we see that exports cis "effected" by local state changes because it is reassigned to the summation of band a. Therefore, (which is why the spec calls for this), we would need to include both band aand any of its dependencies into the bundle.
然而,在这种情况下,我们看到出口c被“影响”,由当地国家的变化,因为它被重新分配给的总和b及a。因此,(这就是规范要求这样做的原因),我们需要将b和a及其任何依赖项都包含到包中。
We chose "sideEffects: false" as a way to save on both compile time and build size because this allows us to instantly prune (explicitly) exports that developers/library authors know are side-effect free (at the expense of a property in a package.json, or 2-3 more lines of config).
我们选择“sideEffects: false”作为一种节省编译时间和构建大小的方法,因为这使我们能够立即修剪(明确地)开发人员/库作者知道没有副作用的导出(以牺牲一个属性为代价) package.json,或多 2-3 行配置)。
Although technically this example is very primitive, when you start dealing with Frameworks or Libraries that reexport a bunch of modules up to a higher level for Developer Experience (Three.js, Angular, lodash-es, etc), then performance gains are significant when (if they are sideEffect free module exports) you flag them in this manner.
尽管从技术上讲,这个示例非常原始,但是当您开始处理将一堆模块重新导出到更高级别以获得开发人员体验(Three.js、Angular、lodash-es 等)的框架或库时,当(如果它们是无副作用的模块导出)您以这种方式标记它们。
Additional Clarifications:
附加说明:
- Obviously side-effects means something particular in fp and would include logging (console or elsewhere) and the throwing of errors. I'm assuming in this context these are perfectly acceptable?
- 显然,副作用在 fp 中意味着某些特定的东西,包括日志记录(控制台或其他地方)和抛出错误。我假设在这种情况下这些是完全可以接受的?
In the case that this is trying to solve, yes. As long as effects created against module exports aren't effected by others that would cause pruning to not be acceptable.
在这试图解决的情况下,是的。只要针对模块导出创建的效果不受其他会导致修剪不可接受的影响。
- Can a module contain circular references and still use
sideEffects: false?
- 模块是否可以包含循环引用并仍然使用
sideEffects: false?
It should, in theory.
理论上应该。
- Is there any way to verify or that a module is able to use
sideEffects: falsebeyond trying to track down errors caused by its misuse?
sideEffects: false除了试图追踪由其误用引起的错误之外,还有什么方法可以验证或模块能够使用吗?
Not that I know of, however this would be a great tool.
不是我所知道的,但这将是一个很好的工具。
- Are there any other factors that would prevent a module from being able to use
sideEffects: false?
- 是否还有其他因素会阻止模块使用
sideEffects: false?
If the property is not in package.jsonor defined in module.rules, or mode: productionis not set (which leverages the optimization).
如果该属性不在 中package.json或在中定义module.rules,或未mode: production设置(利用优化)。
回答by catamphetamine
This sideEffectssetting is very vague and is not described sufficiently in the docs. The docs are mostly like "there's a sideEffectsflag for modules free of any side effects".
这个sideEffects设置非常模糊,文档中没有充分描述。文档大多类似于“没有sideEffects任何副作用的模块有一个标志”。
The consensus is that "has no sideEffects" phrase can be decyphered as "doesn't talk to things external to the module at the top level".
共识是“没有副作用”短语可以解密为“不与顶层模块外部的事物交谈”。
My current understanding is that this sideEffectsflag is only for "re-exports", a "re-export" being:
我目前的理解是这个sideEffects标志仅用于“再出口”,“再出口”是:
export { a } from './lib/a'
export { b } from './lib/b'
somewhere in <npm-package>/index.js(or any other file inside the <npm-package>).
中的某处<npm-package>/index.js(或 中的任何其他文件<npm-package>)。
If Webpack detects that the application only imports afrom <npm-package>, and doesn't import banywhere, then Webpack can simply drop the export { b } from './lib/b'line from <npm-package>/index.jsresulting in not including
'./lib/b.js'file in the resulting bundle (which makes it smaller by the size of './lib/b.js'file).
如果的WebPack检测应用程序只进口a的<npm-package>,并没有导入b任何地方,然后可以的WebPack简单地丢弃export { b } from './lib/b'从线<npm-package>/index.js导致不包括
'./lib/b.js'在生成的包文件(这使得它的尺寸更小的'./lib/b.js'文件)。
Now, if './lib/b.js'had some top-level lines of code doing some "side effects", i.e. if './lib/b.js'did something like:
现在,如果'./lib/b.js'有一些顶级代码行做了一些“副作用”,即如果'./lib/b.js'做了类似的事情:
window.jQuery = ...if (!global.Set) global.Set = require('babel-polyfill').Setnew XmlHttpRequest().post('/analytics', data)
window.jQuery = ...if (!global.Set) global.Set = require('babel-polyfill').Setnew XmlHttpRequest().post('/analytics', data)
then './lib/b.js'would be said to have "side effects" because its top-level code (which gets executed upon import './lib/b') affects something outside the scope of the './lib/b.js'file.
then'./lib/b.js'将被称为具有“副作用”,因为其顶级代码(在 上执行import './lib/b')影响'./lib/b.js'文件范围之外的某些内容。
At the same time, as long as './lib/b.js'top-level code doesn't reach outside that *.jsfile then it's not having any "side effects":
同时,只要'./lib/b.js'顶级代码没有到达该*.js文件之外,那么它就没有任何“副作用”:
let a = 1
a = a + 1 + computeSomeValue()
export default a
export const b = a + 1
export const c = b + 1
these are all not "side effects".
这些都不是“副作用”。
And there's a final gotcha: if an npm package has any *.cssfiles that a user can importthen these *.cssfiles are all "side effects", because:
还有一个最后的问题:如果 npm 包有任何*.css用户可以使用的文件,import那么这些*.css文件都是“副作用”,因为:
import 'npm-package/style.css'
has no variable assigned to this importwhich effectively means "this imported module is not used anywhere in the application" for Webpack. And so Webpack simply discards the 'npm-package/style.css'file from the bundle as part of the "tree-shaking" process if the npm-packagehas sideEffects: falseflag. So, instead of writing sideEffects: falsealways write "sideEffects": ["*.css"]. Even if your npm package doesn't export any CSS files it might do so in some future and this will guard against the aforementioned "CSS file not included" bug.
没有分配给import它的变量,这实际上意味着 Webpack 的“此导入的模块未在应用程序中的任何地方使用”。因此,'npm-package/style.css'如果npm-package有sideEffects: false标志,作为“摇树”过程的一部分,Webpack 只是简单地从包中丢弃文件。所以,不要写sideEffects: false总是写"sideEffects": ["*.css"]。即使您的 npm 包不导出任何 CSS 文件,它也可能在将来这样做,这将防止上述“未包含 CSS 文件”错误。


