一般爲了開發效率,咱們會使用 vue-cli
建立項目,這樣建立的項目默認狀況下編譯是會對代碼進行分割的。可是若是是自行配置的 webpack 環境的話,仍是頗有必要熟悉代碼分割的相關知識的。css
在配置 webpack 的過程當中,不少時候咱們的 webpack 入口只寫了一個 entry: '${sourceDir}/index.js’
,默認狀況下只會生成一個 bundle 文件,包含了第三方庫、公共代碼及不一樣頁面所用到的業務邏輯,這必然會形成該 bundle 文件體積過大,影響頁面首次的加載速度,所以咱們須要對代碼進行分割,加快首次進入頁面的速度。html
首先把第三方庫、公共代碼抽離出來,由於這些代碼變更的頻率小,能夠打包成一個文件,這樣每次上線文件都不發生變化,能夠充分利用網絡緩存加快文件下載速度,分割的細的話就是,第三方庫爲一個 js 文件, 公共代碼爲一個 js 文件。vue
而後,按照路由(頁面)進行代碼分割,每一個頁面生成一個 js 文件,這樣每次首次進入就只加載公共代碼和本頁面用的的 js 文件, 而不用加載其它頁面無關的代碼。node
最後,再進行精細分割的話,就是根據組件使用狀況進行分割,來實現組件的懶加載,好比:頁面中的不一樣 tab,能夠根據 tab 的展現狀況進行分割,把須要點擊或者用戶主動操做才能呈現的組件進行懶加載,這樣就在頁面級又進行了更細粒度的代碼分割。webpack
第一步咱們進行第三方庫的分割,好比 vue、vue-router、vuex、axios 等三方庫,把它們放到 vender.js 中,而後 utils、common 文件等放在 common.js 中。這些經過 webpack 的 entry 及 splitChunk 配置便可實現。ios
修改 entry 配置:web
{ // ... entry: { // 把公共代碼放到 common 裏 common: [`${sourceDir}/utils/index.js`], main: `${sourceDir}/index.js`, }, // ... }
splitChunk 配置:vue-router
{ optimization: { // splitChunks 配置 splitChunks: { cacheGroups: { default: { name: 'vendor', // 把第三方庫放到 vendor 裏,包括 vue, vue-router, vuex 等 // 由於他們都是從 node_modules 里加載的,這裏直接正則匹配 test: /[\\/]node_modules[\\/]/, chunks: 'initial', // 調整優先級,優先處理 priority: 10, }, common: { chunks: 'all', name: 'common', // 匹配 entry 裏的 common 配置 test: 'common', }, }, }, // runtime 代碼放在 runtime 文件中 runtimeChunk: { name: 'runtime', }, } }
另外就是 output 配置了,[name]
表示讓 chunk 名稱做爲文件名, [chunkhash:8]
表示加上 hash,上線後不走緩存加載最新的代碼。vuex
{ output: { path: path.join(__dirname, './dist'), filename: 'static/[name].[chunkhash:8].bundle.js', chunkFilename: 'static/[name].[chunkhash:8].bundle.js', }, }
作完第三方庫及公共代碼分割,打包後生成的文件以下:vue-cli
assets by path static/*.js 138 KiB asset static/vendor.4391b08b.bundle.js 133 KiB [emitted] [immutable] [minimized] (name: vendor) (id hint: default) asset static/main.0d6dab3a.bundle.js 3.9 KiB [emitted] [immutable] [minimized] (name: main) asset static/runtime.bdaa3432.bundle.js 1.1 KiB [emitted] [immutable] [minimized] (name: runtime) asset static/common.3f62940b.bundle.js 204 bytes [emitted] [immutable] [minimized] (name: common) asset index.html 537 bytes [emitted] asset static/main.acdc2841.bundle.css 127 bytes [emitted] [immutable] [minimized] (name: main)
咱們能夠看到代碼分割到了不一樣的文件中,vender.js 包含了全部的第三方庫,main.js 包含了咱們各個頁面的業務邏輯,公共代碼在 common 中,runtime 包含了運行時代碼,這樣代碼就分散到了不一樣的文件中,各司其職,且有利於同時進行加載。
可是 main.js 仍是包含了多個頁面的代碼,若是隻是進入首頁的話,其它頁面的代碼就是多餘的,接下來再進行優化。
這一個比較容易處理,只需改變下路由配置便可,以 () => import(path)
的方式加載頁面組件:
const routes = [ { path: '/', // component: Home, component: () => import('./pages/Home'), }, { path: '/todos', // component: Todos, component: () => import('./pages/Todos'), }, { path: '/about', // component: About, component: () => import('./pages/About'), }, { path: '/404', // component: NotFound, component: () => import('./pages/NotFound'), }, { path: '*', redirect: '/404', }, ];
此時打包會看到多了不少文件,這是把不一樣頁面的代碼分割到了不一樣的 JS 文件中,只有訪問對應的頁面纔會加載相關的代碼。
assets by path static/*.js 142 KiB asset static/vendor.4391b08b.bundle.js 133 KiB [emitted] [immutable] [minimized] (name: vendor) (id hint: default) asset static/runtime.07c35c52.bundle.js 3.99 KiB [emitted] [immutable] [minimized] (name: runtime) asset static/821.7ba5112d.bundle.js 1.89 KiB [emitted] [immutable] [minimized] asset static/main.1697fd27.bundle.js 1.68 KiB [emitted] [immutable] [minimized] (name: main) asset static/820.de28fd7b.bundle.js 562 bytes [emitted] [immutable] [minimized] asset static/646.a902d0eb.bundle.js 406 bytes [emitted] [immutable] [minimized] asset static/114.26876aa2.bundle.js 402 bytes [emitted] [immutable] [minimized] asset static/common.3f62940b.bundle.js 204 bytes [emitted] [immutable] [minimized] (name: common) assets by path static/*.css 127 bytes asset static/main.beb1183a.bundle.css 75 bytes [emitted] [immutable] [minimized] (name: main) asset static/821.cd9a22a5.bundle.css 52 bytes [emitted] [immutable] [minimized] asset index.html 537 bytes [emitted]
固然,這個地方可能會有爭議,爭議的地方就是:「頁面進入時就把全部頁面的代碼都下載下來,再進入其它頁面不是更快嗎?」。這就取決於項目狀況了,看是着重於頁面秒開,仍是着重於頁面切換體驗。若是着重於秒開的話,配合 SSR 處理效果會更好。
若是對於頁面打開速度或性能有更高的要求,還能夠作更細粒度的代碼分割,好比頁面中功能模塊的懶加載。
這裏以一個點擊按鈕時加載相應的組件爲例,進行代碼演示:
這裏有一個 Load Lazy Demo
按鈕,點擊時才加載 LazyComponent
組件,LazyComponent
組件並無什麼特別之處,寫法跟普通組件同樣。
<template> <button @click="loadLazyDemo">Load Lazy Demo</button> <template v-if="showLazyComponent"> <lazy-component /> </template> </template>
這裏經過一個 showLazyComponent
控制組件的顯示,當點擊按鈕時,把 showLazyComponent
置爲 true,而後就加載 LazyComponent 對應的代碼了。其實關鍵仍是經過 () => import(path)
的方式引入組件。
<script> export default { data() { return { showLazyComponent: false, }; }, methods: { loadLazyDemo() { this.showLazyComponent = true; }, }, components: { 'lazy-component': () => import('../components/LazyComponent'), }, }; </script>
OK,以上就是我在 Vue 項目中作的代碼分割的相關內容。