Webpack 4 对带有副作用的包的期望是什么:false
What Does Webpack 4 Expect From A Package With sideEffects: false
Webpack 4 添加了一项新功能:它现在支持在其捆绑的模块的 package.json
中使用 sideEffects
标志。
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.
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.
虽然第二个 link 显示了使用标志的结果,但它没有清楚地解释什么构成了副作用。 ES6 包括概述的模块副作用的概念 ,但这与 Webpack 考虑的副作用有何关系。
在 sideEffects
标志的上下文中,模块需要避免什么才能毫无问题地使用 sideEffects:false
,或者相反,模块需要做什么才能使用 sideEffects:false
没有问题。
为了完整起见,尽管@SeanLarkin 在下面给出了可靠的回答,但我很想澄清以下内容:
显然,副作用意味着 fp 中的某些特定内容,包括日志记录(控制台或其他地方)和错误抛出。我假设在这种情况下这些是完全可以接受的?
模块是否可以包含循环引用并仍然使用 sideEffects: false
?
是否有任何方法可以验证或模块能够验证模块是否可以 sideEffects: false
除了试图追踪其误用导致的错误?
是否有任何其他因素会阻止模块能够使用 sideEffects: false
?
webpack 团队的 Sean!我会尽我所能代替我们仍在进行中的文档来回答您的问题!
根据 ECMA 模块规范(我不会尝试找到 link 所以你必须相信我,因为它被埋没了),
每当模块 re-exports 所有导出时,(无论是否使用)它们都需要被评估和执行,以防其中一个导出创建 side-effect 和另一个。
例如,我用照片创建了一个小场景,以更好地形象化案例:
在这张照片中,我们看到三个模块被导入到一个文件中。然后导入的模块 re-exported 来自该模块:
你可以在这里看到 re-exports 的 none 是相互影响的,因此(如果给 webpack 一个信号),我们可以省略 exports b
和 c
甚至被跟踪或使用(大小和构建时间性能优势)。
但是在这种情况下,我们看到导出 c
受到局部状态变化的“影响”,因为它被重新分配给 b
和 a
的总和。因此,(这就是规范要求这样做的原因),我们需要将 b
和 a
及其任何依赖项都包含在包中。
我们选择“sideEffects: false”作为节省编译时间和构建大小的方法,因为这使我们能够立即(明确地)修剪 developers/library 作者知道 side-effect 免费的导出(以 package.json 中的 属性 或多 2-3 行配置为代价)。
虽然从技术上讲这个例子非常原始,但是当你开始处理框架或库时 re-export 一堆模块达到更高级别的开发人员体验(Three.js,Angular, lodash-es, 等等),那么当您以这种方式标记它们时(如果它们是无副作用的模块导出),性能提升是显着的。
补充说明:
- 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 use
sideEffects: false
beyond 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
?
如果 属性 不在 package.json
中或在 module.rules
中定义,或者 mode: production
未设置(利用优化)。
此 sideEffects
设置非常模糊,文档中没有充分描述。文档大多像 "there's a sideEffects
flag for modules free of any side effects".
共识是"has no sideEffects"短语可以解密为"doesn't talk to things external to the module at the top level"。
我目前的理解是,这个 sideEffects
标志仅适用于 "re-exports",一个 "re-export" 是:
export { a } from './lib/a'
export { b } from './lib/b'
<npm-package>/index.js
中的某处(或 <npm-package>
中的任何其他文件)。
如果 Webpack 检测到应用程序只从 <npm-package>
导入 a
,而没有在任何地方导入 b
,那么 Webpack 可以简单地从中删除 export { b } from './lib/b'
行<npm-package>/index.js
导致不包括
'./lib/b.js'
文件在生成的包中(这使得它比 './lib/b.js'
文件小)。
现在,如果 './lib/b.js'
有一些 top-level 行代码做一些 "side effects",即如果 './lib/b.js'
做了类似的事情:
window.jQuery = ...
if (!global.Set) global.Set = require('babel-polyfill').Set
new XmlHttpRequest().post('/analytics', data)
然后 './lib/b.js'
会被认为有 "side effects" 因为它的 top-level 代码(在 import './lib/b'
上执行)影响 [=23 范围之外的东西=] 文件.
同时,只要 './lib/b.js'
top-level 代码没有到达 *.js
文件之外,那么它就没有任何 "side effects":
let a = 1
a = a + 1 + computeSomeValue()
export default a
export const b = a + 1
export const c = b + 1
这些都不是"side effects"。
还有最后一个陷阱:如果 npm 包有任何 *.css
用户可以 import
的文件,那么这些 *.css
文件都是 "side effects",因为:
import 'npm-package/style.css'
没有分配给这个 import
的变量,这实际上意味着 Webpack 的 "this imported module is not used anywhere in the application"。因此,如果 npm-package
具有 sideEffects: false
标志,Webpack 会简单地从包中丢弃 'npm-package/style.css'
文件作为 "tree-shaking" 过程的一部分。所以,不要写 sideEffects: false
,而是写 "sideEffects": ["*.css"]
。即使您的 npm 包不导出任何 CSS 文件,它也可能在将来导出,这将防止上述 "CSS file not included" 错误。
Webpack 4 添加了一项新功能:它现在支持在其捆绑的模块的 package.json
中使用 sideEffects
标志。
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.
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.
虽然第二个 link 显示了使用标志的结果,但它没有清楚地解释什么构成了副作用。 ES6 包括概述的模块副作用的概念
在 sideEffects
标志的上下文中,模块需要避免什么才能毫无问题地使用 sideEffects:false
,或者相反,模块需要做什么才能使用 sideEffects:false
没有问题。
为了完整起见,尽管@SeanLarkin 在下面给出了可靠的回答,但我很想澄清以下内容:
显然,副作用意味着 fp 中的某些特定内容,包括日志记录(控制台或其他地方)和错误抛出。我假设在这种情况下这些是完全可以接受的?
模块是否可以包含循环引用并仍然使用
sideEffects: false
?是否有任何方法可以验证或模块能够验证模块是否可以
sideEffects: false
除了试图追踪其误用导致的错误?是否有任何其他因素会阻止模块能够使用
sideEffects: false
?
webpack 团队的 Sean!我会尽我所能代替我们仍在进行中的文档来回答您的问题!
根据 ECMA 模块规范(我不会尝试找到 link 所以你必须相信我,因为它被埋没了),
每当模块 re-exports 所有导出时,(无论是否使用)它们都需要被评估和执行,以防其中一个导出创建 side-effect 和另一个。
例如,我用照片创建了一个小场景,以更好地形象化案例:
在这张照片中,我们看到三个模块被导入到一个文件中。然后导入的模块 re-exported 来自该模块:
你可以在这里看到 re-exports 的 none 是相互影响的,因此(如果给 webpack 一个信号),我们可以省略 exports b
和 c
甚至被跟踪或使用(大小和构建时间性能优势)。
但是在这种情况下,我们看到导出 c
受到局部状态变化的“影响”,因为它被重新分配给 b
和 a
的总和。因此,(这就是规范要求这样做的原因),我们需要将 b
和 a
及其任何依赖项都包含在包中。
我们选择“sideEffects: false”作为节省编译时间和构建大小的方法,因为这使我们能够立即(明确地)修剪 developers/library 作者知道 side-effect 免费的导出(以 package.json 中的 属性 或多 2-3 行配置为代价)。
虽然从技术上讲这个例子非常原始,但是当你开始处理框架或库时 re-export 一堆模块达到更高级别的开发人员体验(Three.js,Angular, lodash-es, 等等),那么当您以这种方式标记它们时(如果它们是无副作用的模块导出),性能提升是显着的。
补充说明:
- 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 use
sideEffects: false
beyond 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
?
如果 属性 不在 package.json
中或在 module.rules
中定义,或者 mode: production
未设置(利用优化)。
此 sideEffects
设置非常模糊,文档中没有充分描述。文档大多像 "there's a sideEffects
flag for modules free of any side effects".
共识是"has no sideEffects"短语可以解密为"doesn't talk to things external to the module at the top level"。
我目前的理解是,这个 sideEffects
标志仅适用于 "re-exports",一个 "re-export" 是:
export { a } from './lib/a'
export { b } from './lib/b'
<npm-package>/index.js
中的某处(或 <npm-package>
中的任何其他文件)。
如果 Webpack 检测到应用程序只从 <npm-package>
导入 a
,而没有在任何地方导入 b
,那么 Webpack 可以简单地从中删除 export { b } from './lib/b'
行<npm-package>/index.js
导致不包括
'./lib/b.js'
文件在生成的包中(这使得它比 './lib/b.js'
文件小)。
现在,如果 './lib/b.js'
有一些 top-level 行代码做一些 "side effects",即如果 './lib/b.js'
做了类似的事情:
window.jQuery = ...
if (!global.Set) global.Set = require('babel-polyfill').Set
new XmlHttpRequest().post('/analytics', data)
然后 './lib/b.js'
会被认为有 "side effects" 因为它的 top-level 代码(在 import './lib/b'
上执行)影响 [=23 范围之外的东西=] 文件.
同时,只要 './lib/b.js'
top-level 代码没有到达 *.js
文件之外,那么它就没有任何 "side effects":
let a = 1
a = a + 1 + computeSomeValue()
export default a
export const b = a + 1
export const c = b + 1
这些都不是"side effects"。
还有最后一个陷阱:如果 npm 包有任何 *.css
用户可以 import
的文件,那么这些 *.css
文件都是 "side effects",因为:
import 'npm-package/style.css'
没有分配给这个 import
的变量,这实际上意味着 Webpack 的 "this imported module is not used anywhere in the application"。因此,如果 npm-package
具有 sideEffects: false
标志,Webpack 会简单地从包中丢弃 'npm-package/style.css'
文件作为 "tree-shaking" 过程的一部分。所以,不要写 sideEffects: false
,而是写 "sideEffects": ["*.css"]
。即使您的 npm 包不导出任何 CSS 文件,它也可能在将来导出,这将防止上述 "CSS file not included" 错误。