[英]What Does Webpack 4 Expect From A Package With sideEffects: false
Webpack 4 添加了一個新功能:它現在支持在它捆綁的模塊的package.json
中的sideEffects
標志。
在過去的 30 天里,我們與每個框架密切合作,以確保它們准備好在各自的 cli 等中支持 webpack 4。即使是流行的庫,如 lodash-es、RxJS 也支持 sideEffects 標志,因此通過使用他們最新的版本,您將看到即時捆綁包大小開箱即用。
big-module 的 package.json 中的 "sideEffects": false 標志表示包的模塊沒有副作用(在評估時)並且只公開導出。 這允許像 webpack 這樣的工具優化重新導出。
雖然第二個鏈接顯示了使用該標志的結果,但它並沒有清楚地解釋什么構成了副作用。 ES6 包括此處概述的模塊副作用的概念,但這與 Webpack 考慮的副作用有何關系。
在sideEffects
標志的上下文中,模塊需要避免什么才能使用sideEffects:false
沒有問題,或者相反,模塊需要做什么才能使用sideEffects:false
沒有問題。
為了完整起見,盡管@SeanLarkin 在下面給出了可靠的答案,但我很想澄清以下內容:
顯然,副作用在 fp 中意味着某些特定的東西,包括日志記錄(控制台或其他地方)和拋出錯誤。 我假設在這種情況下這些是完全可以接受的?
模塊可以包含循環引用並仍然使用sideEffects: false
嗎?
是否有任何方法可以驗證或模塊能夠驗證模塊是否可以sideEffects: false
除了試圖追蹤由其誤用引起的錯誤?
是否還有其他因素會阻止模塊使用sideEffects: false
?
來自 webpack 團隊的 Sean! 我會盡我所能代替我們仍在進行中的文檔來回答您的問題!
根據 ECMA 模塊規范(我不會嘗試找到鏈接,因此您必須在這里信任我,因為它已被掩埋),
每當模塊重新導出所有導出時(無論是否使用或未使用),都需要對它們進行評估和執行,以防其中一個導出與另一個導出產生副作用。
例如,我創建了一個帶有照片的小場景以更好地可視化案例:
在這張照片中,我們看到三個模塊導入到一個文件中。 然后從該模塊重新導出導入的模塊:
您可以在這里看到,沒有任何重新導出相互影響,因此(如果給 webpack 一個信號),我們甚至可以省略導出b
和c
跟蹤或使用(大小和構建時間性能優勢)。
然而,在這種情況下,我們看到出口c
受本地狀態變化的“影響”,因為它被重新分配給b
和a
的總和。 因此,(這就是規范要求這樣做的原因),我們需要將b
和a
及其任何依賴項都包含到包中。
我們選擇“sideEffects: false”作為一種節省編譯時間和構建大小的方法,因為這使我們能夠立即修剪(明確地)開發人員/庫作者知道沒有副作用的導出(以犧牲一個屬性為代價) package.json,或多 2-3 行配置)。
盡管從技術上講,這個示例非常原始,但是當您開始處理將一堆模塊重新導出到更高級別以獲得開發人員體驗(Three.js、Angular、lodash-es 等)的框架或庫時,性能提升是當(如果它們是無副作用的模塊導出)您以這種方式標記它們時很重要。
附加說明:
- 顯然,副作用在 fp 中意味着某些特定的東西,包括日志記錄(控制台或其他地方)和拋出錯誤。 我假設在這種情況下這些是完全可以接受的?
在這試圖解決的情況下,是的。 只要針對模塊導出創建的效果不受其他會導致修剪不可接受的影響。
- 模塊可以包含循環引用並仍然使用
sideEffects: false?
理論上應該。
- 有沒有辦法驗證或模塊能夠使用
sideEffects: false
除了試圖追蹤由其誤用引起的錯誤?
不是我所知道的,但這將是一個很好的工具。
- 是否還有其他因素會阻止模塊使用
sideEffects: false
?
如果該屬性不在package.json
或在module.rules
定義,或者mode: production
未設置(利用優化)。
這個sideEffects
設置非常模糊,文檔中沒有充分描述。 文檔大多類似於“沒有任何副作用的模塊有一個sideEffects
標志”。
共識是“沒有副作用”短語可以解密為“不與頂層模塊外部的事物交談”。
我目前的理解是,這個sideEffects
標志僅用於“再出口”,“再出口”是:
export { a } from './lib/a'
export { b } from './lib/b'
某處<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'
文件。
同時,只要'./lib/b.js'
頂級代碼沒有到達*.js
文件之外,那么它就沒有任何“副作用”:
let a = 1
a = a + 1 + computeSomeValue()
export default a
export const b = a + 1
export const c = b + 1
這些都不是“副作用”。
還有一個最后的問題:如果 npm 包有任何用戶可以import
*.css
文件,那么這些*.css
文件都是“副作用”,因為:
import 'npm-package/style.css'
沒有分配給此import
變量,這實際上意味着 Webpack 的“此導入的模塊未在應用程序中的任何地方使用”。 因此,如果npm-package
具有sideEffects: false
標志,作為“搖樹”過程的一部分,Webpack 會簡單地從'npm-package/style.css'
丟棄'npm-package/style.css'
文件。 所以,不要寫sideEffects: false
總是寫"sideEffects": ["*.css"]
。 即使您的 npm 包不導出任何 CSS 文件,它也可能在將來這樣做,這將防止上述“未包含 CSS 文件”錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.