vue项目打包后文件总是很大,首先得确定到底是哪里导致了首屏渲染如此之慢?
打开Chrome Network面板,勾上Disable cache选项,刷新页面观察资源加载情况,发现罪魁祸首就是webpack打包生成的app.js和vendor.js,其中vendor.js大小达到了1.2M,下载时间超过20秒,app.js也快到1M,而manifest.js不是很大。vendor.js主要是把node_modules里所用到的modules都合并成一个js了,所以比较大.而我们也希望将业务代码和第三方引用分开打包。manifest.js包含webpack的runtime代码和module manifest代码,作用是防止修改了代码但是没有修改第三方库文件导致第三方库文件也打包的问题。
通过查一些资料,我们从以下几个方面去优化:
- 开启gzip压缩功能
- 引入CDN
- 路由懒加载
- 某些第三方组件按需加载而不是全部加载
- 较小的图片资源用base64嵌入src中,减少http请求
1.gzip压缩
这个是需要后端配合设置的,首先我们来了解一下什么是gzip?
- gzip是GNUzip的缩写,最早用于UNIX系统的文件压缩。
- HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术,web服务器和客户端(浏览器)必须共同支持gzip。
- 目前主流的浏览器,Chrome,firefox,IE等都支持该协议。
- 常见的服务器如Apache,Nginx,IIS同样支持,gzip压缩效率非常高,通常可以达到70%的压缩率,也就是说,如果你的网页有30K,压缩之后就变成了9K左右
我后端是用的koa,开启gzip非常简单,首先npm install compression安装中间件,然后在app.js里添加use使用即可:
var compression = require('compression');
var app = express();
app.use(compression())
重启服务,观察网络面板里面的response header,如果看到如下红圈里的字段则表明gzip开启成功
2.引入CDN
CDN(内容分发网络),是一种公共服务,他本身有很多台位于不同地域、接入不同运营商的服务器,而所谓的使用CDN实质上就是让CDN作为网站的门面,用户访问到的是CDN服务器,而不是直接访问到网站。由于CDN内部对TCP的优化、对静态资源的缓存、预取,加上用户访问CDN时,会被智能地分配到最近的节点,降低大量延迟,让访问速度可以得到很大提升一个原则是尽量将比较大的第三方库放到cdn上去以减少请求时间,
在我的项目中,我将vue,vuex,vue-router,vant都放到了cdn上,具体操作是打开BootCDN 或者https://www.jsdelivr.com/然后搜索关键字并copy链接粘贴到index.html的body闭合标签前,如下图
注意选取min.js(体积最小),然后在webpack.base.conf.js里设置externals选项,目的是不打包这些选项,由于index.html中script的引入,比如vue就会有一个全局变量Vue存在,因此这里external的value就是Vue
externals: {
'vue': 'Vue', // 左侧vue是我们自己引入时候要用的,右侧是开发依赖库的主人定义的不能修改
'vue-router': 'VueRouter',
'axios': 'axios',
'qs': 'Qs',
'vant': 'vant',
'es6-promise': 'ES6Promise',
'vue-baidu-map': 'VueBaiduMap',
'weixin-js-sdk': 'jWeixin',
},
cdn使用后优势是巨大的,观察network面板,时间几乎都在50ms以下
3.路由懒加载
路由懒加载也叫延迟加载,即在需要的时候进行加载,随用随载。像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,时间过长,会出现长时间的白屏,即使做了loading也是不利于用户体验,而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时。
Vue官网的示例如下,采用异步组件和webpack的code-splitting结合
因此在项目中,进入router的index.js中,将原来的import Comp from '@/component/xxx'改为如下,vue-router的配置项还是保持不变
{
path: '/index',
name: "index",
component: resolve => require(['../page/home/Index.vue'], resolve),
meta: {title: '首页'}
},
{
path: '/personal',
name: 'personal',
component: resolve => require(['../page/personal/PersonalCenter.vue'], resolve),
meta: {title: '我的'}
},
4.第三方按需加载
这个在另一个项目里面用到了,项目里面使用的echarts,只用到了一个柱状图组件,其余的都没有用到,但是这样import后打包时却会把整个echarts都打入包内,造成空间浪费
import echarts from 'echarts
因此只需要import用到的组件即可,如下,这样就可以减少很多不必要的体积
import echarts from 'echarts/lib/echars'
import 'echarts/lib/chart/bar'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/title'
5.图片转base64
小图片可以转为base64字符串然后嵌入img的src中,节省http请求数量,webpack中用url-loader处理,limit控制了图片转base64的阈值,小于该值就转base64
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
6.优化后性能
经过上述优化后,首页打开时间迅速下降,DomContentLoaded用时不到10s,load完全加载用时不到4s,耗时较多的是几张背景大图,本来体积就大,后续考虑放到cdn上。
ps:webpack-bundle-analyzer是神器,能够有效分析出包占用的体积情况~下图是最终优化后的包组成结构图,最初打包的结构图比下图大很多,主要多了vue,vue-router,vuex模块。
整个优化就完成啦~
恭喜你,又掌握了一个新技能~
关注微信公众号【前端FE】了解更多