背景
作为一个新晋菜鸟,首次独立负责搭建一个新的应用,在本地开发的时候没有注意页面加载速度慢的问题,但是部署之后发现首页加载显得非常迟钝,首屏时间4s~5s,What happened ?
首屏加载慢.png首屏作为直面用户的第一屏,其重要性不言而喻。根据百度用户体验部的研究结果,《白皮书4.0》提出,首屏内容应在1.5秒内加载完成。
移动网页首屏在2秒之内完成打开的,在移动搜索下将获得提升页面评价优待,获得流量倾斜;同时,在移动搜索页面首屏加载非常慢(3秒及以上)的网页将会被打压。
根据百度用户体验部的研究结果来看,普通用户期望且能够接受的页面加载时间在3秒以内。
于是猜测导致慢的原因可能是:
- 页面打包的文件bundle.js 860KB 加载时长4.02s;
- 页面依赖的资源文件react耗时;
优化效果
优化前后对比.png优化过程
接下来就需要对这个项目资源文件进行优化,减少体积。
优化bundle.js体积过大 860KB
-
webpack-bundle-analyzer
打包文件体积和依赖关系可视化,分析打包文件体积过大原因。
- 安装
npm install --save-dev webpack-bundle-analyzer
- 配置webpack插件:
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
if(!isProduction){ //开发环境开启
webpackConfig.plugins.push(new BundleAnalyzerPlugin({ analyzerPort: 1996 }));
}
//启动项目后会自动打开一个1996的站点。(http://127.0.0.1:1996/)
依赖模块可视化.png
可以看到我们打包后的bundle.js中的代码一部分来自node_modules文件夹中的模块,一部分来自自己写的代码,也就是src文件夹中的代码,我们应该将这些代码进行分离。
- 分离打包文件中node_modules模块和本地文件
需注意webpack4.x之前使用
CommonsChunkPlugin
;webpack4.x之后建议使用SplitChunksPlugin
。4.x之后CommonsChunkPlugin已被移除
webpack4.x之前:
旧版:http://webpack.html.cn/plugins/commons-chunk-plugin.html
vendor: [
'react',
'react-dom',
'redux',
'react-redux',
'react-router'
],
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor'],
minChunks: Infinity,
filename: 'common.bundle.js'
}),
webpack4.x之后:
optimization: {
splitChunks: {
chunks: 'initial',
automaticNameDelimiter: '.',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: 1
}
}
},
runtimeChunk: {
name: entrypoint => `manifest.${entrypoint.name}`
}
},
bundle分解后.png
- js\css压缩
webpack4.x之前
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false }
}),
// Error: webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead.
webpack4.x之后 默认压缩
image.pngQ:打包失败
https://www.jianshu.com/p/a34e93465051
TypeScript+Webpack.png
awesome-typescript-loader
修改为ts-loader
即可
- css分离
webpack4.x之前使用
extract-text-webpack-plugin
webpack4.x之后使用mini-css-extract-plugin
Q:icon出不来 页面空白
webpack打包成功 dev-server运行后又空白
排查发现是因为没有配置目录
image.png
Q:router报错 页面空白
主要是因为项目优化的同时将react-router升级到了4.x 4.x和2.x的区别将会在下一个主题分享
优化依赖资源
- React依赖区分当前环境,线上环境适应production生产版本的压缩版
- 设置缓存 在资源后拼接?cachevers=40每次会从缓存中读取
<script src="//j1.58cdn.com.cn/escstatic/abgwebsit/react.production.min.js"></script>
<script src="//j1.58cdn.com.cn/escstatic/abgwebsit/react-dom.production.min.js"></script>
<script src="//j1.58cdn.com.cn/escstatic/abgwebsit/react-redux.min.js"></script>
使用生产环境压缩版本.png
二次访问从缓存中获取.png
服务部署优化
由于该项目前期只是一个静态页,由于涉及到前端路由,因为在初期部署的时候采用的方案是通过读文件的形式匹配每次请求,并返回。
const Koa = require('koa');
const path = require('path');
const KoaStatic = require('koa-static');
const fs = require('fs');
const app = new Koa();
const home = KoaStatic(path.join(__dirname)+'./../');
app.use(home);
app.use(async (ctx, next) => {
await next();
ctx.type = 'html';
ctx.body = await fs.createReadStream(path.resolve(__dirname, './../index.html'));
});
app.listen(8001);
每次请求进来都需要读文件流再返回文件显然是存在问题的。
本次优化先将资源路径配置为打包后的public目录,默认会访问到public的index.html,同时将前端静态路由使用HashRouter。调整至二级路由后刷新页面空白是因为静态路由刷新了之后一级路由携带的信息就没了,所以这里利用了localStorage
对一级路由进入二级路由时携带的信息做了一次缓存。
let localRecord = window.localStorage.getItem('record');
if(!this.props.location.state){
this.data = DATA[`${localRecord}`];;
}else{
this.data = DATA[`${this.props.location.state}`];
window.localStorage.setItem('record', this.props.location.state);
}
总结
常用优化手段
- 去掉开发环境配置,比如代码压缩等
- 提取CSS文件ExtractTextPlugin
- CommonsChunkPlugin提取公共模块
- externals通过模板中全局引入SDK方式忽略一些固定不变的模块包 比如react react-dom react-router-dom等
- 按需加载引入的第三方组件库比如ant等
网友评论