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