摘要:原文鏈接開始新增了一個(gè)特性,通過給加入聲明該包模塊是否包含副作用,從而可以為提供更大的優(yōu)化空間。而通常我們期望的是模塊既然不被使用了,其中所有的代碼應(yīng)該不被引入才對(duì)。但當(dāng)我們加上之后,就能安全的把它從里完整的移除掉了。
原文鏈接
webpack v4 開始新增了一個(gè) sideEffects 特性,通過給 package.json 加入 sideEffects: false 聲明該包模塊是否包含 sideEffects(副作用),從而可以為 tree-shaking 提供更大的優(yōu)化空間。
先看張圖感受一下:
注:v4 beta 版時(shí)叫 pure module, 后來改成了 sideEffects
基于我們對(duì) fp 中的 side effect 的理解,我們可以認(rèn)為,只要我們確定當(dāng)前包里的模塊不包含副作用,然后將發(fā)布到 npm 里的包標(biāo)注為 sideEffects: false ,我們就能為使用方提供更好的打包體驗(yàn)。原理是 webpack 能將標(biāo)記為 side-effects-free 的包由 import {a} from xx 轉(zhuǎn)換為 import {a} from "xx/a",從而自動(dòng)修剪掉不必要的 import,作用同 babel-plugin-import。
于是很愉快的我給我的幾個(gè)庫(kù)都加上了這個(gè)配置(確定都不含副作用)。
直到我?guī)讉€(gè)月前看到 @Sean Larkin 給 vue 提交了這樣一個(gè) pr:chore(package.json): Add sideEffects: false field in package.json, 當(dāng)時(shí)我就有點(diǎn)疑惑,依我對(duì) vue 的了解,代碼里的副作用挺多啊,比如很多函數(shù)都有對(duì) Vue.prototype 的引用甚至修改,應(yīng)該不能設(shè)置 sideEffects: false 才對(duì)啊。然而事實(shí)是我被打臉了,因?yàn)橛却蠛芸斓暮喜⒘诉@個(gè) pr。。這直接導(dǎo)致我不敢給 mobx 加上這個(gè)配置,因?yàn)橐呀?jīng)完全不明白 webpack 的這個(gè) sideEffects 指的是什么了。。
直到前兩天有人給 mobx-utils 提了 issue 說可以加上這個(gè)配置幫助 tree shaking,疑惑中我想起了 vue 的那個(gè) pr 又翻出來看了一遍,發(fā)現(xiàn)在 pr 下已經(jīng)有人跟我提了一樣的疑問:
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 的意思是當(dāng)你按需引入 vue 的源碼文件而不是打包的 bundle 時(shí),webpack 能幫助你做更好的 tree shaking。比如你這樣引用 vue 中的模塊:import Vue from "vue/src/core" 。
然后 Sean 就說此副作用非彼副作用(fp 中的),然后給了一個(gè)他在 stackoverflow 上的回答來解釋 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.每當(dāng)一個(gè)模塊重導(dǎo)出了所有導(dǎo)出(無論是否會(huì)被用) 需要被計(jì)算和執(zhí)行時(shí),其中一個(gè)導(dǎo)出就對(duì)其他的導(dǎo)出產(chǎn)生了副作用。
老實(shí)講還是沒懂。。有興趣的看原答案:what-does-webpack-4-expect-from-a-package-with-sideeffects-false
翻完 官方文檔 跟 官方 example,只是了解到有了 sideEffects 后 bundle 的變化,依然無法解釋 webpack sideEffects 跟 fp 中的 sideEffect 有什么區(qū)別,進(jìn)而也無法解釋為什么 vue 明明很多副作用依然能配置 sideEffects: false ?
毛主席教導(dǎo)我們:自力更生,豐衣足食。
Tree Shaking 與副作用Tree Shaking 的背景就不介紹了想必很多人都了解,webpack 的 tree shaking 的作用是可以將未被使用的 exported member 標(biāo)記為 unused 同時(shí)在將其 re-export 的模塊中不再 export。說起來很拗口,看代碼:
// a.js export function a() {} // b.js export function b(){} // package/index.js import a from "./a" import b from "./b" export { a, b } // app.js import {a} from "package" console.log(a)
當(dāng)我們已 app.js 為 entry 時(shí),經(jīng)過搖樹后的代碼會(huì)變成這樣:
// a.js export function a() {} // b.js 不再導(dǎo)出 function b(){} function b() {} // package/index.js 不再導(dǎo)出 b 模塊 import a from "./a" import b from "./b" export { a } // app.js import {a} from "package" console.log(a)
配合 webpack 的 scope hoisting 和 uglify 之后,b 模塊的痕跡會(huì)被完全抹殺掉。
但是如果 b 模塊中添加了一些副作用,比如一個(gè)簡(jiǎn)單的 log:
// b.js export function b(v) { reutrn v } console.log(b(1))
webpack 之后會(huì)發(fā)現(xiàn) b 模塊內(nèi)容變成了:
// b.js console.log(function (v){return v}(1))
雖然 b 模塊的導(dǎo)出是被忽略了,但是副作用代碼被保留下來了。由于目前 transformer 轉(zhuǎn)換后可能引入的各種奇怪操作引發(fā)的副作用(參考:你的Tree-Shaking并沒什么卵用),很多時(shí)候我們會(huì)發(fā)現(xiàn)就算有了 tree shaking 我們的 bundle size 還是沒有明顯的減小。而通常我們期望的是 b 模塊既然不被使用了,其中所有的代碼應(yīng)該不被引入才對(duì)。
這個(gè)時(shí)候 sideEffects 的作用就顯現(xiàn)出來了:如果我們引入的 包/模塊 被標(biāo)記為 sideEffects: false 了,那么不管它是否真的有副作用,只要它沒有被引用到,整個(gè) 模塊/包 都會(huì)被完整的移除。以 mobx-react-devtool 為例,我們通常這樣去用:
import DevTools from "mobx-react-devtools"; class MyApp extends React.Component { render() { return (... { process.env.NODE_ENV === "production" ? null :); } }}
這是一個(gè)很常見的按需導(dǎo)入場(chǎng)景,然而在沒有?sideEffects: false?配置時(shí),即便?NODE_ENV?設(shè)為?production?,打包后的代碼里依然會(huì)包含?mobx-react-devtools?包,雖然我們沒使用過其導(dǎo)出成員,但是?mobx-react-devtools?還是會(huì)被 import,因?yàn)槔锩妗翱赡堋睍?huì)有副作用。但當(dāng)我們加上 sideEffects false 之后,tree shaking 就能安全的把它從 bundle 里完整的移除掉了。
sideEffects 的使用場(chǎng)景上面也說到,通常我們發(fā)布到 npm 上的包很難保證其是否包含副作用(可能是代碼的鍋可能是 transformer 的鍋),但是我們基本能確保這個(gè)包是否會(huì)對(duì)包以外的對(duì)象產(chǎn)生影響,比如是否修改了 window 上的屬性,是否復(fù)寫了原生對(duì)象方法等。如果我們能保證這一點(diǎn),其實(shí)我們就能知道整個(gè)包是否能設(shè)置?sideEffects: false了,至于是不是真的有副作用則并不重要,這對(duì)于 webpack 而言都是可以接受的。這也就能解釋為什么能給 vue 這個(gè)本身充滿副作用的包加上 sideEffects: false 了。
所以其實(shí) webpack 里的 sideEffects: false 的意思并不是我這個(gè)模塊真的沒有副作用,而只是為了在搖樹時(shí)告訴 webpack:我這個(gè)包在設(shè)計(jì)的時(shí)候就是期望沒有副作用的,即使他打完包后是有副作用的,webpack 同學(xué)你搖樹時(shí)放心的當(dāng)成無副作用包搖就好啦!。
也就是說,只要你的包不是用來做 polyfill 或 shim 之類的事情,就盡管放心的給他加上 sideEffects: false 吧!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/96250.html
摘要:根據(jù)依賴關(guān)系,按照配置文件把模塊函數(shù)分組打包成若干個(gè)。會(huì)隨著自身的的修改,而發(fā)生變化。只需要在命令行運(yùn)行時(shí)帶上參數(shù)就搞定一些插件的廢除和替換廢棄了頂替者用屬性變化壓縮優(yōu)化代碼分割,下面詳解還有一些新的插件,。 1. 前端工程化項(xiàng)目打包歷史 前端工程化之前的時(shí)代略過 1. 半自動(dòng)執(zhí)行腳本來壓縮合并文件 自從xmlhttprequest被挖掘出來,網(wǎng)頁(yè)能夠和服務(wù)端通訊,js能做的事越來越多...
摘要:根據(jù)依賴關(guān)系,按照配置文件把模塊函數(shù)分組打包成若干個(gè)。會(huì)隨著自身的的修改,而發(fā)生變化。只需要在命令行運(yùn)行時(shí)帶上參數(shù)就搞定一些插件的廢除和替換廢棄了頂替者用屬性變化壓縮優(yōu)化代碼分割,下面詳解還有一些新的插件,。 1. 前端工程化項(xiàng)目打包歷史 前端工程化之前的時(shí)代略過 1. 半自動(dòng)執(zhí)行腳本來壓縮合并文件 自從xmlhttprequest被挖掘出來,網(wǎng)頁(yè)能夠和服務(wù)端通訊,js能做的事越來越多...
摘要:注意使用的版本不同,可能會(huì)導(dǎo)致打包出的結(jié)果不一樣。完整的優(yōu)化代碼見有用的文章分離第三方庫(kù)及公用文件 現(xiàn)在的 web 應(yīng)用,內(nèi)容一般都很豐富,站點(diǎn)需要加載的資源也特別多,尤其要加載很多 js 文件。js 文件從服務(wù)端獲取,體積大小決定了傳輸?shù)目炻?;瀏覽器端拿到 js 文件之后,還需要經(jīng)過解壓縮、解析、編譯、執(zhí)行操作,所以,控制 js 代碼的體積以及按需加載對(duì)前端性能以及用戶體驗(yàn)是十分的重...
摘要:隨著承擔(dān)地職責(zé)越來越大,模塊化開發(fā)的需求越來越急迫。我們可以把當(dāng)成是模塊化標(biāo)準(zhǔn)的實(shí)現(xiàn)方案,但的功能不僅限于此。支持多種模塊使用方式,包括的。下面介紹一下在工程中常用的。最后一個(gè)的輸出就是我們最終要的結(jié)果。在文件有值的情況下,是必要的。 由于web應(yīng)用擴(kuò)展地得極其迅猛,前端技術(shù)也是日新月異,前端的苦不是有多難學(xué),而是我剛學(xué)完,這東西就被淘汰了(手動(dòng)哭臉)??蚣芊矫嫖覀冇衯ue、react...
閱讀 900·2023-04-26 01:37
閱讀 3374·2021-09-02 15:40
閱讀 966·2021-09-01 10:29
閱讀 2898·2019-08-29 17:05
閱讀 3427·2019-08-28 18:02
閱讀 1184·2019-08-28 18:00
閱讀 1493·2019-08-26 11:00
閱讀 2615·2019-08-26 10:27