做移动端数据可视化产品,需要封装echarts图表做子组件,并兼容原先pc端api请求格式,还引入了地图数据,支持省份下钻。完成所有功能后,vendor大小2.49M,build速度59s,首屏加载速度和webpack打包速度都很慢。
webpack: 3.6 echarts:4.1
优化1:echart按需加载
(echart整体画图数据包700KB,比highcharts和f2要大,技术选型上可以考虑一下其他方案。)
从全局引用,优化为按需引用。引用echarts压缩过的省份地图的js数据,json数据会大一些,还需要registerMap。
import echarts from 'echarts/lib/echarts'
import 'echarts/lib/chart/bar'
import 'echarts/lib/component/tooltip'
require('node_modules/echarts/map/js/china.js') // 引入中国地图数据
require('node_modules/echarts/map/js/province/anhui.js')
require('node_modules/echarts/map/js/province/aomen.js')
require('node_modules/echarts/map/js/province/beijing.js')
require('node_modules/echarts/map/js/province/chongqing.js')
require('node_modules/echarts/map/js/province/fujian.js')
...
优化2:路由懒加载,vue异步组件,vendor分包,首屏加载速度加快。
将路由页面拆分chunk打包,所有路由页面打包在cube中。
按需加载省市js数据,打包到province中。
封装echart子组件,打包到echarts中。
const Demo = () => import(/* webpackChunkName: 'cube' */ '@/components/pages/demo/demo')
const Notfound = () => import(/* webpackChunkName: 'cube' */ '@/components/pages/content/notfound')
let r = require.ensure([], function() {
require('node_modules/echarts/map/js/province/anhui.js')
require('node_modules/echarts/map/js/province/aomen.js')
...
}, 'province')
r.then(
res => {
this.drawChart()
}
)
import Vue from 'vue'
const Chart = Vue.component('Chart', () => import(/* webpackChunkName: 'echarts' */'@/utils/echarts.vue'))
export default Chart;
分包结果:
npm run build --report
访问一般页面加载cube,有echarts图表加载echarts chunk,有省份地图数据下钻加载province chunk。nginx开启了gzip压缩,在webpack中也可以配置。
优化3:webpack打包速度
分包后build速度41s,先用webpack-visualizer-plugin
分析一下当前打包的状况。
const Visualizer = require('webpack-visualizer-plugin')
new Visualizer({
filename: './statistics.html'
}),
echarts 打包占了整个打包时长的71.3%,map地图的js数据占打包时长的28.5%。这些地图数据包括常规的vue、vue-loader等不会变化,想把他们分离出来,不用每次都打包。
开发环境:
热更新
生产环境:
配置CommonsChunkPlugin
加速文件搜索
配置 resolve.modules
设置 test & include & exclude
使用并行压缩插件 webpack-parallel-uglify-plugin
配置externals(cdn)(会增加首屏加载时长)
DllPlugin和DllReferencePlugin (会加载首屏加载时长)
使用HappyPack来加速构建
webpack.dll.conf.js:
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
vendor: [
'axios',
'vue-router',
'vue'
]
},
output: {
path: path.resolve(__dirname, '../static/js'),
filename: '[name].dll.js',
library: '[name]_library'
},
plugins: [
new webpack.DllPlugin({
path: path.resolve('../static', '[name]-manifest.json'),
name: '[name]_library'
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
};
webpack.prod.conf.js:
new webpack.DllReferencePlugin({
manifest: require('../static/vendor-manifest.json')
})
//这个主要是将生成的vendor.dll.js文件加上hash值插入到页面中。解决不同环境下的路径问题。
new AddAssetHtmlPlugin([{
filepath: path.resolve(__dirname,'../dist/static/js/vendor.dll.js'),
outputPath: utils.assetsPath('js'),
publicPath: path.posix.join(config.build.assetsPublicPath, 'static/js'),
includeSourcemap: false,
hash: true,
}]),
package.json
"scripts": {
"build:dll": "webpack --config build/webpack.dll.conf.js"
}
npm run build:dll
npm run build
webpack 3.x版本,add-asset-html-webpack-plugin需要2.1.3版本。
报错:TypeError: Cannot read property 'compilation' of undefined
dll真是快的起飞啊,build时间从41s降低到19s。
生成的vendor.dll.js放在index.html会被首屏加载,但把太多的第三方依赖都打包进去,会影响首屏加载的速度。但是不放进去会影响webpack的打包速度。
省份数据不用打包到index页面的vendor里,异步加载。
vendor是vue等基础组件,vendor2是echarts。
减少webpack打包时间,省份数据还编译。
加了cache-loader做缓存,用了only-if-changed-webpack-plugin插件,发现全局不动不编译,有一点动都编译。还和 html-webpack-plugin 有冲突。
巨大的echarts让人头大。
一开始想让打包好的dll,可以不首屏加载,动态加载。
发现有一个scriptjs的插件。
let scriptjs = require('scriptjs')
// scriptjs不能单独引用require
let r = scriptjs(echart_prefix + 'dist/echarts.min.js', () => {
scriptjs(echart_prefix + 'map/js/china.js') // 引入中国地图数据
let map_province = ['anhui', 'aomen', 'beijing', 'chongqing', 'fujian', 'gansu', 'guangdong', 'guangxi', 'guizhou', 'hainan', 'hebei', 'heilongjiang', 'henan', 'hubei', 'jiangsu', 'jiangxi', 'jilin', 'liaoning', 'neimenggu', 'ningxia', 'qinghai', 'shandong', 'shanghai', 'shanxi1', 'sichuan', 'taiwan', 'tianjin', 'xianggang', 'xinjiang', 'xizang', 'yunnan', 'zhejiang']
let map_province_data = []
for (let x in map_province) {
map_province_data.push(echart_prefix + 'map/js/province/' + map_province[x] + '.js')
}
scriptjs(map_province_data, () => {
this.drawChart()
})
})
把echarts、地图数据拆到cdn里,scriptjs按需加载。
总结:
程序猿学好英语是件很重要的事情,github看的让人头大。
小师傅好厉害,哈哈哈。
相关链接:
https://www.npmjs.com/package/scriptjs
https://github.com/webpack/webpack/issues/3115