做移動(dòng)端數(shù)據(jù)可視化產(chǎn)品,需要封裝echarts圖表做子組件,并兼容原先pc端api請(qǐng)求格式,還引入了地圖數(shù)據(jù),支持省份下鉆。完成所有功能后,vendor大小2.49M,build速度59s,首屏加載速度和webpack打包速度都很慢。
webpack: 3.6 echarts:4.1


優(yōu)化1:echart按需加載
(echart整體畫(huà)圖數(shù)據(jù)包700KB,比highcharts和f2要大,技術(shù)選型上可以考慮一下其他方案。)
從全局引用,優(yōu)化為按需引用。引用echarts壓縮過(guò)的省份地圖的js數(shù)據(jù),json數(shù)據(jù)會(huì)大一些,還需要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') // 引入中國(guó)地圖數(shù)據(jù)
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')
...
優(yōu)化2:路由懶加載,vue異步組件,vendor分包,首屏加載速度加快。
將路由頁(yè)面拆分chunk打包,所有路由頁(yè)面打包在cube中。
按需加載省市js數(shù)據(jù),打包到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;
分包結(jié)果:
npm run build --report


訪問(wèn)一般頁(yè)面加載cube,有echarts圖表加載echarts chunk,有省份地圖數(shù)據(jù)下鉆加載province chunk。nginx開(kāi)啟了gzip壓縮,在webpack中也可以配置。

優(yōu)化3:webpack打包速度
分包后build速度41s,先用webpack-visualizer-plugin分析一下當(dāng)前打包的狀況。
const Visualizer = require('webpack-visualizer-plugin')
new Visualizer({
filename: './statistics.html'
}),

echarts 打包占了整個(gè)打包時(shí)長(zhǎng)的71.3%,map地圖的js數(shù)據(jù)占打包時(shí)長(zhǎng)的28.5%。這些地圖數(shù)據(jù)包括常規(guī)的vue、vue-loader等不會(huì)變化,想把他們分離出來(lái),不用每次都打包。
開(kāi)發(fā)環(huán)境:
熱更新
生產(chǎn)環(huán)境:
配置CommonsChunkPlugin
加速文件搜索
配置 resolve.modules
設(shè)置 test & include & exclude
使用并行壓縮插件 webpack-parallel-uglify-plugin
配置externals(cdn)(會(huì)增加首屏加載時(shí)長(zhǎng))
DllPlugin和DllReferencePlugin (會(huì)加載首屏加載時(shí)長(zhǎng))
使用HappyPack來(lái)加速構(gòu)建
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')
})
//這個(gè)主要是將生成的vendor.dll.js文件加上hash值插入到頁(yè)面中。解決不同環(huán)境下的路徑問(wèn)題。
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版本。
報(bào)錯(cuò):TypeError: Cannot read property 'compilation' of undefined

dll真是快的起飛啊,build時(shí)間從41s降低到19s。


生成的vendor.dll.js放在index.html會(huì)被首屏加載,但把太多的第三方依賴都打包進(jìn)去,會(huì)影響首屏加載的速度。但是不放進(jìn)去會(huì)影響webpack的打包速度。
省份數(shù)據(jù)不用打包到index頁(yè)面的vendor里,異步加載。
vendor是vue等基礎(chǔ)組件,vendor2是echarts。


減少webpack打包時(shí)間,省份數(shù)據(jù)還編譯。
加了cache-loader做緩存,用了only-if-changed-webpack-plugin插件,發(fā)現(xiàn)全局不動(dòng)不編譯,有一點(diǎn)動(dòng)都編譯。還和 html-webpack-plugin 有沖突。
巨大的echarts讓人頭大。
一開(kāi)始想讓打包好的dll,可以不首屏加載,動(dòng)態(tài)加載。
發(fā)現(xiàn)有一個(gè)scriptjs的插件。
let scriptjs = require('scriptjs')
// scriptjs不能單獨(dú)引用require
let r = scriptjs(echart_prefix + 'dist/echarts.min.js', () => {
scriptjs(echart_prefix + 'map/js/china.js') // 引入中國(guó)地圖數(shù)據(jù)
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、地圖數(shù)據(jù)拆到cdn里,scriptjs按需加載。



總結(jié):
程序猿學(xué)好英語(yǔ)是件很重要的事情,github看的讓人頭大。
小師傅好厲害,哈哈哈。
相關(guān)鏈接:
https://www.npmjs.com/package/scriptjs
https://github.com/webpack/webpack/issues/3115