在前一個部份我們學到可以大幅度改善你的應用程式效能的模式 – 透過路由來切割程式碼。僅管透過路由切割程式碼是非常有幫助的但仍然有很多程式是使用者剛進去網站時使用不到的。在本篇我們將專注在我們的狀態管理的程式碼切割 – Vuex modules。
這個系列是基於從Vue Storefront的效能優化處理中所學到的。透過以下的技術我們可以砍掉我們最初的打包的70%,使他載入在一眨間就完成。
兩種Vuex modules的類型
在我們繼續往下看Vuex modules的lazy loading之前,這裡有一件很重要的事你需要注意的。你需要了解有哪些可以注冊Vuex modules的方法以及他們的優缺點。
靜態Vuex modules在store初始化時就宣告了。以下是個明確的建置靜態模組的範例:
// store.js
import { userAccountModule } from './modules/userAccount'
const store = new Vuex.Store({
modules: {
user: userAccountModule
}
})
上面的程式碼會new一個新的Vuex Store以及靜態模組userAccountModule。靜態模組不能被取消註冊(並且不能被延遲註冊)以及他們的架構(這是不是指state)在初始化後不能被改變。
僅管這個限制對於大部份的module來說不會是個問題,並且把全部的modules宣告在同一個地方對於讓資料的關聯在同一個地方維持一致是很好用的,但這個方法還是有些缺點。
假設我們的應用程式裡有一個管理者儀表板以及它專用的Vuex module。
// store.js
import { userAccountModule } from './modules/userAccount'
import { adminModule } from './modules/admin'
const store = new Vuex.Store({
modules: {
user: userAccountModule,
admin: adminModule
}
})
你可以想像這樣子的module可以是非常大的。即使儀表板只有限於一部份的使用者使用(也可想成只在特定的/admin路由),由於統一註冊了靜態Vuex module它所有的程式碼還是會在主要的打包程式當中。
這個情況當然不是我們所要的結果,我們需要一個方法只在/admin路由當中讀取它。你可能已經猜到靜態module不能滿足我們的需求,全部的靜態module必須在Vuex Store被建置時被註冊、因此無法延後註冊的時機。
這也就是動態module幫的上忙的地方!
動態module和靜態的相反,它可以在Vuex store創建之後才註冊。這個聰明的特性暗示我們不需要在應用程式初始化時做動態載入,可以打包成不同的模塊或在需要的時候才延遲載入。
首先,我們來看前面所說的動態註冊admin module會長什麼樣子。
// store.js
import { userAccountModule } from './modules/userAccount'
import { adminModule } from './modules/admin'
const store = new Vuex.Store({
modules: {
user: userAccountModule,
}
})
store.registerModule('admin', adminModule)
取代直接把adminModule物件直接放入store裡的property,我們在store建置出來後使用registerModule方法註冊它。
動態註冊並不需要更改module本身,所以所有的Vuex module都可以直接註冊或動態的註冊。
當然,以目前這個寫法來說動態註冊module沒有給我們任何優勢。
正確地切割Vuex module程式碼
延續前面的討論,現在我們知道如何動態地註冊admin module、所以我們當然可以試著把它放入/admin路由的綁定。
我們暫且停一下,來簡單理解一下我們的應用程式的運作方式。
// router.js
import VueRouter from 'vue-router'
const Home = () => import('./Home.vue')
const Admin = () => import('./Admin.vue')
const routes = [
{ path: '/', component: Home },
{ path: '/admin', component: Admin }
]
export const router = new VueRouter({ routes })
我們來瞧瞧這裡做了什麼!
我們在Admin.vue(路由/admin)的mounted裡import並註冊admin store。稍後程式裡我們會在使用者離開的時候把module給取消註冊,以避免同樣的module被重覆註冊。
現在因為admin module被import到Admin.vue裡取代原本的store.js,它現在和程式切割了的Admin.vue綁定在一起。
重要注意:如果你使用SSR模式請確保你把註冊module放在mounted裡,否則的話當beforeDestory鈎子沒設好可能會導致memory leak。
現在我們知道如何使用動態Vuex module註冊,來分開我們特定路由的module到適當的打包中。我們來看看稍微複雜一點的使用方式。
Lazy loading Vuex modules
假設我們有的Home.vue有一個推薦區塊,我們希望能展示關於我們服務的正面意見。因為數量會很多所以我們不需要在使用者進入後就馬上呈現,比較好的展示方式是當使用者看的時候。我們可以增加一個”檢視推薦”按鈕當點擊時我們才把推薦內容給呈現出來。
為儲存推薦資料我們需要再一個Vuex module命名為testimonials。這個module負責呈現前一個加入的推薦並新增一個新的,我們不需要知道關於它實作的細節。
我們希望testimonials module只有在使用者點擊按鈕的時候下載,因為在這之前並不需要它。我們來看這個動態import及註冊module的功能該如何實現。Testimonials.vue是Home.vue裡的一個子component。
方法,getTestimonialsModule()負責取得testimonials.js。當promise被resolved(代表module被讀取)我們動態地註冊它並dispatch action來取得推薦內容。
感謝動態import,testimonial.js的內容被綁定到分開的檔案中,只有當getTestimonialsModule方法被呼叫時才會被下載。)
當我們需要離開管理者平台,我們在剛才的beforeDestory生命週期鉤子裡有取消註冊,所以如果我們要再次進入路由它不會被重覆。
總結
僅管理靜態Vuex module註冊足以應付大部份的使用情況,還是有些特定情況我們還是需要動態註冊。
- 如果只有在特定路由需要module,那我們可以在特定的路由component裡動態的註冊,所以不會出現在主要的打包當中。
- 如果只有在特定的互動需要module,那我們需要在特定的方法中合併動態註冊module和動態import、延遲載入。
切割Vuex module程式碼是一個強而有力的工具。在應用程式裡處理得愈多資料相關的操作,表示能節省愈多的打包容量。
在下一篇我們將學習如何延遲載入獨立的component,以及更重要的是哪個component應該被延遲載入。