Vue 項目中使用 webpack 將多個組件合併打包並實現按需加載

使用 Vue 開發項目時,若是要使用其單文件組件特性,必然要使用 webpack 或者 Browserify 進行打包,對於大型應用,爲了提高加載速度,可使用 webpack 的 code splitting 功能進行分割打包,生成較小的模塊並按需加載,這在 Vue 文檔及 vue-router 文檔中均有介紹:Async ComponentsLazy Loadingjavascript

webpack 的 code splitting 可使用 webpack 的 require.ensure 特殊語法或者使用 AMD 風格的 callback-require 語法,以 AMD 風格的 callback-require 語法爲例——html

全局註冊 Async Component:前端

let myAsyncComponent = resolve => {
  require(['./my-async-component'], resolve)
}
Vue.component('async-webpack-example', myAsyncComponent)

局部註冊 Async Component,單文件組件中 script 塊內容:vue

let myAsyncComponent = resolve => {
  require(['./my-async-component'], resolve)
}

// Vue 擴展實例選項,其餘選項略
export default {
  components: {
    'async-webpack-example': myAsyncComponent
  }
}

在使用 vue-router 時,爲實現不一樣路由下的組件異步加載,在路由映射中可使用一樣的方式來設置路由項的 component 屬性。java

這裏的 myAsyncComponent 被定義爲一個工廠函數,在須要時纔會以 Vue 或者 vue-router 定義的用於解析組件選項的 resolve 回調函數(是的,在 Vue 和 vue-router 中有兩個不一樣的解析組件選項的函數)爲參數執行 callback-require 函數(resolve 回調函數的參數是組件選項),這樣,在執行打包腳本時,my-async-component.vue 文件會被單獨打包成一個文件,而且僅當該組件被使用時纔會加載。webpack

當要求異步加載的組件較多時,將會生成更多的單個文件,對於前端性能而言,雖然每一個文件更小了,但可能意味着更多的網絡鏈接創建和關閉的開銷,所以在前端優化的實踐中,一般須要在文件數量和單個文件大小之間取得平衡。web

本文介紹如何將多個組件合併打包成一個單獨的文件,一方面能夠減小代碼塊的數量,另外一方面,若是合併打包的這些組件在不一樣地方屢次重複使用,因爲 Vue 的緩存機制,能夠加快後續組件的加載速度,而且若是這些通用組件長時間不會變化(如 UI 相關的組件),打包生成的文件也長期不會變化,能夠充分利用瀏覽器的緩存功能,實現前端加載速度的優化。vue-router

先上效果圖,在使用 vue-router 的 SPA 應用中,將除根路由以外的路由項對應的 ComponentA、ComponentB、ComponentC 等三個組件合併打包成一個文件。初次加載頁面時,從開發者工具的 Network 面板上能夠看到,此時未加載包含 ComponentA、ComponentB、ComponentC 這三個組件的 0.a5a1bae6addad442ac82.js 文件,當點擊 Page A 連接時,加載了該文件,而後再點擊 Page B、Page C 連接時,沒有從新加載該文件。vue-cli

result

咱們首先經過 vue-cli 命令行工具使用 webpack 項目模板建立一個包含 vue-router 的項目,在其 src/components 目錄下建立一個 CommonComponents 目錄,在該目錄中建立 ComponentA、ComponentB、ComponentC 這三個組件。segmentfault

CommonComponents

同時在 CommonComponents 目錄下建立 index.js,其內容以下:

exports.ComponentA = require('./ComponentA')
exports.ComponentB = require('./ComponentB')
exports.ComponentC = require('./ComponentC')

這樣,咱們只須要使用 webpack 的 require.ensure 特殊語法或者使用 AMD 風格的 callback-require 語法異步加載 CommonComponents 目錄下的 index.js,在使用 webpack 進行打包時,就能夠實現將 ComponentA、ComponentB、ComponentC 這三個組件合併打包。以 AMD 風格的 callback-require 語法爲例示範以下,這裏的 callback 回調函數的形式沒有任何特殊要求。

require(['components/CommonComponents'], function (CommonComponents) {
  // do whatever you want with CommonComponents
})

components/CommonComponents 模塊加載成功時,這裏的回調函數中的 CommonComponents 參數將會是一個包含 ComponentA、ComponentB、ComponentC 這三個組件選項的對象。

在定義異步組件時,咱們使用的是一個工廠函數 resolve => {require(['./my-async-component'], resolve)},若是須要在路由配置文件中添加 component 屬性爲 ComponentA 組件的路由項,應該定義什麼樣的工廠函數呢?記住這裏的 resolve 是一個用於解析組件選項的回調函數,其參數是所獲取的組件選項,而上一段代碼中的 CommonComponents 剛好是包含若干個組件選項的對象,所以咱們能夠將 CommonComponents 的子屬性做爲參數用於 resolve 調用,咱們編寫一個函數 getCommonComponent,用於根據組件名稱返回獲取相應的組件選項的工廠函數。

let getCommonComponent = componentName => resolve => require(['components/CommonComponents'], components => resolve(components[componentName]))

在組件模板或者路由映射等使用其中某一個組件的地方,可使用相似於 getCommonComponent('ComponentA') 這樣的函數調用進行組件設置,在路由映射中的使用示例以下:

routes: [
  {
    path: '/',
    name: 'Hello',
    component: Hello
  },
  {
    path: '/a',
    name: 'A',
    component: getCommonComponent('ComponentA')
  },
  {
    path: '/b',
    name: 'B',
    component: getCommonComponent('ComponentB')
  },
  {
    path: '/c',
    name: 'C',
    component: getCommonComponent('ComponentC')
  }
]

最終打包生成的文件列表以下圖所示,其中的 0.a5a1bae6addad442ac82.js 包含了 ComponentA、ComponentB、ComponentC 這三個組件。

built


進階學習

SF 講堂《學習 Vue 你須要知道的 webpack 知識》

相關文章
相關標籤/搜索