前端工程化 - 聊聊 Webpack v3 到 Webpack v5 的核心架構變遷

前言

隨着前端工程化的持續發展, Webpack 做爲一個核心框架, 在整個打包構建中佔據了主導地位, 但同時 Webpack 從最初的相對簡單的配置也變得日益複雜和龐大, 從個人經從來講, 到目前的 v5 版本, 我所理解的 Webpack 架構經歷了 3 次比較大的變遷, 因爲職業病的關係, 本着對於架構的關注和熱愛, 我將這些架構變遷整理成文, 但願和各位一塊兒聊聊其中一些有趣的設計, 和變遷的細節, 遂有此文前端

正文

v1 - v3 單圖架構

Webpack 誕生之初的口號是一切皆可打包, 正如官網首頁上的那張圖所顯示的那樣, 能夠說從 Webpack 開始, 前端工程纔有真正意義上的 bundle, 過去的 grant, gulp 解決了流程問題, 但始終沒有解決如何將資源打成一個包, 這個最樸素的問題, Webpack 補齊了前端工程化的這塊短板, 也同時將前端工程化推向了一個嶄新的領域.docker

這個時期差很少是 v1 - v3 這三個版本, 我記憶中, 從 v1 - v3 Webpack 的升級沒有太太重大的變動, 都仍是比較平滑, 這種平滑的背後是核心架構在設計上的穩定, 先讓咱們來看看, 這一時期 Webpack 帶來的幾個主要概念npm

  • entry
  • output
  • Module
  • chunk

在早期的核心架構中, 將這 4個概念融合成一張圖差很少是這樣gulp

解釋下這張圖的意思, Webpack 經過 entry 指定的入口文件進行分析, 這個分析過程麼, 一言難盡, 反正你只要知道, 對於 Webpack 來說 require, import 等等各類模塊導入語法都要支持, 這裏 Webpack 主要用的是前端工程化

acorn.js 這是個用 JavaScript 寫的很是快的高性能解釋器, 用於將 JavaScript 代碼轉成抽象語法樹, 你說爲啥不用 babel ? 首先 babel 主要針對的仍是各類版本的 JavaScript 的語法轉換, 可是 babel 其實不解決模塊解析這個問題, 因此對於 Webpack 來講用 babel 過重了. 並且也不能完全解決問題, 況且 v1 的時候不也沒 babel 啥事麼.api

讓咱們回到上面的圖, 這裏重點要說下 chunk module 以及連起來的那幾條線, 在 Webpack 的核心架構裏, 最核心的內容就是 chunk, 能夠說 chunk 這個概念, 以及圍繞 chunk 的一系列設計是整個 Webpack 的核心的核心, 基礎的基礎, 沒有 chunk Webpack 能夠說就等於沒有了靈魂. 而後是 module, 在 Webpack 的設計裏 module 是文件的抽象映射, 配合 loader 組成了 bundle 的實體內容, 不像 chunk 這麼抽象, module 很是具體, 一個文件 → 一個module.babel

上面講了這麼多, 其實還沒點到題, 標題裏我寫了一個 單圖架構 這個單圖指的就是 ChunkGraph, 一個有 chunk 構建的圖結構, chunk 內包裹了 module, 這個基於 ChunkGraph 的單圖架構就是當時 Webpack 的核心架構, Webpack 的依賴分析, 包括 CommonsChunkPlugin 的公共代碼優化, 打包等等都是基於這個核心架構來完成的.架構

那爲何後來到 v4 就變了呢, 經歷過 v3 到 v4的同窗應該有感觸, Webpack v4 升級在當時是很是不平滑的, 好多插件不兼容, 遷移成本很大, 這裏一個核心緣由其實在於這個 CommonsChunkPlugin 的優化已經不能適應當時前端工程化對於拆包的訴求, 因而就有了 v4 的重大變動以及後來引入的 SplitChunksPlugin框架

v3 - v4 從單圖架構到雙圖架構

隨着技術發展, Webpack 團隊逐漸發現 CommonsChunkPlugin 已經沒有太多的優化空間, 在官網上有一篇文章解釋了沒法繼續優化的緣由, 其中的緣由和優化策略有關, 簡單來講就是在 ChunkGraph 中, 全部的 Chunk 都有一個 parent info, 標註了本身的父級 Chunk 是哪個, 而後假設有一個 module 它所在的 Chunk 的 parent 是全的, 那說明這個 module 是一個能夠被 common 化的 module, 因此你看這個 CommonsChunk 就知道這插件幹嘛的, 就是搞一個 Chunk 把這些公共的 module 都存起來, 而後呢? 再添加回 ChunkGraph, 而後由於每一個 Chunk 都得有 parent 那個 info嘛, 因此 Webpack 默認 CommonsChunk 是 parent chunk, 這麼作可能早期問題不大, 不事後來就有問題了, 主要是 2 點.異步

  • 由於 CommonsChunk 裏面是一堆公共依賴, 可是沒啥前後順序, 因此很難異步加載, 你必須儘量同步
  • 另外麼就是反正你要不要不重要哈, 無論裏面的 module 你要不要, 反正這個 chunk 一加載就全來了, 拖家帶口的很是不友好

另外 chunk 做爲一種抽象設計, 但卻隱含了 module 的依賴關係, 這種實現其實比較難以理解, 由於二者的抽象維度並不相同, 這也會致使後續的其餘優化在這一設計上遇到困境.

因而就有了 v4 裏的雙圖架構, 這裏的雙圖是原有的 ChunkGraph, 另外一個是 ModuleGraph. 而後 CommonsChunk 變成了 SplitChunk, 而且把原來的 parent chunk 和 child chunk 的關係變成了 parent chunk group 和 child chunk group 的關係, 這裏 chunk group 也是個新增的概念, 其實就是爲了把 chunk 變純粹, 父子關係抽象到 chunk group 上去了, Webpack 管這個叫啓發式, React 也有個啓發式, 感受比較類似, 雙圖架構的好處顯而易見, 至關於把攪和在一塊兒的兩張網給拆開了, Chunk 依然包含 Module 可是在依賴分析上, ModuleGraph 本身玩本身的, Chunk 成了一個純粹的抽象概念

由於 Chunk 的分析變獨立了, 也沒有父子結構了, 扁平了, 對 Chunk 的拆分組合以及異步化就變得很是容易了, 想怎麼組合怎麼組合, 想異步就異步, 只要把 Chunk 自己作個分類, 好比有 inital chunk 和 non-inital chunk, 後者就是用來搞異步的, 前者就是經過 entry 造成的那個 chunk

因此從 v3 到 v4 Webpack 的拆包功能提高了不少, SplitChunk 很是靈活, 可控性也強了不少, 不過前端工程化發展的也很是快, 從 v4 到如今 2年多的時間, 微前端 被拋了出來, 這對前端工程化又提出了新的要求, 天然做爲與時俱進的 Webpack 團隊也不能落後不是, 因而就有 v5, 新鮮出爐的熱乎特性 Module Federation , 一樣的 v5 也帶來了新的架構設計

v5 - 基於容器的架構

由於 v5 目前依然處於 beta 階段, 因此這裏寫的一些概念可能隨後都有可能發生變化, 最終以官網發佈的版本爲準, 我會盡量更新文章以匹配官方的內容

其實之因此有 v5, 若是沒有 v4 的 ModuleGraph 架構升級也是作不到的, 由於你看 Module Federation, 是基於 Module 的, 若是仍是 v3 的 單圖架構, 包都拆不出來不要說搞聯盟了, 最可能是個獨裁, 因此架構是演進出來的, 不存在跳躍式的架構, 每一次演進都是有跡可循, 相互聯繫的 , 因此 Module Federation 要解決什麼問題?

Module Federation 要解決的核心問題是, 如何在生產環境的 runtime 裏支持構建, 而且還不影響原有的線下的構建模式, 從而支持線上構建結果的水平拆解. 簡單來說呢就是你能夠線上加載別的 bundle 裏的模塊而不用線下從新 build 了, 很神奇是否是, 若是你受夠了 npm 引用, 對方一升級, 你要從新打包構建發佈, 那確實很神奇, 解決了大問題.

因此要作到這一點, 原有的架構設計確定不知足嘛, 因而就有了新概念 Container

Container 裏有一個 fileName , 就是 output 的別名, 而後 Container 也有本身的 entry, 經過 name 來映射到你本身配置裏的 entry, Container 還有一個重要的概念就是拿 module 當接口, 沒錯, 你沒看錯, 你就把 Container 想象成啥一個服務, 對 api 是啥就是裏面的 module, 因此你要這個 module 就很簡單, 去請求這個 Container 就行了嘛, 因此 Container 有一個 remotes 屬性用來標識一個請求源.

因此在 v5 的核心架構裏, 除了原有的雙圖架構, Webpack 增長了 Container 這個概念, 有點像 docker? 而內部的 module 相似服務接口, 這些設計確實頗有腦洞, 也能看出來 Webpack 團隊在前端工程化上積累多年的技術理解和創新意識.

不過由於 v5 還未發佈, 因此後續是否有變化很差說, 從目前看, 這套架構設計上有些概念還比較模糊, 因此我以爲還有很大的優化空間, 也就意味着還會發生一些變化, 至少在我看的上個月的相關內容, 在這個月就有些不太同樣了, 若是你感興趣, 能夠自行查閱相關的文檔, 包括示例, 官方給的仍是挺全的, 同時也清保持對 Webpack v5 持續關注吧.

後話

Webpack 的架構設計很是有趣也很值得深刻學習, 對於理解前端工程化有很大的幫助, 經過學習和探索, 也讓我獲益良多, 也但願以此文喚起你們對架構設計上的探索和興趣

相關文章
相關標籤/搜索