Vue 项目打包优化 - CDN、配置分离、路由懒加载

前言

Vue 项目打包优化 - CDN、配置分离、路由懒加载。
本例项目是写的一个管理系统,项目使用的库版本:

  • vue-cli: @3.11.0
  • vue: @2.6.10
  • vue-router: @3.1.3

另外本项目还用到了 axios、echarts、element-ui、nprogress、vue-quill-editor等,不优化直接打包会非常大。优化目的:

  1. 配置分离:开发模式使用本地资源,生产模式打包资源使用 CDN 引入。
  2. 路由懒加载:js包过大会影响页面加载速度,路由被访问才加载对应组件更加高效。
生成打包报告

有两种方式:

  1. 命令行生成打包报告(build命令后加 --report)
  2. 利用 vue ui 工具(推荐,非常直观)
命令行生成报告
npm vue-cli-service build --report

#或者在 package.json 的 build 命令后添加 --report,然后再
npm run build

此方法会自动在 dist 目录下生成 report.html,打开如下:


reprot.png
vue ui 图形化界面生成报告

vue-cli3 中自带了 vue ui 图形化界面,用于创建和管理项目。

# 启动 Vue UI
vue ui

【导入项目】-【任务】-【build】- 【运行】,效果如下:


vue ui.png

优化一:配置分离

从打包报告中可以看出,依赖项大小还是挺大的,如 element-ui、echarts等,我们可以通过配置分离,在生产模式打包时不要打包这些依赖以及一些 CSS 本地资源,在 html 模版中引入依赖的 CDN 资源。国内的CDN服务推荐使用 BootCDN

使用 CDN 的好处有以下几个方面:

  • 加快打包速度。分离公共库以后,每次重新打包就不会再把这些打包进 vendors 文件中。
  • CDN减轻自己服务器的访问压力,并且能实现资源的并行下载。浏览器对 src 资源的加载是并行的(执行是按照顺序的)。

需要了解的知识有:

  1. webpack-externals: 防止某些 import 的包打包到 bundle 中。
  2. vue-cli3 中的 chainWebpack链式操作,使用指南webpack-chain

分离配置

vue-cli3 中需要添加 vue.config.js 配置文件。

  1. 给不同模式定义不同的入口文件
  2. 需要 CDN 引入的依赖添加到 externals 中
  3. 给 htmlWebpackPlugin 添加一个参数变量来控制 html 模版生成
// vue.config.js
module.exports = {
  chainWebpack: config => {
    // 生产模式
    config.when(process.env.NODE_ENV === 'production', config => {
      // 生产模式加载 main-prod 入口文件
      config.entry('app').clear().add('./src/main-prod.js')
      // CDN - externals
      config.set('externals', {
        vue: 'Vue',
        'vue-router': 'VueRouter',
        axios: 'axios',
        lodash: '_',
        echarts: 'echarts',
        nprogress: 'NProgress',
        'vue-quill-editor': 'VueQuillEditor'
      })
      // 首页自定义,添加一个变量来控制html模版,是否加载cdn资源。
      config.plugin('html').tap(args => {
        args[0].isProd = true
        return args
      })
    })
    // 开发模式
    config.when(process.env.NODE_ENV === 'development', config => {
      // 开发模式加载 main-dev 入口文件
      config.entry('app').clear().add('./src/main-dev.js')
      // 首页自定义
      config.plugin('html').tap(args => {
        args[0].isProd = false
        return args
      })
    })
  }
}

注:vue-cli 中 html 模版是由 html-webpack-plugin 处理的,所以可以通过给插件属性添加一个变量,并且 html 模版可以通过插值的方式,根据变量来决定是否输出 CDN 资源。

定义不同的入口文件

原入口文件 main.js 复制两份分别命名 main-dev.js、main-prod.js。
在 main-prod.js 注释或删除 CDN 引入的 CSS。

// 生产模式入口文件 main-prod.js

// css - 生产模式cdn引入
// import 'quill/dist/quill.core.css'
// import 'quill/dist/quill.snow.css'
// import 'quill/dist/quill.bubble.css'
// import 'nprogress/nprogress.css'

// elementUI 按需引入,生产模式 cdn 引入
// import './plugins/element.js'

html 模版引入 CDN

public/index.html 引入 external 忽略的依赖和入口文件删除的 CSS 对应的 CDN 链接。

<title><%= htmlWebpackPlugin.options.isProd ? '' : 'DEV - ' %>管理系统</title>
<!-- 生产模式才加载 CDN -->
<% if(htmlWebpackPlugin.options.isProd) { %>
  <!-- nprogress进度条 css -->
  <link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css">
  <!-- vue-quill-editor富文本编辑器 css -->
  <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.7/quill.core.min.css">
  <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.7/quill.snow.min.css">
  <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.7/quill.bubble.min.css">
  <!-- elementUI css -->
  <link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.13.0/theme-chalk/index.css">
  <!-- js -->
  <script src="https://cdn.staticfile.org/vue/2.6.10/vue.min.js"></script>
  <script src="https://cdn.staticfile.org/vue-router/3.1.3/vue-router.min.js"></script>
  <script src="https://cdn.staticfile.org/axios/0.19.0/axios.min.js"></script>
  <script src="https://cdn.staticfile.org/lodash.js/4.17.13/lodash.min.js"></script>
  <script src="https://cdn.staticfile.org/echarts/4.6.0/echarts.min.js"></script>
  <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
  <script src="https://cdn.staticfile.org/quill/1.3.7/quill.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.6/dist/vue-quill-editor.min.js"></script>
  <script src="https://cdn.staticfile.org/element-ui/2.13.0/index.js"></script>
<% } %>

如上设置模版,即可通过变量 isProd 在不同模式下是否加载 CDN 资源,以及不同模式下有不同的 title。


优化二:路由懒加载

如上操作后可以一定程度减少打包大小,但此时所有组件仍会被打包到同一个 chunk-vendors.js 中,如果组件过多打包数据仍然会很大,从而影响首屏加载时间。

路由懒加载可以将代码分割打包,且仅当路由被访问时才加载对应组件。

最简单方法:

// import Login from '../views/Login.vue'
const Login = () => import('../views/Login.vue')

以上方式有个缺点,会将每个路由组件单独打包。可以通过魔法注释将部分组件打包在同个 chunk 中,相同chunkName为一个包。如下

// src/router/index.js

// import Login from '../views/Login.vue'
// import Home from '../views/Home.vue'
// import Welcome from '../components/home/Welcome.vue'
// import Users from '../components/users/Users.vue'
// import RightsList from '../components/rights/RightsList.vue'
// import RolesList from '../components/rights/RolesList.vue'
// import GoodsCategories from '../components/goods/GoodsCategories.vue'
// import GoodsList from '../components/goods/GoodsList.vue'
// import CategoriesParams from '../components/goods/CategoriesParams.vue'
// import AddGoods from '../components/goods/AddGoods.vue'
// import OrdersList from '../components/orders/OrdersList.vue'
// import StatisticsReports from '../components/statistics/StatisticsReports.vue'

// 路由懒加载
const Login = () => import(/* webpackChunkName: "Index" */ '../views/Login.vue')
const Home = () => import(/* webpackChunkName: "Index" */ '../views/Home.vue')
const Welcome = () => import(/* webpackChunkName: "Index" */ '../components/home/Welcome.vue')

const Users = () => import(/* webpackChunkName: "Users" */ '../components/users/Users.vue')

const RightsList = () => import(/* webpackChunkName: "Rights" */ '../components/rights/RightsList.vue')
const RolesList = () => import(/* webpackChunkName: "Rights" */ '../components/rights/RolesList.vue')

const GoodsCategories = () => import(/* webpackChunkName: "Goods" */ '../components/goods/GoodsCategories.vue')
const GoodsList = () => import(/* webpackChunkName: "Goods" */ '../components/goods/GoodsList.vue')
const CategoriesParams = () => import(/* webpackChunkName: "Goods" */ '../components/goods/CategoriesParams.vue')
const AddGoods = () => import(/* webpackChunkName: "Goods" */ '../components/goods/AddGoods.vue')

const OrdersList = () => import(/* webpackChunkName: "Orders" */ '../components/orders/OrdersList.vue')

const StatisticsReports = () => import(/* webpackChunkName: "Statistics" */ '../components/statistics/StatisticsReports.vue')
结果


另外:如果服务器开启 Gzip,在 vue.config.js 配置中使用 Gzip 压缩,能得到更好的压缩效果,如何开启这里就不赘述了,自行 Google 吧。

参考:https://www.cnblogs.com/slightFly/p/12485129.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容