Vue.js應用性能優化:第二部分---路由懶加載和 Vendor bundle 反模式

前一篇文章中,咱們學習了什麼是代碼分割,它是如何與 Webpack 一塊兒工做的,以及如何在Vue應用程序中使用延遲加載。如今,咱們將更深刻地研究,並學習用於分割 Vue.js 應用程序最實用的模式。javascript

本系列文章基於對 Vue Storefront 性能優化過程的學習。經過使用下面的技術,咱們可以將初始文件的大小減小70%,並在眨眼間使其加載。前端

應用程序增加的問題

Vue-router 是一個庫,它容許將咱們的web應用程序天然地分割成單獨的頁面。每一個頁面都是與某個特定URL路徑相關聯的路由。vue

瞭解了這一點,假設咱們有一個簡單的應用程序,其結構以下:java

1-2.jpg
整個JS代碼打包在一個文件中 -  app.jsnode

你可能已經注意到,咱們正在訪問的路徑,可能不須要 Home.vueAbout.vue(和它依賴的lodash),但它們都在相同的 app.js 文件中,不管用戶訪問哪個路徑,都會被下載。多麼浪費下載和解析時間啊!react

若是咱們下載一個額外的路由,這並非什麼大不了的事,但你能夠想象這個應用會變得愈來愈大,任何新的增長將意味着在首次訪問時要下載更大的文件。webpack

僅僅一秒鐘的時間足以讓用戶心理髮生變化,並頗有潛在可能會離開咱們的網站,這是不能接受的。git

image.png

來自 Ilya Grigorik 關於性能和人類感知的精彩演講github

以上圖片中出現的英文譯文:web

  • Wetware perception reaction times 人腦感知反應時間
  • instant 馬上
  • slight perceptible delay 輕微可察覺的延遲
  • Task focus,perceptible delay 明顯的延遲
  • Mental context switch 心理髮生變化
  • I'll come back later 我一下子再來

基於路由的代碼分割

爲了不讓應用程序變得更糟,咱們只須要使用上一篇文章中學習的動態導入語法爲每一個路由建立單獨的包

像在 Vue.js 中很容易實現延遲加載組件同樣,咱們要作的不是直接將組件導入到路由對象中,而是傳遞一個 動態導入函數,只有在訪問這個路由時,纔會下載對應的路由組件。

因此不要像這樣靜態導入路由組件:

import RouteComponent form './RouteComponent.vue'
const routes = [{ path: /foo', component: RouteComponent }]

咱們須要動態導入它,這將建立一個新的包,並將此路由做爲入口點:

const routes = [
  { path: /foo', component: () => import('./RouteComponent.vue') }
]

知道了這些,讓咱們看看動態導入後打包的文件和路由是什麼樣子的:

4-5.jpg

使用這個設置,webpack 將建立三個包:

  • app.js 咱們的主文件,包含了應用程序入口點(main.js)和每一個路由所須要的庫/組件。
  • home.js/** 路徑時才被下載。
  • about.js/about** 路徑時纔會被下載。

_爲了便於理解,文件名稱並非由webpack生成的真實名稱。其實是根據webpack配置生成 0.js1.js** 等_,具體取決於您的webpack配置。

這種技術幾乎適用於全部的應用,而且能夠產生很是好的效果。

在許多狀況下,基於路由的代碼分割將解決全部的性能問題,而且能夠在不到幾分鐘的時間內應用到幾乎任何應用程序中!

Vue生態系統中的代碼拆分

你可能正在使用 Nuxtvue-cli 來建立你的應用程序。若是是這樣,重要的是要知道它們都有關於代碼拆分的一些自定義行爲:

  • vue-cli3prefetchingvue-cliprefetching** 的知識,請看這篇文章
  • Nuxt路由系統,全部頁面路由的代碼分割都是開箱即用的。

如今讓咱們來看看很是流行且常被用到的反模式(anti-pattern),它能夠下降基於路由的代碼分割的影響。

Vendor bundle 反模式

Vendor bundle 一般用於包含 node_modules 中的全部模塊的單獨js文件。

雖然把全部文件都打包在一塊兒,以便將全部依賴關係保存在一個地方並緩存它們可能很吸引人,但這種方法引入了咱們將全部路由打包在一塊兒時遇到的一樣的問題:

6.png

你看到問題了嗎?即便咱們只須要在一個路由中使用 lodash(它是其中一個依賴項),它就會被打包在 vendor.js 中以及全部其餘依賴項中,所以它始終將會被下載。

將全部依賴項打包在一個文件中聽起來很吸引人,但這會延長應用程序的加載時間。咱們能夠作得更好!

咱們的應用程序使用基於路由的代碼分割,就足以確保只下載所須要的代碼。但這會致使一些代碼重複。

假設 Home.vue 也須要 lodash

7.png

在這種狀況下,從 /about (about .vue) 跳轉到 / (Home.vue) 將會下載 lodash 兩次。

雖然仍然比下載大量冗餘代碼要好,可是若是咱們已經知道了有這種依賴關係,那麼作不到被重用就沒有意義,對吧?

這就是 webpack splitChunksPlugin 能夠幫助咱們的地方。只要在 webpack 的配置中添加下面這幾行代碼,咱們就能夠將公共依賴項分組到一個單獨的文件中,這樣就能夠被共享了。

// webpack.config.js
optimization: {
  splitChunks: {
    chunks: 'all'
  }
}

chunk 屬性中,咱們只是告訴 webpack 應該優化那些代碼塊。正如您可能已經猜到的那樣,將該屬性設置爲 all 意味着它應該優化全部依賴項。

您能夠在 webpack文檔 中閱讀關於此過程的更多信息。

總結

按路由拆分代碼是保持初始加載文件大小較小的最佳(也是最簡單)方法之一。接下來,咱們將學習其餘部分(Vuex和單獨的組件)也可以從主文件分割出來並延遲加載。

若是對你有幫助,請關注【前端技能解鎖】:
qrcode_for_gh_d0af9f92df46_258.jpg

相關文章
相關標籤/搜索