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