摘要:使用允許使用多線程進行構建來提升構建的速度。在中,有大量的文件,稱為動態鏈接庫。文檔里面還有一句話是這樣說的動態鏈接庫提供了將應用模塊化的方式,應用的功能可以在此基礎上更容易被復用。
本文原文發表在:https://medium.com/@Erichain/...
本文采用的 Webpack 版本為 2.0+
本文源代碼地址:https://github.com/Erichain/w...
如果你問我對 Webpack 什么印象的話,我只能告訴你,慢,真的慢。即使他的配置如文檔所說(當然,它的文檔也不是那么好)很簡單,不像 Grunt 或者 Gulp 那樣需要一堆配置,只需那么幾十行就能夠配置一個構建系統,我依然覺得,這個構建工具很慢。或許,是從它的文檔開始,我就印象不好了?OK,這個話題到此為止,我們開始我們的正題吧。
本篇文章面向的不是 Webpack 新手,如果你對 Webpack 還不太熟悉的話,建議去閱讀它的官方文檔。當然,我們肯定也會涉及到一些基礎的東西。
本文重點講解對生產環境的構建的性能的提升,如果需要對本地構建的性能進行提升的話,可以在本文結束之后,自己尋找一下解決方案哦。當然,還有一點需要說明的是,本文中的代碼在本地不一定真正能夠在瀏覽器中運行,有需要的可以自行搭建本地的構建系統。
一點基礎使用過 Webpack 的朋友肯定知道,Webpack 的最簡單的配置如下:
module.exports = { entry: { app: "./src/app.js" }, output: { path: path.join(__dirname, "dist-[hash]"), filename: "[name].[hash].js" } };
這樣的配置會將我們的文件打包成為一個 app.[hash].js 文件。這樣針對的一般是我們的項目不算大的情況,并且公用模塊比較少的情況(當然,公用模塊較多的話,配置肯定也不會這么簡單了)。
對于項目中有用到預處理器,ES2015+ 或者其余的需要編譯后在瀏覽器上運行的語言,我們需要做的就是為這些東西添加上對應的 loader,然后,Webpack 就會自動的幫我們進行處理了(老實說,這一步還是挺方便的)。
一些 loader 配置示例如下:
rules: [ { test: /.jsx?$/, loader: ["babel-loader?presets[]=react,presets[]=latest&compact=false"], }, { test: /.scss$/, loader: [ "style-loader", "css-loader", "postcss-loader", "sass-loader" ], }, { test: /.jpe?g|png|svg|gif/, loader: ["url-loader?limit=8192&name=assets/images/[name]-[hash].[ext]"], } ]
另外,我們還可以通過一些插件來更多的定義 Webpack 的打包行為。比如,如果我們有很多第三方庫的引用,并且,多個地方都會引用到這些庫,我們就可以使用 Webpack 的 CommonsChunkPlugin 來將這些公用的代碼打包成一個文件(當然,至于速度嘛,我們后面再說),然后,將我們頁面的業務代碼打包成為一個文件。
Webpack 的主要配置就這幾項,其他更多的更深入的配置可以查看 Webpack 的官方文檔。
速度慢盡管 Webpack 配置起來很方便,但是,按照一般的配置來的話,構建的速度真的是太慢了,每構建一次都會花掉相當長的時間,這對于開發者們來說簡直是噩夢。
可是,速度為什么會這么慢呢?
以我所在的項目為例,由于我們的項目存在多個 entries(大概四十多個),所以,我們的 Webpack 采用的配置是將公用的第三方庫通過 CommonsChunkPlugin 來打包成為一個 common.js。
根據這個 common.js 的內容來看,這里面存放的就是各個 entry 引用的公有的代碼,比如,我們的很多組件都會用到 React 或者 Redux 這些第三方庫。通過將公有的代碼多帶帶打包成一個文件,然后再將業務代碼打包成一個文件,這樣一來,業務代碼模塊本身的體積就會減小很多,頁面的加載速度也能夠得到很大的提升。
雖然這樣打包的方式能夠在一定程度上提升頁面的加載速度,但是,我們簡單的想一想也知道,CommonsChunkPlugin 會去將所有 entry 中的公有模塊遍歷出來再進行編譯壓縮混淆,這個過程是非常緩慢的(我們的項目以前在使用這種方式的時候,在這一步會花上至少十二分鐘的時間,你可以想象這個過程有多么漫長)。
經過了幾個迭代的痛苦的打包上線的過程之后,我們終于不能忍了,決定對這個構建系統進行改造。
改造的過程說實話,一開始我其實是沒有任何頭緒的,我只知道這個構建的過程慢,但是,并不清楚應該從何處開始進行改造。
與同事們進行了一些商討之后,我準備從以下幾個方面入手:
減少構建的文件,減小文件大小:我們的項目中存在太多的無用的文件和代碼,我決定先刪除這些無用的東西
移除 CommonsChunkPlugin
Search with Google
第一步的作用其實并不明顯,我刪除了很大一部分的無用的圖片和代碼,但是,構建速度并沒有明顯的提升。
第二步,簡單的移除掉 CommonsChunkPlugin 的話,構建速度確實會快很多,但是,這樣打包出來的項目就不能夠運行了,所以,還需要結合第三步(必須要感謝這個世界存在 Google)。
我在網上找到了許多相關的問題,關鍵性的建議有以下幾個:
將 css-loader 的版本回溯到 0.15 及其以前的版本
使用 HappyPack
使用 DllPlugin
首先,第一點,降低 css-loader 的版本。
在 GitHub 上有這樣一個 issue:0.15.0+ makes Webpack load slowly。按照 issue 中大家的討論,我將我們項目中的 css-loader 的版本降到了 0.14.5。滿懷期待的以為這樣就能夠提升一部分速度,但是,結果是令人失望的——構建的速度并沒有明顯的改變。我試著構建了好幾遍,速度依然沒有提升,所以,第一個方法失敗,我將 css-loader 的版本恢復了回來。
那么,繼續嘗試第二個方法,也是本文將要重點說明的方法之一,那就是使用 HappyPack。
使用 HappyPackHappyPack 允許 Webpack 使用 Node 多線程進行構建來提升構建的速度。
使用的方法與在 Webpack 中定義 loader 的方法類似,只是說,我們把構建需要的 loader 放到了 HappyPack 中,讓 HappyPack 來為我們進行相應的操作,我們只需要在 Webpack 的配置中引入 HappyPack 的 loader 的配置就好了。
比如,我們編譯 .jsx 文件的 loader 就可以這樣寫:
new HappyPack({ id: "jsx", threads: 4, loaders: ["babel-loader?presets[]=react,presets[]=latest&compact=false"], })
其中,threads 指明 HappyPack 使用多少子進程來進行編譯,一般設置為 4 為最佳。
編譯 .scss 文件的 loader 這樣寫:
new HappyPack({ id: "scss", threads: 4, loaders: [ "style-loader", "css-loader", "postcss-loader", "sass-loader", ], })
其中,需要注意的一點就是,在使用 HappyPack 的情況下,我們需要多帶帶創建一個 postcss.config.js 文件,不然,在編譯的時候,就會報錯。
由于 HappyPack 對 url-loader 和 file-loader 的支持度的問題,所以,我們此處,打包圖片文件的時候,并沒有使用 HappyPack。
postcss.config.js 的配置就像下面這樣(根據你的需求,定制你自己的配置):
module.exports = { autoprefixer: { browsers: ["last 3 versions"], } };
定義好了我們 HappyPack 的 loader 之后,我們直接在我們的 Webpack 的配置的 plugins 一項中,引入就好了。
那么,我們在編譯的時候,就會看到下面的輸出:
這就是 HappyPack 在編譯的時候的輸出內容。
但是,我們的關注點不是它輸出了什么,而是說,我們的構建速度有沒有提升。
當然,結果是令人失望的,我們多帶帶使用 HappyPack 的情況下,構建速度并沒有明顯的提升(當然,或許有所提升但是我沒有發現也有可能)。
所以,為了進一步的提升我們的構建速度,我們將采取第三種方案,那就是 DllPlugin。
使用 DllPlugin仔細閱讀過 Webpack 文檔的朋友肯定對這個插件會有印象,或者說知道這個插件是干嘛用的。其實,我們此處也是基于 Webpack 的文檔的一些說明,然后,結合我在項目中的實踐來為大家講解這個插件。
在 Webpack 中,DllPlugin 并不是多帶帶的使用的,而是需要與一個名為 DllReferencePlugin 的插件結合起來使用的。
熟悉 Windows 的朋友就應該知道,DLL 所代表的含義。在 Windows 中,有大量的 .dll 文件,稱為動態鏈接庫。
在 MSDN 上,微軟是這樣解釋動態鏈接庫的:
A dynamic-link library (DLL) is a module that contains functions and data that can be used by another module (application or DLL).
大概的意思就是說,動態鏈接庫包含的是,可以在其他模塊中進行調用的函數和數據。
文檔里面還有一句話是這樣說的:
DLLs provide a way to modularize applications so that their functionality can be updated and reused more easily.
動態鏈接庫提供了將應用模塊化的方式,應用的功能可以在此基礎上更容易被復用。
回到我們的項目中,類似的,我們其實要做的也是將各個模塊中公用的部分給打包成為一個公用的模塊。這個模塊就包含了我們的其他模塊中需要的函數和數據(比如,其他組件所需的 React 庫)。
使用 DllPlugin 的時候,會生成一個 manifest.json 這個文件,所存儲的就是各個模塊和所需公用模塊的對應關系。
說了這么多,我們不如直接來看看這個插件到底是怎么使用的:
首先,我們需要一個文件,這個文件包含所有的第三方或者公用的模塊和庫,我們在此將其命名為 vendor.js,文件的內容如下:
import "react"; import "react-dom";
由于我們的示例項目中只用到了這兩個公用的第三方庫,所以,我們此處只需要引入這兩個庫就行了。
在打包的時候,我們將這些公用的模塊多帶帶打包成一個文件,然后,通過生成的 manifest.json 文件對應過去。所以,我們需要多帶帶創建一個 webpack.config.vendor.js。
文件內容其實很簡單:
const webpack = require("webpack"); const path = require("path"); module.exports = { entry: { vendor: [path.join(__dirname, "src", "vendor.js")], }, output: { path: path.join(__dirname, "dist-[hash]"), filename: "[name].js", library: "[name]", }, plugins: [ new webpack.DllPlugin({ path: path.join(__dirname, "dll", "[name]-manifest.json"), filename: "[name].js", name: "[name]", }), ] };
可以看到,我們主要的操作是在 plugins 配置中,生成的文件名就是我們所定義的 entry 的名稱,JSON 文件名可以根據自己的需要來命名。像上面這樣,我們就可以將我們的一些公用模塊打包出來了。
運行以下命令:
webpack -p --progress --config webpack.config.vendor.js
我們就可以看到這樣的輸出:
這樣,我們就完成了構建的第一步。下一步,我們需要在構建應用的配置文件中,加入我們的 DllPlugin 的配置。
這時候,我們就需要用到 DllReferencePlugin 了。
在我們的主要配置文件中,加入以下的配置:
const manifest = require("./dll/vendor-manifest.json"); // ... 其他完美的配置 plugins: [ new webpack.DllReferencePlugin({ manifest, }), ],
就這樣,我們的所有工作就完成了,我們只需要運行一條命令,就能夠看到構建速度的巨大提升。
當然,為了更完美,我們可以將 DllPlugin 和 HappyPack 結合起來使用,效果會更好。具體的代碼細節,此處不予展示,朋友們可以直接去 GitHub 上查看。
為了方便構建,我們可以寫一個腳本將構建過程簡單化。在我的 GitHub 項目里面有相關的腳本,包含了一些基礎的操作,有需要的朋友可以去查看。此處,我們就認為我們的命令可以直接構建了。
為了體現出構建速度的區別,我們先運行 npm run build,這是采用普通方式進行構建的命令。
可以看到,構建時間為 20353ms,換算下來為 20s 左右。
接下來,我們運行 npm run build dll,通過 DllPlugin 和 HappyPack 進行構建。
我們將兩個時間加起來,總共為 12184ms,換算下來為 12s 左右。快了將近一倍的時間!這還只是文件少的情況。在我們的實際項目中,構建時間提升了 3 倍多,所以,可以看到 DllPlugin 的強大之處。
一點總結本文只是尋找了這樣幾種能夠提升構建速度的解決方案,我相信,方法肯定不止這些,一定還有更多的解決方案等待我們去發現。所以,希望各位朋友能夠對本文中不足的地方提出建議,希望與大家共同學習,共同進步。
ReferencesOPTIMIZING WEBPACK FOR FASTER REACT BUILDS
Optimizing Webpack build times and improving caching with DLL bundles
Dynamic-Link Libraries
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83831.html
摘要:但是,隨者工程開發的復雜程度和代碼規模不斷地增加,暴露出來的各種性能問題也愈發明顯,極大的影響著開發過程中的體驗。對應的資源也可以直接由頁面外鏈載入,有效地減小了資源包的體積。 背景 如今前端工程化的概念早已經深入人心,選擇一款合適的編譯和資源管理工具已經成為了所有前端工程中的標配,而在諸多的構建工具中,webpack以其豐富的功能和靈活的配置而深受業內吹捧,逐步取代了grunt和gu...
摘要:是對的轉譯結果進行緩存,之后的進行構建時,都會去嘗試讀取緩存來避免高耗能的重新轉譯過程,可以指定一個緩存目錄或者指定為,為時將使用默認的緩存目錄。這篇文章如果有錯誤或不嚴謹的地方,歡迎批評指正,如果喜歡,歡迎點贊收藏 由于前端的快速發展,相關工具的發展速度也是相當迅猛,各大框架例如vue,react都有自己優秀的腳手架工具來幫助我們快速啟動一個新項目,也正式因為這個原因,我們對于腳手架...
摘要:小組最近在二次開發一個開源項目,前端主要使用的技術棧試。所以需要對作出如下的改動。原文件變動后至此,我們大部分的優化的內容已經完成,下面是我們打包時間的一個對比。 webpack是當下前端界中最著名的一個模塊加載工具,react和vue也都是用其作為項目的開發工具之一。小組最近在二次開發一個開源項目,前端主要使用的技術棧試react+redux+es6。構建工具則采用的是webpack...
摘要:使用要給項目構建接入動態鏈接庫的思想,需要完成以下事情把網頁依賴的基礎模塊抽離出來,打包到一個個單獨的動態鏈接庫中去。接入已經內置了對動態鏈接庫的支持,需要通過個內置的插件接入,它們分別是插件用于打包出一個個單獨的動態鏈接庫文件。 webpack優化 查看所有文檔頁面:全棧開發,獲取更多信息。原文鏈接:webpack優化,原文廣告模態框遮擋,閱讀體驗不好,所以整理成本文,方便查找。 ...
摘要:使用打包的基本上都是獨立庫文件,這類文件有一個特性就是變化不大。修改往添加一個配置只針對的模塊化有效配置文件詳情請點擊 基于vue-cli優化的webpack配置 大概分為以下幾點 通過 externals 配置來提取常用庫,引用外鏈 配置CommonsChunkPlugin提取公用代碼 (vue-cli已做) 善用alias(vue-cli配置了一部分) 啟用DllPlugin和D...
閱讀 2770·2021-11-17 09:33
閱讀 3092·2021-10-25 09:44
閱讀 1200·2021-10-11 10:59
閱讀 2396·2021-09-27 13:34
閱讀 2905·2021-09-07 10:19
閱讀 2133·2019-08-29 18:46
閱讀 1535·2019-08-29 12:55
閱讀 928·2019-08-23 17:11