前言
程式碼分割是提升單頁應用初始載入速度的重要方式之一。因為使用者不用在第一次進入應用時下載所有程式碼,使用者能更快的看到頁面並與之互動。這會改善使用者體驗,尤其在移動端;而且這對 SEO 有很大幫助,因為 Google 會降低載入速度慢的網站權重。
上週我寫了一篇關於Vue.js 與 Webpack 如何分割程式碼的文章,長話短說,每個元件都封裝在單個檔案中,那很容易分割程式碼,當你匯入模組時,Webpack 可以建立一個分割點,並且 Vue 也可以很方便的載入一個非同步元件。
我認為程式碼分割最困難的部分不是如何讓它工作起來,而是何時、何地讓它工作。我想說,當設計你的應用時,就要將程式碼分割作為架構考慮進去。
在這篇文章中,我將介紹目前 Vue.js 的三種程式碼分割方式:
By page(按照頁面切分)
By page fold(按照頁面的可見區域摺疊切分)
sxsa- By condition(按條件載入)
注:這篇文章最初於2017/07/08發表在Vue.js開發部落格上。
1.By page(按照頁面切分)
按照頁面切分是思路最清晰的。這個簡單的應用有三個頁面:
我們假設每個元件都是一個單獨的檔案,比如:Home.vue
, About.vue
和 Contact.vue
,然後我們可以使用 Webpack 的動態 import
(dynamic import) 功能拆分成單獨的構建檔案。當使用者訪問不同頁面時,Wenpack 會非同步載入並請求改頁檔案。
如果你使用 vue-router
,這很容易實現,因為你的頁面已經在單獨的元件裡了。
const Home = () => import(/* webpackChunkName: "home" */ './Home.vue');
const About = () => import(/* webpackChunkName: "about" */ './About.vue');
const Contact = () => import(/* webpackChunkName: "contact" */ './Contact.vue');
const routes = [
{ path: '/', name: 'home', component: Home },
{ path: '/about', name: 'about', component: About },
{ path: '/contact', name: 'contact', component: Contact }
];複製程式碼
看看我們編譯程式碼時的統計資料,每個頁面都在它們自己的檔案裡,但要注意到有個重要的bundle檔案叫 build_main.js,它包含了所有的公共程式碼以及非同步載入其他檔案的邏輯。無論使用者訪問哪個路由,都必須先載入它。
現在我訪問 http://localhost:8080/#/contact
載入 Contact 頁面,我檢視 Network 選單,發現下列檔案被載入:
注意 build_main.js 這一欄的 initiator 值為 (index)。這意味著 index.html 請求了這個指令碼,這正是我們所期盼的。但是 build_1.js 的 initiator 卻是 bootstrap_a877…,這是 Webpack 指令碼負責的非同步載入檔案。當你使用 Webpack 的動態匯入功能,這個指令碼會自動加入構建。最重要的一點是: build_1.js 不會阻塞初始頁面的載入。
2.By page fold(按照頁面的可見區域摺疊切分)
摺疊以下(Below the “fold”)代表頁面初始時不可見的部分。你可以非同步載入這些內容,因為使用者通常需要一兩秒鐘才能閱讀完摺疊以上的內容,尤其是在第一次訪問站點時。
在這個例項應用中,我考慮把摺疊線設在刊頭下。那麼讓我們在頁面初始化時載入導航欄和刊頭,它們之下的所有內容,稍後再載入。我會建立一個名叫 BelowFold 的元件,提取出相關的程式碼如下:
Home.vue:
<template>
<div>
<div class="jumbotron">
<h1>Jumbotron heading</h1>
...
</div>
<below-fold></below-fold>
<!--All the code below here has been put into-->
<!--into the above component-->
<!--<div class="row marketing">
<div class="col-lg-6">
<h4>Subheading</h4>
<p>Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.</p>
...
</div>
...
</div>-->
</div>
</template>
<script>
const BelowFold = () => import(
/* webpackChunkName: "below-fold" */ './BelowFold.vue'
);
export default {
...
components: {
BelowFold
}
}
</script>複製程式碼
BelowFold.vue:
<template>
<div class="row marketing">
<div class="col-lg-6">
<h4>Subheading</h4>
<p>Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.</p>
...
</div>
...
</div>
</template>複製程式碼
當我們編譯程式碼時,可以看到 below-fold 被打包成了單獨的檔案:
提示:below-fold 小到只有1.36k,看起來似乎不值得把它單獨分離出來。因為現在只是一個很小的演示應用。在真實的應用中,頁面的大部分內容都在摺疊以下,因此可能有大量的程式碼,它包括 JS、CSS 以及所有子元件。
3.By condition(按條件載入)
另一個選擇方案是按條件載入。比如:模態框、Tab頁、選單等。
這個應用有個模態框,當你按下"Sign up today"按鈕時會彈出它:
和之前一樣,我們只是將模態框程式碼移動到它自己的單個檔案元件中:
Home.vue:
<template>
<div>
<div class="jumbotron">...</div>
<below-fold></below-fold>
<home-modal v-if="show" :show="show"></home-modal>
</div>
</template>
<script>
const BelowFold = () => import(
/* webpackChunkName: "below-fold" */ './BelowFold.vue'
);
const HomeModal = () => import(
/* webpackChunkName: "modal" */ './HomeModal.vue'
);
export default {
data() {
return {
show: false
}
},
components: {
HomeModal,
BelowFold
}
}
</script>複製程式碼
HomeModal.vue:
<template>
<modal v-model="show" effect="fade">...</modal>
</template>
<script>
import Modal from 'vue-strap/src/Modal.vue';
export default {
props: ['show'],
components: {
Modal
}
}
</script>複製程式碼
注意我在模態框上加了 v-if
。布林值 show
用來開啟/關閉模態框,並且它也用來判斷是否渲染模態框本身。因為初始化頁面時 show
為 false
,只有當模態框開啟時,才會下載程式碼。
這很合適,因為如果使用者沒有開啟模態框,那這塊程式碼是不會下載的。唯一的缺點是:它有很小的使用者體驗成本,當使用者按下按鈕後必須等待檔案下載完成。
再次編譯,下面是現在的輸出結果:
啊哈,我們又節省了5KB的首屏流量...
結論
除了以上三種程式碼分割的方法,我相信一定還有其他方法去實現,只要你運用自己的想象力!
本文譯者:餘震(Freak)
譯文出處:Rockjins Blog
版權宣告:本部落格所有文章除特別宣告外,均採用 CC BY-NC-SA 3.0 CN許可協議。轉載請註明出處!