日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

前端 Webpack 工程化的最佳實(shí)踐

作者 | 阿里文娛前端開發(fā)專家 芃蘇

責(zé)編 | 屠敏

頭圖 | CSDN 下載自視覺中國

 

引言

前端構(gòu)建工具的演變

回想在2015-2016年的時(shí)候,開發(fā)者們開始漸漸把視線從大量使用Task Runner的Grunt工具,轉(zhuǎn)移到Gulp這種Pipeline形式的工具。Gulp還可以配合上眾多個(gè)性化插件(如gulp-streamify),從而使得整個(gè)前端的準(zhǔn)備工作鏈路,變得清晰易控,如刷新頁面、代碼的編譯和壓縮等等。自動(dòng)化“流水線”工具取代了很多繁雜的手動(dòng)工作,可以說,是具有跨時(shí)代意義的。之于Webpack而言,其本質(zhì)是是基于“模塊化”思想的一個(gè)“JS預(yù)編譯”解決方案,誕生初期,和其相似的方案還有Browserify,和Webpack屬于同門不同派別的還有sea.js或require.js,這二者需“在線依賴”解釋器編譯。

時(shí)至今日,多數(shù)日常工作接觸的項(xiàng)目,已經(jīng)可以完全的舍棄Gulp了。但工作中有時(shí)還會(huì)接觸一些老項(xiàng)目,其中Gulp的使用和維護(hù)屢見不鮮。2019年初之時(shí),通過一個(gè)老項(xiàng)目(gulp 3.x + webpack 3.x)的技術(shù)升級,借機(jī)了解了gulp 4.x的動(dòng)態(tài),又不禁讓人回想起gulp-browserify,和gulp-webpack(五年前發(fā)布,目前改名為webpack-stream)。所以,Webpack做為某一個(gè)垂直方向的解決方案,當(dāng)然可以manaually built-in Gulp中。在拿Webpack“方案”和Gulp類“工具”去做正面比較的時(shí)候,需要明晰兩者解決問題的范圍和思路。如今再次回顧歷史,對技術(shù)的發(fā)展演變順序,能有一個(gè)基本客觀的概念。

在2017年的時(shí)候,Gulp和Webpack在用戶的使用率和“將繼續(xù)使用”的意向上,還不分伯仲。但從《State of JAVAscript 2019》 中可以看到,Webpack已經(jīng)完全碾壓了其它工具和類庫,成為了首屈一指被大家廣泛使用、討論的Build Tool。2018年2月25日Webpack 發(fā)布了4.0.0正式版本;那是對不少項(xiàng)目進(jìn)行了Webpack 4.10.2版本的升級;過年前后,又將部分項(xiàng)目升級到了4.29.0 最新版本。這一系列的“跟進(jìn)式升級”中,一方面是在不斷融入Webpack對于模塊構(gòu)建的新思路和理念,為了能夠更好的適應(yīng)其未來的變化(Webpack 5.x的beta版過應(yīng)該不久就會(huì)面世了),另一方面是在一個(gè)好的方案中不斷嘗試,結(jié)合項(xiàng)目的基礎(chǔ)設(shè)施優(yōu)化,從而提高效能,保障產(chǎn)品穩(wěn)定。

? 本次回顧

Webpack工具雖說只是前端項(xiàng)目CI流程的一個(gè)小部分(構(gòu)建 build),就它自身而言,所涉及到的Node知識和包依賴管理經(jīng)驗(yàn),是一整塊技能。細(xì)節(jié)來看,里面涉及了Webpack自己的包和第三方plugin生態(tài),還要配合恰當(dāng)?shù)腷abel、typescript、flow.js、eslint配置等多個(gè)生態(tài),去處理JavaScript語言本身的編譯/轉(zhuǎn)譯。以及,正確管理本地靜態(tài)資源文件和遠(yuǎn)端CDN資源文件路徑(打包配置決定打包結(jié)果),涉及到了跨域知識和Node層服務(wù)配置、模板配置知識。更進(jìn)一步還有,NPM眾多包的版本管理等讓人頭疼的問題。其中瑣碎細(xì)節(jié)數(shù)不勝數(shù),當(dāng)所有第三方工具正確使用的前提下,也許還有些plugin小工具,需要開發(fā)者去自研發(fā)。知識譜系之大,可見一斑。

本文不描述Webpack Docs使用指南,也不描述第三方插件的使用“指北”。更多的是結(jié)合過往項(xiàng)目經(jīng)驗(yàn),記錄實(shí)踐得出的使用技巧,也記錄一些走過的彎路所帶來的問題,希望對其它眾多的前端技術(shù)人能夠起到一點(diǎn)借鑒作用。 (Package Checking List:React: 16.3.2,Babel: 7.0.0,Webpack: 4.29.0,Node: 11.8.0)

 

文件結(jié)構(gòu)

在4.x版本中的早期,CLI工具集里的命令是Webpack主包自帶的,但在Webpack 4.x后期的版本,將webpack-cli作為獨(dú)立包剔除出去,需要手動(dòng)單獨(dú)安裝才可以執(zhí)行tnpm run start這樣的腳本命令。其次,對于開發(fā)/日常環(huán)境(dev)和預(yù)發(fā)/生產(chǎn)環(huán)境(prod)來說,打包的策略是截然不同的:

1. 對于dev日常環(huán)境:

  1. 方便的debug和troubleshootin,有比較強(qiáng)的source mApping;

  2. 希望能夠得到顆粒度較小、且有根據(jù)變動(dòng)代碼針對性的的加載(live reloading/hot module replacement);

  3. 希望可以做一些代理Proxy相關(guān)的調(diào)試;

  4. 可以方便的根據(jù)開發(fā)者的情況,對本地的dev-server進(jìn)行配置等。

2. 對于Prod生產(chǎn)環(huán)境:

  1. 通過壓縮Javscript/css代碼,獲取更小的文件加載體積;

  2. 通過包的拆解來得到更優(yōu)的加載策略,從而降低load time;

  3. 比較輕量的source mapping(當(dāng)然,當(dāng)你需要一些trace信息做日志和報(bào)警的時(shí)候是另外一番情景);

  4. 線上的產(chǎn)品的一些個(gè)性訴求(比如,對同一份Javascript代碼也許要匹配不同的樣式文件)等。

3. 通常評估效率維度主要有以下幾個(gè),穩(wěn)重提到的數(shù)據(jù)來源主要屬于前三個(gè):

  • 本地開發(fā)compile(w/ DLL or NO DLL)

  • 本地開發(fā)re-compile(w/ DLL or NO DLL)

  • 本地測試build(webpack analyse分析的重點(diǎn)部分)

  • 云構(gòu)建時(shí)長 (NO DLL or 配置化OSS支撐DLL)

在Webpack的新版本中,webpack-merge: 4.2.1 這個(gè)獨(dú)立包的使用,開發(fā)者使用webpack.common.js文件對開發(fā)和生產(chǎn)環(huán)境中的公共部分進(jìn)行配置,webpack.dev.js針對開發(fā)環(huán)境,webpack.prod.js針對生產(chǎn)環(huán)境。區(qū)分后,兩種環(huán)境的配置差異,一目了然:

前端 Webpack 工程化的最佳實(shí)踐

(圖:webpack配置文件結(jié)構(gòu))

關(guān)于cz.config.js和flowGlobalVars.js里面“話題點(diǎn)”頗多,不在此處重點(diǎn)描述。

如果需要DLL配置(在后面的優(yōu)化部分會(huì)重點(diǎn)講),還需要單獨(dú)加入一個(gè)webpack.dll.js打包的配置文件。當(dāng)然,dll其實(shí)也是一個(gè)普通的文件Output,我們可以在webpack.common.js文件中module.exports時(shí),寫兩個(gè)區(qū)分開。通過這種不是很常見的靈活寫法(Exporting multiple configurations),可以更多的去理解文件的I/O和module模塊的概念。

 

基礎(chǔ)/自定義配置

CommonsChunkPlugin被取代

被移入到了webpack.optimization.splitChunks中。有關(guān)拆包切分和顆粒度控制,這個(gè)其實(shí)從Webpack的層面已經(jīng)為我們做了很多優(yōu)化,自身也是有一套基礎(chǔ)默認(rèn)的優(yōu)化策略的。類比來看,React生態(tài)里面diff算法本身也是有策略機(jī)制的,更多的優(yōu)化,使用者可以在這個(gè)對象里面加入回調(diào)方法,自己去細(xì)化控制。

這里需要特別注意的是cacheGroups,當(dāng)不明確哪些內(nèi)容需要被cache時(shí),或者是顆粒度不好把控時(shí),這樣的切分會(huì)給我們帶來非常多的冗余文件。下面的代碼中,定義了一個(gè)vendors對象,那么我們的output文件(不包含chunksFiles)的每一個(gè)都會(huì)生成一個(gè)cache文件。加入output的有app.bundle.js和polyfill.bundle.js,一旦加入這個(gè)vendors對象,打包的時(shí)候會(huì)額外的生成兩份文件,分別是vendors-app.js和vendors-polyfill.js。雖然不用擔(dān)心這兩個(gè)文件內(nèi)容會(huì)重新打包代碼進(jìn)去,里面只是放一些cache索引,但這兩個(gè)文件如果在不確定要用他們來做什么的時(shí)候,cacheGroups的設(shè)置,需要重新認(rèn)真去考慮。

OccurrenceOrderPlugin

本身不在是一個(gè)webpack類下面的構(gòu)造器,而是被重新命名(之前的名稱因?yàn)閱卧~拼寫錯(cuò)誤了),然后放入到新的位置,調(diào)用起來需要重新去書寫:new webpack.optimize.OccurrenceOrderPlugin。

terser(默認(rèn)的內(nèi)置壓縮工具包)

webpack.optimization.minimizer的新版本中,default built-in的工具已經(jīng)由舊有的uglifyJS變成了terserJS,舊的uglify已經(jīng)被depreacted處理,相信不久之后的狀態(tài)就會(huì)變成legacy,新的terser更好的性能,對ES6+的語法支持的更多,也同時(shí)兼容了babel 7的生態(tài),同步其它第三方庫代碼壓縮后的訴求。目前我在使用的是terser-webpack-plugin,和普通的terser配置的參數(shù)上有一些差異,需要自己手動(dòng)引入(官方文檔推薦)。

? module.rules.exclude[0]

module.rules.exclude[0]的文件地址書寫,要求更加嚴(yán)格(4.11.0以后的版本)。

以往我們在對module.rules做配置時(shí),有些文件不希望被遍歷到,那么我們通過exclude這個(gè)參數(shù)配置,將其跳過,有時(shí)候會(huì)使用'src/contianer/xx.jsx'這樣的寫法,如果是多個(gè)path索引,那就放到一個(gè)Array中就好。但這種寫法,在新版本中是不被允許的,我們只能使用path.resolve或/regExp/的寫法去聲明文件路徑地址。(Bonus Basic Tips,如何用正則書寫并集和特定路徑,如我希望include所有src加上一個(gè)指定的npm包: /(src/.*)|(node_modules/.*@ali/lark-components)/)

alias和絕對路徑

webpack在打包的時(shí)候,通常需要對文件的路徑去做查找、搜索,它需要明確知道文件的引用位置和引用關(guān)系,從而能夠完整的知道整個(gè)映射mapping關(guān)系。減少這方面的開銷,我們可以考慮去配置alias,從而以絕對路徑的寫法代替大量相對路徑寫法。好處的話,一方面是幫助webpack更快的去定位文件位置,另一方面書寫起來,也不再用被輸入 '../../*' 還是 '../../../*' 而困擾。

  • Webstorm尋找絕對路徑:在配置里面對webpack配置項(xiàng)加入webpack文件路徑就好,Webstorm IDE會(huì)自己找到對應(yīng)的alias關(guān)系。

  • VSCode尋找絕對路徑:插件層面沒有發(fā)現(xiàn)太好的辦法,如果項(xiàng)目正在使用typescript,可以在tsconfig.json里面配置相關(guān)的編譯項(xiàng),可以達(dá)到和上面Webstorm同樣的效果。

大圖片上傳CDN

上傳CDN后可以大幅減小包體積。另外,webpack也不需要再去關(guān)注那些圖片的文件索引路徑了。項(xiàng)目稍微大一些,本地圖片5Mb ~ 10Mb的情況非常普遍,亟待優(yōu)化。

devServer Proxy的代理能力

去調(diào)研這個(gè)能力,得益于一次請求層的改造。訴求是希望Token不再顯示傳遞,而是通過塞到Header去實(shí)現(xiàn)。在本地開發(fā)的環(huán)境,我們通常使用jsonp去解決跨域問題,但其本質(zhì)其實(shí)是在網(wǎng)頁中嵌入一段<script />,自然也就不能寫入Header信息,這個(gè)和我們的初衷并不相符,無法滿足訴求。所以對于這樣的跨域問題,我們通過幾個(gè)簡單的參數(shù)配置,在請求發(fā)起和請求返回的兩端,分別做了代理配置,從而“欺騙”了“源Origin”,得以解決本地開發(fā)的跨域問題:

devServer: {
// ...
headers: {
'Access-Control-Allow-Origin': '*', // CORS
},
proxy: { // for ajax cors
'/h5/ajaxObj': {
target: 'http://xxx.xxx.xxx.com',
onProxyReq: (proxyReq) => {
proxyReq.setHeader('Origin', 'http://xxx.xxx.com');
},
onProxyRes: (proxyRes) => { // …},
},
},
},
 

優(yōu)化性能 by Node / Happypack

基礎(chǔ)配置和需要的自定義配置已經(jīng)有了,整個(gè)項(xiàng)目的構(gòu)建時(shí)間有可能還是非常不理想的,當(dāng)前本文提及的測試項(xiàng)目,大概有57s的時(shí)間,還是有很多地方?jīng)]有補(bǔ)足的,可優(yōu)化的空間非常大。

第一步可以先關(guān)注下Node版本,經(jīng)過測試,是對整體速度可以至少提升30%的事情,尤其是在Node V8版本到V10的時(shí)候,以下是之前在另一個(gè)項(xiàng)目做技術(shù)改造時(shí)記錄到的數(shù)據(jù):

Node版本

v 8.x

v 10.x

compile

32s - 36s

26s

re-compile

8s - 9s

4s

但是這次,在把項(xiàng)目直接升級到了 v 11.x 后發(fā)現(xiàn),有帶node-sass的項(xiàng)目編譯構(gòu)建都崩潰了。才意識到,node-sass的版本也需要相應(yīng)的版本更新。也測試了Babel v 6.x 到 v 7.x 版本的升級效果,本來以為babel的大版本升級會(huì)帶來顯著的編譯速度提高,實(shí)際上卻并不理想(基本可以忽略不計(jì))。

打算開啟多線程能力,去處理模塊化打包里面那些本是單線程執(zhí)行的 loaders 們的工作。Happypack的提升效率對整個(gè)項(xiàng)目的首次編譯而言,效果是20%左右,比較明顯。加入Happypack能力的時(shí)候,有兩點(diǎn)需要注意:

  • 其對file-loader和url-loader的支持不好,可以考慮不加,畢竟我們項(xiàng)目里面圖片類(最好上傳CDN)的和非常規(guī)格式的文件只是小部分;

  • 這次也嘗試了把ts-loader加入到多線程中,但是也出現(xiàn)了不少編譯問題。大概率懷疑是我個(gè)人的配置問題,但過程中去看issues見到了不少ts-loader和ts生態(tài)依賴兼容性的問題。目前這個(gè)項(xiàng)目.ts只是少數(shù)文件,作為一種嘗試,大部分文件還都是.jsx和.js,所以針對ts也先不加入Happypack能力了。

 

優(yōu)化性能 by DLL/ Optimization

首先需要借助一些工具來進(jìn)行分析,如:webpack-bundle-analyzer ,通過這個(gè)工具我們可以對整個(gè)構(gòu)建(用于生產(chǎn),Webpack Analyse針對的build過程,不是compile)過程和結(jié)果進(jìn)行數(shù)據(jù)、圖形上的分析,從而得知問題具體出現(xiàn)在了哪里。進(jìn)而得知DLL所需拆分的內(nèi)容是什么。以下內(nèi)容是在第一次分析時(shí)得出的:

前端 Webpack 工程化的最佳實(shí)踐

這個(gè)圖片的 3532 modules和62 chunks可以看到具體的模塊以及chunks劃分后的情況。更加直觀的我們來看下面這張圖,可以看到Parsed的尺寸,入口文件(7.09MB)和主chunk(2.04MB,主要是一些首頁就需要加載的node_module)的大小都很夸張,并且node_modules里面的包基本上是一一打包、整整齊齊:

前端 Webpack 工程化的最佳實(shí)踐

有了這些分析結(jié)果,對應(yīng)解法的思路就很清晰了:首先要抽離常用的node_modules(這是DLL的意義),然后要逐個(gè)分析,把不被經(jīng)常用到的node_module們(僅被某些頁面使用,不具有公共特點(diǎn))也抽出去。

對于React項(xiàng)目中的React、React-Dom、React-router、Redux等,還要一些第三方比較大的庫,比如antv或者G2相關(guān)的,也要進(jìn)行DLL抽離了:

前端 Webpack 工程化的最佳實(shí)踐

modules數(shù)量由3532降低到1500,編譯時(shí)間縮短了三倍

在做了上述DLL的抽離后其實(shí)效果已經(jīng)很明顯了,進(jìn)一步的提升空間,可以對optimization進(jìn)行了配置(用法詳見官方文檔):

  • terser

  • chunksAll

  • no mimimizer sourceMap

 

結(jié)尾

本文大概主要介紹了一些工具衍變背景、基礎(chǔ)的組織結(jié)構(gòu)和自定義配置,以及如何通過分析工具去來做性能優(yōu)化,其中很多小的細(xì)節(jié)沒辦法一一提到,比如我們看到加載的chunk都是hash值的時(shí)候,如何能夠辨別是什么組件呢:解法是可以在路由處通過配置moduleName的方式去做:

 => import(/* webpackChunkName: "chunkNameDisplay" */'../containers/UserList/chunkNameDisplay')

諸如此類,實(shí)在繁多。隨著Webpack 5.x版本的陸續(xù)發(fā)布和眾多團(tuán)隊(duì)使用之后,也許很多東西又會(huì)有大的改變。并且各種框架的集成已經(jīng)越來越豐富,更多的解放程序員在工程化維護(hù)上的雙手,我們關(guān)注工程化的演進(jìn),看看Webpack生態(tài)會(huì)給我們帶來什么樣的驚喜。

分享到:
標(biāo)簽:Webpack
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定