最近在做项目时,测试提出了在App端的H5项目入口加载时间过长,白屏等待过久,需要优化的问题,于是着手开始分析:
通过访问线上环境,结合Chrome devtool中Network和Performance功能可以具体分析整个白屏的耗时主要在哪一块儿
animate.css, mini-ui.css
的请求耗时最长。animate.css
由于使用的是第三方CDN(国外服务器)所有请求时间相对较长,所以如果必须要用animate.css那么可以下载下来作为本地资源,也可以使用国内CDN,或者不用animate.css,而是针对使用到的几个CSS动画,直接自己造轮子由于mint-ui在原项目中使用的是全局引用的方式,这才导致打包资源过大,css单独请求耗时过长的问题,所以主要解决方案是
按需引入mint-ui
,借助babel-plugin-component,
我们可以只引入需要的组件,以达到减小项目体积的目的。
npm install babel-plugin-component -D
{
"presets": [
["env", { "modules": false }],
"stage-2"
],
"plugins": ["transform-runtime",["component", [
{
"libraryName": "mint-ui",
"style": true
}
]]],
"comments": false,
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
}
}
}
import Vue from 'vue'
import { Button, Cell } from 'mint-ui'
import 'mint-ui/lib/style.min.css' // 引用CSS
import App from './App.vue'
Vue.component(Button.name, Button)
Vue.component(Cell.name, Cell)
/* 或写为
* Vue.use(Button)
* Vue.use(Cell)
*/
new Vue({
el: '#app',
components: { App }
})
import Vue from 'vue'
var Popup = Vue.component('mt-popup')
var Swipe = Vue.component('mt-swipe')
var SwipeItem = Vue.component('mt-swipe-item')
export default {
name:'my-component',
components:{
Popup,
Swipe,
SwipeItem
}
}
此按需引入方案也同样适用于其他第三方UI组件库
图片小图通过webpack可以直接转为base64,而大图可以通过压缩或者换格式的方式来优化,这里推荐一个好用的图片压缩工具,工具:tinyPNG,如下是图片转换前后对比
在完成了上述优化以后,下面着重关注下webpack打包后生成的文件大小,看还有没有可以优化的余地。由于项目中已经通过
路由按需加载
的方式来做了功能拆分,所以通过webpack打包后生成了很多分散的js文件,如下图:
通过上图分析可以知道打包后有几个文件相对较大,vendor.js都知道是第三方库文件打包形成,之前通过mint-ui按需加载会有一定的变化,后面记录。这里着重看另两个带hash的js文件,这里并看不出来它为什么这么大,所以这里需要用到webpack打包分析工具来做进一步的打包文件分析:webpack-bundle-analyzer
它的作用如下图,即在打包后生成打包文件大小分析图,方便我们更加直观的看到文件大小和引用情况
npm intall -D webpack-bundle-analyzer
webpack.pro.conf.js
. (这里由于只是用于生产打包分析且是通过vue-cli生成的项目框架)var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
// ...
plugins:[
new BundleAnalyzerPlugin()
]
}
npm run build
,(webpack默认会在打包完成时生成分析图)在vue-cli3中,webpack配置向不再对外暴露,而是集中在vue.config.js中进行修改,下面是新的配置项
// vue.config.js
module.exports={
//...
chainWebpack: config => {
config
.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
},
}
通过上面的分析图可以看到打包文件过大是由于第三方库引用的问题,如
mint-ui, moment.js, echarts.js,zrender,Vue
等
1. mint-ui按需加载改造
通过之前的按需引用加载后,再次webpack打包可以看到vendor.js中mint-ui
包的大小明显缩小
2. 第三方库引用优化-使用CDN
对于像Vue,Vue-router,echarts等都可以使用CDN的方式来引入,目前使用的是Bootcdn相对其他免费CDN还是比较稳定的
// 1. 在index.html中通过CDN方式引用第三方
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
// 2.修改webpack.base.conf.js
module.exports = {
// ...
externals: {
'vue': 'Vue',
'vue-router': 'VueRouter',
},
}
通过分析图可以看到,剩下比较大的就是单文件js中引入了echarts.js, moment.js的包了,moment.js通过CDN引用方式也可以直接优化
而echarts.js由于项目中使用了一个第三方的组件库vue-charts
导致echarts被直接打包到了文件中,使用CDN的方式也无法把echarts抽离,这里采用的方式是重写图表组件,再使用CDN引入。
通过performance可以看到整个过程从发起请求拿到index.html开始(3900ms处),到FMP位置(timestamp:4569.8 ms)结束,耗时约0.669s。总结:3.5s-> 0.669s
此次优化大致用到以下几种方案:
babel-plugin-component
缩小项目打包体积)