Vue 的打包优化之路

Vue的打包优化之路

场景分析

一个结构简单 依赖蛮多的可视化项目,用到的库有

  1. vue + vue-router + vuex + axios
  2. echarts + 全省份地图文件 + 中国地图文件
  3. elementui
  4. moment(后面被date-fns代替)
  5. lodash lodash-decorator(用到了装饰器)

ECharts的JSON地图文件占了很大一部分,大概有1.96MB gzip以后900KB,这一部分是没有办法做处理的。然后ECharts也应该使用按需加载

接着是依赖的一些公共库,比如Vue全家桶,这部分是可以提取到 cdn 的

最后是一些类似 lodash moment的工具库,可能只引用到了部分功能,但是默认会加载全部包,这样是不划算的。lodash moment默认都不支持 three-shake 因此需要手动按需加载或者使用更小体积的库。

先来看看默认没有经过优化的打包分析

默认配置

只做了简单的异步路由加载,各种库均没有按需引用


vue-bundle-1.png

这一个地方在体积处理上没有更好的优化办法

vue-bundle-2.png

这里可以看到ECharts的库占了很大一部分 然后是 moment elementui这些库

vue-bundle-3.png

初步优化

因为业务的需求 需要用到地图相关信息所以这部分体积是没法减少的。但是并不是初次进入页面就需要加载这些文件。我们知道 ECharts 是通过 ECharts.registerMap('china', China) 注册地图的。 这个注册是可选的,并且仅仅是地图相关的组件会用到,因此我们单独封装这个地图组件,在组件内部注册,并通过异步路由切割,达到分片的目的

//...
import China from 'echarts/map/json/china.json'
import provinceList from './provinceList.json'

// 注册地图
ECharts.registerMap('china', China)
provinceList.forEach(pro => {
  const map = require('echarts/map/json/province/' + pro.path)
  ECharts.registerMap(pro.py, map)
})

@Component
export default class AreaChart extens Vue {}
//...

另外一个优化点在于默认引入 ECharts 是引入全部的 import * as ECharts from 'echarts' 我们只需要部分组件,因此单独定义一个echarts文件, 这样我们所有引用 ECharts的文件,都改为引用这个文件就实现了按需加载

# echarts.ts
import ECharts from 'echarts/lib/echarts'

import 'echarts/lib/chart/bar'
import 'echarts/lib/chart/line'
import 'echarts/lib/chart/pie'
import 'echarts/lib/chart/funnel'
import 'echarts/lib/chart/scatter'
import 'echarts/lib/component/title'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/axisPointer'
import 'echarts/lib/component/visualMap'
import 'echarts/lib/component/markLine'
import 'echarts/lib/component/markPoint'
import 'echarts/lib/component/markArea'
import 'echarts/lib/component/geo'

export { ECharts }

在 vendors 中还有 moment 这个很大其实我只用到了moment(current).subtract(1, 'day').format('YYYY-MM-DD') 这几个基本功能, 这样的使用引入全部 moment 是不值得,因此改为了 date-fns 然后按需引入了部分功能。上面代码等价转换为 format(subDays(parse(now), 8), 'YYYY-MM-DD') 然而我们只需要按需引入这三个函数就ok了

vue-bundle-4.png
vue-bundle-5.png
vue-bundle-6.png

moment 也被替换为了date-fns

vue-bundle-8.png
vue-bundle-9.png

CDN进一步优化

在初步优化完成后,我们发现 vue 全家桶以及 elemenUI i仍然占了很大一部分 vendors 体积,这部分代码是不变的,但会随着每次 vendor 打包改变 hash 重新加载。我们可以使用 cdn 剔除这部分不经常变化的

另外一方面我们的页面很小,但是因为异步路由加载分割了好几块。小碎片的加载也是影响浏览器性能要素之一,我们通过更改打包策略解决

使用 webpack-cdn-plugin 插件

WebpackCDNPlugin

过去我们外部引入 CDN 需要手动编写 index.html 模板,在里面指定加载的版本,通过这个插件就能自动的把指定的公共库写入到 index.html 模板里,目前的文档有坑,我已经提了PR

需要注意的是,通过CDN引入,在使用 VueRouter Vuex ElmentUI 的时候要改下写法。CDN会它们挂载到window上,因此不再使用 Vue.use(xxx)

import Vue from 'vue'
import VueRouter from 'vue-router'

if (!window.VueRouter) Vue.use(VueRouter)

更改打包策略

通过webpack-chunk-name 合并一些包

const A1 = () => import(/* webpackChunkName: "A" */ '@/views/A1')
const A2 = () => import(/* webpackChunkName: "A" */ '@/views/A2')
const A3 = () => import(/* webpackChunkName: "A" */ '@/views/A3')

[图片上传失败...(image-61ee85-1544087237201)]

剔除全家桶以后,剩下的需要首次加载 vendor 就很小了

优化后的数据

(只显示gzip大小) Vendors Echarts Moment or date-fns
默认打包 601.48kb 195.41kb 66.45kb
初步优化 410.66kb 104.87kb 7kb
CDN优化 206.78kb 104.85kb 7kb

优化的意义与思路

我们优化的目的除了写KPI和升职答辩外,最主要的就是提升用户的体验。

提升首次访问的渲染速度。影响首次渲染速度除了代码上的优化之外就是网络传输的速度。

代码上能优化的地方不多,主要考虑的就是网络传输。

一方面是要考虑打包后的体积,从这个维度来考虑,我们可以通过按需引用以及 CDN。按需引用方便理解效果也比较显著,而使用 CDN 的好处有以下几个方面

  1. 抽离出公共包避免每次打包加快打包速度。分离公共库以后,每次重新打包就不会再把这些打包进 vendors 文件中,即使更改了 hash 用户也只需要获取改变的部分
  2. cdn 具有复用的效果。网站A B 都引用同一份资源(版本路径都相同),那么用户访问了A网站以后浏览器缓存了这部分资源,访问B网站时就可以直接复用,减少不必要的加载
  3. CDN减轻自己服务器的访问压力,并且能实现资源的并行下载。浏览器对 src 资源的加载是并行的(执行是按照顺序的), 通过不同的域名加载资源提高很多的加载速度

另一方面应该减少需要加载包的数量,特别是体积较小的碎片包。在初次优化之后,我们发现很多自己写的组件只占了很小的体积,却仍然分割成了独立的块。我们便可以将这些碎片包打包成一个包,减少请求次数。

最后

从没有优化到最后使用CDN优化,可以显著的发现打包后的文件大小减少。如果我们的应用有很高的 pv 每一点优化到最后都能节省很多的流量。从数值上看到优化的效果,对于程序员来说也是蛮有成就感的。
以上就是关于打包优化的一点分享

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

推荐阅读更多精彩内容

  • 谈及如今欣欣向荣的前端圈,不仅有各类框架百花齐放,如Vue, React, Angular等等,就打包工具而言,发...
    晚晴幽草阅读 2,973评论 0 15
  • 刚刚下铺和我说了一件事:我和下铺在考场上是前后桌关系,我下铺说,做我旁边的那个这次高数95+,他看的都是他前...
    Alianna阅读 374评论 0 0
  • 吃过午饭,忙了一上午的奶奶终于肯歇上一会儿,在我们还没开始睡午觉之前的这一段时间里,这是我最期待的时光。 外面的阳...
    一个好士兵阅读 275评论 0 3
  • curl http://169.254.169.254/latest/meta-data/public-ipv4
    金琥阅读 240评论 0 1