1. 程式人生 > >手摸手,帶你用合理的姿勢使用 webpack 4(上)

手摸手,帶你用合理的姿勢使用 webpack 4(上)

(點選上方公眾號,可快速關注)

作者:華爾街見聞技術團隊 - 花褲衩

segmentfault.com/a/1190000015919863

前幾天 webpack 作者 Tobias Koppers 釋出了一篇新的文章:webpack 4.0 to 4.16: Did you know?,總結了一下 webpack4釋出以來,做了哪些調整和優化,並且說自己正在著手開發 webpack5

Oh you are still on webpack 3. I’m sorry, what is blocking you? We already working on webpack 5, so your stack might be outdated soon…

翻譯成中文就是:

640?wx_fmt=jpeg

正好我也在使用一個文件生成工具 docz(安利一波) 也最低需要 webpack4+,新版 webpack效能提高了不少,而且 webpack4 都已經發布五個多月了,想必應該已經沒什麼坑了,應該可以安心的按照別人寫的升級攻略升級了。之前一直遲遲不升級完全是被去年被 webpack3 坑怕了。它在 code splitting 的情況下 CommonsChunkPlugin會完全失效。過了好一段時間才修復,欲哭無淚。

所以這次我等了快大半年才準備升級到 webpack4 但萬萬沒想到還是遇到了不少的問題! 有很多之前遺留的問題還是沒有很好地解決。但最主要的問題還是它的文件有所欠缺,已經廢除了的東西如

commonsChunkPlugin還在官方文件中到處出現,很多重要的東西卻一筆帶過,甚至沒寫,需要使用者自己去看原始碼才能解決。

還比如在 v4.16.0版本中廢除了 optimization.occurrenceOrderoptimization.namedChunksoptimization.hashedModuleIdsoptimization.namedModules 這幾個配置項,替換成了 optimization.moduleIdsoptimization.chunkIds,但文件完中全沒有任何體現,所以你在新版本中還按照文件那樣配置其實是沒有任何效果的。

最新最完整的文件還是看他專案的配置WebpackOptions.json,強烈建議遇到不清楚的配置項可以看這個,因為它一定保證是和最新程式碼同步的。

吐槽了這麼多,我們言歸正傳。由於本次手摸手篇幅有些長,所以拆解成了上下兩篇文章:

  • 上篇 -- 就是普通的在 webpack3的基礎上升級,要做哪些操作和遇到了哪些坑

  • 下篇 -- 是在 webpack4下怎麼合理的打包和拆包,並且如何最大化利用 longterm caching

本文章不是手摸手從零教你 webpack 配置,所以並不會講太多很基礎的配置問題。比如如何處理 css 檔案,如何配置 webpack-dev-server,講述 file-loader 和 url-loader 之間的區別等等,有需求的推薦看 官方文件 或者 survivejs 出的一個系列教程。或者推薦看我司的另一篇 wbepack 入門文章,已同步到 webpack4 傳送門。

升級篇

前言

我一直認為模仿和借鑑是學習一個新東西最高效的方法。所以我建議還是通過借鑑一些成熟的 webpack 配置比較好。比如你專案是基於 react 生態圈的話可以借鑑 create-react-app ,下載之後 npm run eject 就可以看到它詳細的 webpack 配置了。vue 的話由於新版 vue cli不支援 eject了,而且改用 webpack-chain來配置,所以借鑑起來可能會不太方便,主要配置 地址。覺得麻煩的話你可以直接借鑑 vue-element-admin 的 配置。或者你想自己發揮,你可以借鑑 webpack 官方的各種 examples,來組合你的配置。

升級 webpack

首先將 webpack 升級到 4 之後,直接執行 webpack--xxx是不行的,因為新版本將命令列相關的東西單獨拆了出去封裝成了 webpack-cli。會報如下錯誤:

The CLI moved into a separate package: webpack-cli. Please install webpack-cli in addition to webpack itself to use the CLI.

所有你需要安裝 npm install webpack-cli-D-S。你也可將它安裝在全域性。

同時新版 webpack 需要 Node.js的最低支援版本為6.11.5不要忘了升級。如果還需要維護老專案可以使用 nvm 來做一下 node 版本管理。

升級所有依賴

因為 webpack4改了 它的 hook api ,所以所有的 loadersplugins都需要升級才能夠適配。

可以使用命令列 npm outdated,列出所以可以更新的包。免得再一個個去 npm找相對於的可用版本了。

640?wx_fmt=jpeg

反正把 devDependencies的依賴都升級一下,總歸不會有錯。

帶來的變化

其實這次升級帶來了不少改變,但大部分其實對於普通使用者來說是不需要關注的,比如這次升級帶來的功能 SideEffectsModuleType’sIntroducedWebAssemblySupport,基本平時是用不到的。我們主要關注那些對我們影響比較大的改動如: optimization.splitChunks代替原有的 CommonsChunkPlugin(下篇文章會著重介紹),和 BetterDefaults-mode更好的預設配置,這是大家稍微需要關注一下的。

640?wx_fmt=jpeg

如果想進一步瞭解 TreeShakingSideEffects的可見文末拓展閱讀。上圖參考 Webpack 4 進階

預設配置

webpack 4 引入了 零配置的概念,被 parcel 刺激到了。 不管效果怎樣,這改變還是值得稱讚的。

最近又新出了 Fastpack 可以關注一下。

言歸正題,我們來看看 webpack 預設幫我們做了些什麼?

development 模式下,預設開啟了 NamedChunksPluginNamedModulesPlugin方便除錯,提供了更完整的錯誤資訊,更快的重新編譯的速度。

  1. module.exports = {

  2. + mode: 'development'

  3. - devtool: 'eval',

  4. - plugins: [

  5. -   new webpack.NamedModulesPlugin(),

  6. -   new webpack.NamedChunksPlugin(),

  7. -   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),

  8. - ]

  9. }

production 模式下,由於提供了 splitChunksminimize,所以基本零配置,程式碼就會自動分割、壓縮、優化,同時 webpack 也會自動幫你 ScopehoistingTree-shaking

  1. module.exports = {

  2. +  mode: 'production',

  3. -  plugins: [

  4. -    newUglifyJsPlugin(/* ... */),

  5. -    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),

  6. -    new webpack.optimize.ModuleConcatenationPlugin(),

  7. -    new webpack.NoEmitOnErrorsPlugin()

  8. -  ]

  9. }

webpack 一直以來最飽受詬病的就是其配置門檻極高,配置內容極其複雜和繁瑣,容易讓人從入門到放棄,而它的後起之秀如 rollup、parcel 等均在配置流程上做了極大的優化,做到開箱即用,所以 webpack4也從中借鑑了不少經驗來提升自身的配置效率。願世間再也不需要 webpack 配置工程師

html-webpack-plugin

用最新版本的的 html-webpack-plugin你可能還會遇到如下的錯誤:

thrownewError('Cyclic dependency'+nodeRep)

產生這個 bug 的原因是迴圈引用依賴,如果你沒有這個問題可以忽略。

目前解決方案可以使用 Alpha 版本, npm i--save-dev [email protected]

或者加入 chunksSortMode:'none'就可以了。

但仔細檢視文件發現設定成 chunksSortMode:'none'這樣是會有問題的。

Allows to control how chunks should be sorted before they are included to the HTML.

這屬性會決定你 chunks 的載入順序,如果設定為 none,你的 chunk 載入在頁面中載入的順序就不能夠保證了,可能會出現樣式被覆蓋的情況。比如我在 app.css裡面修改了一個第三方庫 element-ui的樣式,通過載入順序的先後來覆蓋它,但由於設定為了 none,打包出來的結果變成了這樣:

  1. <linkhref="/app.8945fbfc.css"rel="stylesheet">

  2. <linkhref="/chunk-elementUI.2db88087.css"rel="stylesheet">

app.css被先載入了,之前寫的樣式覆蓋就失效了,除非你使用 important或者其它 css 權重的方式覆蓋它,但這明顯是不太合理的。 vue-cli正好也有這個相關 issue,尤雨溪也在不使用 @next版本的基礎上 hack 了它,有興趣的可以自己研究一下,本人在專案中直接使用了 @next版本,也沒遇到其它什麼問題(除了不相容 webpack 的 prefetch/preload 相關 issue)。兩種方案都可以,自行選擇。

其它 html-webpack-plugin 的配置和之前使用沒有什麼區別。

mini-css-extract-plugin

與 extract-text-webpack-plugin 區別

由於 webpack4對 css 模組支援的完善以及在處理 css 檔案提取的方式上也做了些調整,所以之前我們一直使用的 extract-text-webpack-plugin也完成了它的歷史使命,將讓位於 mini-css-extract-plugin

使用方式也很簡單,大家看著 文件 抄就可以了。

它與 extract-text-webpack-plugin最大的區別是:它在 code spliting的時候會將原先內聯寫在每一個 js chunk bundle的 css,單獨拆成了一個個 css 檔案。

原先 css 是這樣內聯在 js 檔案裡的:640?wx_fmt=jpeg

將 css 獨立拆包最大的好處就是 js 和 css 的改動,不會影響對方。比如我改了 js 檔案並不會導致 css 檔案的快取失效。而且現在它自動會配合 optimization.splitChunks的配置,可以自定義拆分 css 檔案,比如我單獨配置了 element-ui作為單獨一個 bundle,它會自動也將它的樣式單獨打包成一個 css 檔案,不會像以前預設將第三方的 css 全部打包成一個幾十甚至上百 KB 的 app.xxx.css檔案了。

640?wx_fmt=png

壓縮與優化

打包 css 之後檢視原始碼,我們發現它並沒有幫我們做程式碼壓縮,這時候需要使用 optimize-css-assets-webpack-plugin 這個外掛,它不僅能幫你壓縮 css 還能優化你的程式碼。

  1. //配置

  2. optimization: {

  3.  minimizer: [newOptimizeCSSAssetsPlugin()];

  4. }

640?wx_fmt=jpeg

如上圖測試用例所示,由於 optimize-css-assets-webpack-plugin這個外掛預設使用了 cssnano 來作 css 優化,所以它不僅壓縮了程式碼、刪掉了程式碼中無用的註釋、還去除了冗餘的 css、優化了 css 的書寫順序,優化了你的程式碼 margin:10px20px10px20px; => margin:10px20px;。同時大大減小了你 css 的檔案大小。更多優化的細節見文件。

contenthash

但使用 MiniCssExtractPlugin 有一個需求特別注意的地方,在預設文件中它是這樣配置的:

  1. newMiniCssExtractPlugin({

  2. // Options similar to the same options in webpackOptions.output

  3. // both options are optional

  4.  filename: devMode ? "[name].css" : "[name].[hash].css",

  5.  chunkFilename: devMode ? "[id].css" : "[id].[hash].css"

  6. });

簡單說明一下: filename 是指在你入口檔案 entry中引入生成出來的檔名,而 chunkname是指那些未被在入口檔案 entry引入,但又通過按需載入(非同步)模組的時候引入的檔案。

copy 如上程式碼使用之後發現情況不對!每次改動一個 xx.js檔案,它對應的 css 雖然沒做任何改動,但它的 檔案 hash 還是會發生變化。仔細對比發現原來是 hash 惹的禍。 6.f3bfa3af.css => 6.40bc56f6.css

640?wx_fmt=png

但我這是根據官方文件來寫的!為什麼還有問題!後來在文件的最最最下面發下了這麼一段話!

For long term caching use filename: [contenthash].css. Optionally add [name].

非常的不理解,這麼關鍵的一句話會放在 Maintainers 還後面的地方,預設寫在配置裡面提示大家不是更好?有熱心群眾已經開了一個 pr,將文件預設配置為 contenthashchunkhash=> contenthash相關 issue。

這個真的蠻過分的,稍不注意就會讓自己的 css 檔案快取無效。而且很多使用者平時修改程式碼的時候都不會在意自己最終打包出來的 dist資料夾中到底有哪些變化。所以這個問題可能就一直存在了。浪費了多少資源!人艱不拆!大家覺得 webpack 難用不是沒道理的。

這裡再簡單說明一下幾種 hash 的區別:

hash

hash 和每次 build有關,沒有任何改變的情況下,每次編譯出來的 hash都是一樣的,但當你改變了任何一點東西,它的 hash就會發生改變。

簡單理解,你改了任何東西, hash 就會和上次不一樣了。

chunkhash

chunkhash是根據具體每一個模組檔案自己的的內容包括它的依賴計算所得的 hash,所以某個檔案的改動只會影響它本身的 hash,不會影響其它檔案。

相關推薦

合理姿勢使用 webpack 4

(點選上方公眾號,可快速關注)作者:華爾街見聞技術團隊 - 花褲衩segmentfault.co

【轉】vue擼後臺 系列二(登錄權限篇)

userinfo ogr abort 變化 再次 狀態碼 quest -o 監聽 前言 拖更有點嚴重,過了半個月才寫了第二篇教程。無奈自己是一個業務猿,每天被我司的產品虐的死去活來,之前又病了一下休息了幾天,大家見諒。 進入正題,做後臺項目區別於做其它的項目,權限驗證與

vue擼後臺 系列二(登入許可權篇)

前言 拖更有點嚴重,過了半個月才寫了第二篇教程。無奈自己是一個業務猿,每天被我司的產品虐的死去活來,之前又病了一下休息了幾天,大家見諒。 進入正題,做後臺專案區別於做其它的專案,許可權驗證與安全性是非常重要的,可以說是一個後臺專案一開始就必須考慮和搭建的基礎核心功能

vue實現後臺管理許可權系統及頂欄三級選單顯示

手摸手,帶你用vue實現後臺管理許可權系統及頂欄三級選單顯示 效果演示地址 專案demo展示 重要功能總結 許可權功能的實現 許可權路由思路: 根據使用者登入的roles資訊與路由中配置的roles資訊進行比較過濾,生成可以訪問的路由表,並通過router.addRoutes(store.gett

寫Struts深入原始碼中心解析

個人剖析,不喜勿噴 掃碼關注公眾號,不定期更新干活 在此申明本博文並非原創,原文:http://blog.csdn.net/lenotang/article/details/3336623,本文章是在此文章基礎上進行優化。也談不上優化,只是加上了點自己的想法 jar包準備 為什麼會用到這兩個j

合理姿勢使用webpack4

推薦先閱讀 webpack 入門教程之後再來閱讀本文。 本文為手摸手使用 webpack4(下),主要分為兩部分: 怎麼合理的運用瀏覽器快取 怎麼構建可靠的持久化快取 預設分包策略 webpack 4 最大的改動就是廢除了 CommonsChunkPlugin 引

golang--深入簡出golang的反射擼一個公用後臺查詢方法

一些基本方法 本篇不會介紹反射的基本概念和原理等,會從每個常用的方法入手,講解一些基本和進階用法,反射不太適合在業務層使用,因為會幾何倍的降低執行速度,而且用反射做出來的程式健壯度不高,一旦一個環節沒有處理好就會直接panic,影響程式的執行,但是在後臺上使用還是很適合的,可以極大的降低程式碼量,從繁複的增刪

Android事件分發機制完全解析從原始碼的角度徹底理解()-郭霖

其實我一直準備寫一篇關於Android事件分發機制的文章,從我的第一篇部落格開始,就零零散散在好多地方使用到了Android事件分發的知識。也有好多朋友問過我各種問題,比如:onTouch和onTouchEvent有什麼區別,又該如何使用?為什麼給ListView引入了一

Android事件分發機制完全解析從原始碼的角度徹底理解()

其實我一直準備寫一篇關於Android事件分發機制的文章,從我的第一篇部落格開始,就零零散散在好多地方使用到了Android事件分發的知識。也有好多朋友問過我各種問題,比如:onTouch和onTouchEvent有什麼區別,又該如何使用?為什麼給ListView引入

圖文筆記走進《未來簡史》1-5

    除了舉例驗證了人類對永生的渴望。     同時,這部分還介紹了科學界為永生而做出的具體努力和樂觀展望,即:基因工程、再生醫學和納米科技有望實現衰老組織的再生,至少達到使人長生不老。     接下來,作者設想了當人類壽命可以達到150歲,將給社會帶來的一些影響,比如:     (1)家庭結構

H5寫簽名適用於手機網頁、電腦網頁IE9+

先看看效果吧: 圖片儲存到伺服器為png格式,一般10k左右。 這個功能適用於H5app,或者H5,或者pc網頁端(IE9以上,支援canvas), 低端安卓機依然不支援,具體低端到什麼程度,沒有經過測試。 下邊上程式碼,前端HTML: <!DOCTYPE

Android事件分發機制完全解析從原始碼的角度徹底理解() (出自郭霖老師)

其實我一直準備寫一篇關於Android事件分發機制的文章,從我的第一篇部落格開始,就零零散散在好多地方使用到了Android事件分發的知識。也有好多朋友問過我各種問題,比如:onTouch和onTouchEvent有什麼區別,又該如何使用?為什麼給ListView引入了

圖文筆記走進《未來簡史》36-41

作者:@文曰小強(微信公眾號:diaoxiazhangqiang) 整理:@一喵(作者已授權) 轉載請註明出處。 英脫歐、美大選的資料本質《未來簡史》筆記36     上期語音我們提到,政治結構本質上也可以理解為資料處理系統。原著裡作者就提到:民主和專制本質

51CTO學院新課發布~~遇見更好的自己2017.11.06-11.12

新課推薦 開發 運維 人工智能 雲計算 大數據 編程 軟考 設計 遊戲 金融財會 職場 辦公hello,各位小仙女(dan)、小哥哥(shen)們(dogs),雙11已過,想必大家的日常除了等快遞已生無可戀。小編姐姐來撒把狗糧在下面,如果你的雙11不是醬紫渡過的,而是剁手剁手再剁手,恭喜你的雙11很圓滿呀~~

51CTO學院新課發布~~遇見更好的自己2017.11.20-11.26

新課推薦 開發 運維 辦公 金融財會 一周的時間匆匆即逝,又到了給你們出新課列表的時候了,小編每周都辛苦的給你們推課,也不幾道你們到底看了沒,想到小編之前做講師的時候,那可是一把鼻涕一把淚的催著同學們學習。有個段子特別能描述當時的心情:“老師這個職業吧,說的文明點就是每天帶著學生在知識的海洋裏暢遊。然而暢遊一

51CTO學院新課發布~~遇見更好的自己2017.11.27-12.03

新課 開發 運維 設計 office 以往新課發布的開場白,都是小編姐姐逗比的閑扯,小編姐姐準備轉變一下畫風,以後的新課發布開場白就談談每周我對於職場或者生活的一點小理解吧。上周看到一篇文章,關於人和人的身價的差距:職場10年,為什麽有人已經當上了董事總經理,而有的人還是資深銷售經理?為什

51CTO學院新課發布~~遇見更好的自己2017.11.04-12.17

開發 運維 辦公 設計 理財 新的一周新的失望,大家好,你們的毒雞湯姐又華麗麗的上線了。今天想跟大家聊聊這個投資。為什麽要說這個呢?因為最近小編的媽媽(一位三四線小城市的中年婦女),居然開始玩區域鏈了,這使得小編不寒而栗,畢竟我現在都沒徹底搞清楚區域鏈。曾記得我是2014年的時候開始聽說比

一文瞭解求職面試那些名詞乾貨

喬兄剛剛經歷了19秋招,收穫了百度offer,馬上要迎來了19春招,有很多公眾號的粉絲經常會問今年不是2018年嗎,你咋就已經完成了2018校招了?由於被很多人經常問起,下面喬兄給大家普及一下跟校招相關的名詞。 現在時間是北京時間 2018.11.15,請務必根據現在的時間去推測你的情況。 201

即學即輕鬆搞定這些選擇器!

所謂基本選擇器是指選擇器的名稱前面沒有其他選擇器,即在組成上,基本選擇器是單一名稱。 基本選擇器主要包括: 元素選擇器 ID 選擇器 類選擇器 偽類選擇器 偽元素選擇器 通用選擇器 元素選擇器 在 W3C 標準中,元素選擇器又稱為型別選擇器。使用元素選擇器設定樣式的語法如下: 元素選擇器 { 屬性

CocosCreator之KUOKUO做瘋狂木板-過橋2原始碼分享

本次引擎2.0.5 編輯工具VSCode 目標: 第二部分,過橋與得分。 接著上一節: 我們實現了木板的變長與下落。 現在我們實現一個牛逼的平臺,怎麼說它牛逼呢?我準備全程就用它一個來完成所有功能。 看KUOKUO怎麼實現。console.log(滑稽) 首先,我們複