《Webpack實戰:入門、進階與調優》讀書筆記


概述

這幾天我讀了 Webpack實戰:入門、進階與調優,感覺收獲挺大的,把讀書筆記發出來,供以后開發時參考,相信對其他人也有用。

我的書單

讀書筆記

1.CommonJS 與 ES6 Module 最本質的區別在於前者對模塊依賴的解決是“動態”的,而后者是“靜態”的。動態的含義是:模塊依賴關系的建立發生在代碼運行階段;而靜態則是模塊依賴關系的建立發生在代碼編譯階段。所以 ES6 Module 具有以下幾點優勢:1.死代碼檢測和排除。2.模塊變量類型檢查。3.編譯器優化。

2.在導入一個模塊時,對於 CommonJS 來說獲取的是一份導出值得拷貝,而在 ES6 Module 中則是值的動態映射,並且這個映射是只讀的。

3.在 CommonJS 中,若遇到循環依賴我們沒有辦法得到預想中的結果;但是在 ES6 Module 中,我們只需要保證當導入的值被使用時已經設置好正確的導出值,就可以支持循環依賴。

4.每個 npm 模塊都有一個入口。當我們加載一個模塊時,實際上就是加載該模塊的入口文件。這個入口被維護在模塊內部 package.json 文件的 main 字段中。

5.webpack 的 context 字段表示的是基本目錄,可以理解為資源入口的路徑前綴,在配置時要求必須使用絕對路徑的形式。默認使用當前目錄。

6.為了解決打包體積過大的問題,我們可以使用提取 vendor 的方法。vendor 的意思是“供應商”,在 webpack 中 vendor 一般指的是工程所使用的的庫、框架等第三方模塊集中打包而產生的 bundle。

7.在多入口的場景中,我們需要為對應產生的每個 bundle 指定不同的名字,webpack 支持使用一種類似模板語言的形式動態地生成文件名。除了[name]可以指代 chunk name 以外,還有其它幾種模板變量可以用於 filename 的配置中。

8.在 webpack4 以前的版本中,打包資源默認會生成在工程根目錄,因此我們需要上述配置;而在 webpack4 之后,output.path 已經默認為 dist 目錄,除非我們需要更改它,否則不必單獨配置。

9.loader 里面的 test、exclude、include 本質上屬於對 resource 也就是被加載者的配置,如果想要對 issuer 加載者也增加條件限制,則要額外寫一些配置。

10.webpack 中的 loader 按照執行順序可分為 pre、inline、normal、post 四種類型,上面我們直接定義的 loader 都屬於 normal 類型,inline 形式官方已經不推薦使用,而 pre 和 post 則需要使用 enforce 來指定。enforce 的值為 pre,代表它將在所有正常 loader 之前執行,這樣可以保證其檢測的代碼不是被其它 loader 更改過的。而 post 表示在所有 loader 之后執行。

11.對於 babel-loader 本身我們添加了 cacheDirectory 配置項,它會啟用緩存機制,在重復打包未改變過的模塊時防止二次編譯,同樣也會加快打包的速度。cacheDirectory 可以接收一個字符串類型的路徑來作為緩存路徑,這個值也可以為 true,此時緩存目錄會指向 node_modules/.cache/babel-loader。

12.由於 @babel/preset-env 會將 es6 module 轉化為 commonjs 的形式,這會導致 webpack 中的 tree-shaking 特性失效。將 @babel/preset-env 的 modules 配置項設置為 false 會禁用模塊語句的轉化,而將 es6 module 的語法交給 webpack 本身處理。

13.url-loader 與 file-loader 作用類似,唯一的不同在於用戶可以設置一個文件大小的閾值,當大於該閾值時與 file-loader 一樣返回 publicPath,而小於該閾值時返回文件 base64 形式編碼。

14.在寫自定義 loader 的時候,可以使用 this.sync 獲取 callback 函數。callback 函數的3個參數分別是拋出的錯誤、處理后的源碼,以及 source-map。

15.css-loader 在把 css 打包之后,在運行的時候會將其插入到 style 標簽中,但是在生產環境下,我們希望樣式存在於 css 文件中,這樣更有利於客戶端緩存。而 mini-css-extract-plugin 就是專門用於提取樣式到 css 文件的。而說到 mini-css-extract-plugin 的特性,最重要的就是它支持按需加載 css。

16.Sass 本身是對 css 的語法增強,它有兩種語法,現在使用更多的是 scss。所以你會發現,在安裝和配置 loader 時都是 sass-loader,而實際的文件后綴是 .scss。

17.loader 本身只是編譯核心庫與 webpack 的連接器,因此這里我們除了 sass-loader 以外還要安裝 node-sass,node-sass是真正用來編譯 scss 的,而 sass-loader 只是起到黏合的作用。值得一提的是,加入我們想要在瀏覽器的調試工具里查看源碼,需要分別為 sass-loader 和 css-loader 單獨添加 source map 的配置項。

18.解決 node-sass 下載較慢的方法是為其單獨設置一個 cnpm 的鏡像地址,可使用如下命令:npm config set sass_binary_site=https://npm.taobao.org/mirrors/node-sass/

19.嚴格來說,postcss-loader 不能算是一個 css 預編譯器,它只是一個編譯插件的容器,它的工作模式是接收樣式源代碼並交由編譯插件處理,最后輸出 css。

20.我們可以在 autoprefixer 中添加需要支持的特性(如grid)以及兼容哪些瀏覽器(browsers)。

21.postcss 可以與 cssnext 結合使用,讓我們在應用中使用最新的css語法特性。

22.使用 css modules 時 css 文件會導出一個對象,我們需要把這個對象中的屬性添加到 html 標簽上。

23.代碼分片可以有效降低首屏加載資源的大小,但同時也會帶來新的問題,比如我們應該對哪些模塊進行分片、分片后的資源如何管理等,這些也是需要關注的。

24.有些時候我們不希望所有的公共模塊都被提取出來,比如項目中一些組件或工具模塊,雖然被多次引用,但是可能經常修改,如果將其和 react 這種庫放在一些反而不利於客戶端緩存。這個時候可以把 minChunks 配置項的值調大一點來解決。

25.minChunks 設置為 Infinity 的意義有兩個,第一個是我們只想讓 webpack 提取 vendor 字段寫的幾個模塊,讓提取更加可控;另一個是能夠生成一個僅僅包含 webpack 初始化環境的文件,稱為 manifest 文件。manifest 文件其實就是各個 chunk 的打包地圖,以前可以用它來有效解決打包的時候 verdor 包的 chunId 變化的問題。

26.webpack runtime 指的是初始化環境的代碼,如創建模塊緩存對象、聲明模塊加載函數等。

27.CommonChunkPlugin 的不足:1.一個 CommonChunkPlugin 只能提取一個 verdor;2.會多加載一個 manifest 文件;3.會破壞掉原有 chunk 中模塊的依賴關系,導致難以進行更多的優化。而 webpack4 里面的 optimization.SplitChunks 就是為了改進 CommonChunkPlugin 而重新設計和實現的代碼分片特性,是 webpack 的內置模塊,可以直接使用。

28.資源異步加載主要解決的問題是,當模塊數量過多、資源體積過大時,可以把一些暫時使用不到的模塊延遲加載。這樣使頁面初次渲染的時候用戶下載的資源盡可能小,后續的模塊等到恰當的時機再去觸發加載,因此一般也把這種方法叫做按需加載。

29.與正常 es6 的 import 語法不通,通過 import 函數加載的模塊及其依賴會被異步地進行加載,並返回一個 Promise 對象。

30.首屏加載的 js 地址是通過頁面中的 script 標簽來指定的,而間接資源(通過首屏 JS 再進一步加載的 JS)的位置則要通過 output.publicPath 來指定。

31.動態加載的 js 會插入到頁面的 head 標簽,並有一個 async 屬性。

32.在生產環境中我們關注的是如何讓用戶更快地加載資源,涉及如何壓縮資源、如何添加環境變量優化打包、如何最大限度地利用緩存等。

33.在 DefiinePlugin 中我們需要在值得外面加上 JSON.stringify。

34.如果對打包速度需求比較高的話,建議使用一個簡化版的 source map。比如,在開發環境中,cheap-module-eval-source-map 通常是一個不錯的選擇,屬於打包速度和源碼信息還原程度的一個良好折中。

35.webpack 提供了 hidden-source-map 及 nosources-source-map 兩種策略來提升 source map 的安全性。前者會產出完整的 map 文件,只不過不會在 bundle 文件中添加對於 map 文件的引用。如果我們要追溯源碼,則要利用一些第三方服務,將 map 文件上傳到那上面。目前最流行的解決方案是 sentry。后者的安全性沒那么強,打包之后能在 source 選項卡中看到源碼的目錄結構,但是文件的具體內容會被隱藏起來。

36.對於生產環境的 source map 我們還有另外一種選擇,就是使用 nginx 將 .map 文件只對固定的白名單(比如公司內網)開放。

37.壓縮 js 的工具是 terser,它在 webpack4 里面是內置模塊,可以直接使用。它相比 uglifyjs 的有點事支持 es6+ 代碼的壓縮。

38.壓縮 css 文件的前提是使用 exract-text-plugin 或 mini-css-extract-plugin 將樣式提取出來,接着使用 optimize-css-assets-webpack-plugin 來進行壓縮,這個插件本質上使用的是壓縮器 cssnano。

39.資源名的改變也就意味着 html 中的引用路勁的改變。每次更改后都要手動去維護它是很困難的,理想的情況是在打包結束后自動把最新的資源名同步過去。使用 html-webpack-plugin 可以幫我們做到這一點。

40.bundlesize 這個工具包可以幫助我們自動化地對資源體積進行監控。

41.開發環境中我們可能關注的是打包速度,而在生產環境中我們關注的則是輸出的資源體積以及如何優化客戶端緩存來縮短頁面渲染時間。

42.webpack 是單線程的,假設一個模塊依賴於幾個其它模塊,webpack 必須對這些模塊逐個進行轉譯。雖然這些轉譯任務彼此之間沒有任何依賴關系,卻必須串行地執行。HappyPack 恰恰以此為切入點,它的核心特性是可以開啟多個線程,並行地對不同模塊進行轉譯,這樣就可以充分利用本地的計算資源來提升打包速度。

43.從宏觀角度來看,提升性能的方法無非兩種:增加資源或者縮小范圍。增加資源指的是使用更多CPU和內存,用更多的計算能力來縮短執行任務的時間;縮小范圍則是針對任務本身,比如去掉冗余的流程,盡量不做重復性的工作等。

44.有些庫我們是希望 webpack 完全不要去進行解析的,即不希望應用任何 loader 規則,庫的內部也不會有對其他模塊的依賴,那么這時可以使用 noParse 對其進行忽略。

45.exclude 和 include 是確定 loader 的規則范圍,noParse 是不去解析但仍會打包到 bundle 中。最后讓我們再看一個插件 IgnorePlugin,它可以完全排除一些模塊,被排除的模塊即使被引用了也不會被打包進資源文件中。

46.webpack 的 tree shaking 功能可以在打包過程中幫助我們檢測工程中沒有被引用過的模塊,這部分代碼將永遠無法被執行到,因此也被稱為“死代碼”。webpack 會對這部分代碼進行標記,並在資源壓縮時將它們從最終的 bundle 中去掉。tree shaking只是為死代碼添加上標記,真正去除死代碼是通過壓縮工具來進行的。比如說 terser-webpack-plugin(它已經內置在 webpack4 里面了)

47.即使我們的項目本身僅僅有一行代碼,webpack 也需要將自身代碼注入進去(大概50行左右)。顯然 rollup 的產出更符合我們的預期,不包含無關代碼,資源體積更小。

48.在進行技術選型的時候,我們不僅要結合目前工具的一些特性,也要看其未來的發展路線圖。如果其能在后續保持良好的社區生態及維護狀況,對於項目今后的發展也是非常有利的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM