从构建优化,网络层面和代码层优化总结。
构建优化
1. tinypng.com在线压缩工具压缩大图。
这个工具挺好用,但是压缩大的图和批量压缩要收费。
2. webpack配置image-webpack-loader,压缩本地图片体积。
这个其实比较鸡肋,npm安装总是不成功,要用cnpm。当然这是其次,主要是压缩的效果不是很好呀。
3. webpack配置compressionPlugin插件把大文件预先压缩为gzip,与nginx配合传输。
这个效果杠杠的,能把资源压缩近70%呢。
原理可查看这篇文章(www.cnblogs.com/style-hyh/p…
const CompressionPlugin = require('compression-webpack-plugin');
chainWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config.plugin('compressionPlugin')
.use(new CompressionPlugin({
test: /\.js$|\.html$|\.css/, // 匹配文件名
threshold: 10240, // 对超过10k的数据压缩
deleteOriginalAssets: false // 不删除源文件
}))
}
}
#开启gzip模式
gzip on;
#nginx对于静态文件的处理模块,开启后会寻找以.gz结尾的文件,直接返回,不会占用cpu进行压缩,如果找不到则不进行压缩
gzip_static on;
#gizp压缩起点,文件大于1k才进行压缩
gzip_min_length 1k;
# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间
gzip_comp_level 1;
# 进行压缩的文件类型。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript ;
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
# 设置压缩所需要的缓冲区大小,以4k为单位,如果文件为7k则申请2*4k的缓冲区
gzip_buffers 2 4k;
# 设置gzip压缩针对的HTTP协议版本
gzip_http_version 1.0;
4. 生产环境不生产Map文件
module.exports = { productionSourceMap: false}
map文件相当于是查看源码的一个东西。如果不需要定位问题,并且不想被看到源码,就把productionSourceMap 置为false,既可以减少包大小,也可以加密源码。
5.prerender-spa-plugin 预渲染
未实践
6. 利用webpack的splitChunk分包
7. 利用import()按需加载
这里介绍两个场景使用场景:
A. 路由懒加载。广为人知的应用场景,不做赘述。
B. 在业务逻辑中使用。比如现在有一个混合开发app,我需要在h5模块装安装一个类似eruda这样的控制台调试工具。当然这个只是在测试环境才需要,生产环境无需引入。这时候,就可以通过桥协议获取app的环境,根据环境判断是否调用import()函数动态引入这个工具,然后再初始化,而不是先把工具引入,再根据环境判断是否初始化。
8. 打包es5和es6两个版本的js,根据浏览器版本动态引入对应版本js。
9. 使用webpack的Tree shaking
webpack官网对Tree shaking的介绍webpack.docschina.org/guides/tree…
其实在最新的babel-loader中,已经默认关闭对import和export相关的转化,所以不会影响webpack的tree shaking。
网络层优化
1. 浏览器缓存机制
网页的静态资源,并不是实时更新的,所以可以请求到最新版本之后,把它放入缓存中,下次访问网页时,如果没有更新资源,可以直接从缓存里获取。
因为资源更新之后,要从服务器中获取最新资源,那就无法使用强制缓存,只能使用协商缓存判断是否要获取最新数据。
我们使用的时nginx,所以只说下nginx怎么配置。
当我们使用nginx默认配置时,nginx在返回请求时,会带着etag和last-modified的,但是刷新页面再次请求后,请求头里并没带有if-none-match,而是默认强制缓存了。缓存的时间,也是根据浏览器自己定的缓存时间策略。
那么我们如何设置为协商缓存呢?
经过查阅nginx官网文档,在nginx配置文件中把Expires设置为-1,就可以解决这个问题了。
但是,如果有负载均衡的话,每台服务器就都会产生一个etag,这样单靠etag来判断是否资源更新就不准了,这时,If-Modified-Since就派上用场了。
还有一个极端的情况,万一这些服务器不是同一时间启动的,这样时间也不准了,那怎么办呢?只能修改etag的生成算法来解决吗?
2. 开启HTTP2.0
HTTP2.0的出现目的就是为了优化性能。虽然HTTP1.1也是长连接了,但是不能并行发送请求。2.0就解决了这个问题呀,而且服务端可以往客户端发送请求。也就是说静态文件js, css, html不用必须向服务器发送三次请求。如果是nginx服务器,版本要1.9.5以上,并且是https协议。
3. 离线包缓存
离线包方式其实就是把H5代码打包压缩成zip包形式,上传的后台服务器。App在打开此应用时,下载此资源。当然下载前会先判断是否有更新,无更新就用本地缓存的资源。这么看来倒是很像http的协商缓存了。
下载后打开静态资源,当然就比在线打开要快一些了。
但是,这里会出现跨域的问题,解决办法可以有两种:
A. 使用CROS解决跨域问题。
B. 添加拦截HTTP请求方法,用原生端做代理发送请求,等获得响应后再返回给H5。这样对 H5是无感的。推荐!
CDN图片存储
CDN存储图片、pdf等资源,多节点,提高用户访问速度。
4. nginx配置浏览器强制缓存静态资源案例
如果你问我,强制缓存和协商缓存,优先用哪个,我的答案是,在条件允许的情况下,用强制缓存,如果条件不允许,先想办法创建条件使用强制缓存。
可能要问,为什么优先强制缓存?因为强制缓存相比协商缓存来说,是不需要发起网络请求的。
起初在我的项目中,也是使用的协商缓存。静态资源的获取,每次都要发送请求向后端确认是否更新,当返回304时,证明没有更新,直接在本地获取缓存数据即可。随着项目不断完善,发版次数也在减少,每个资源每次加载都向后台发送这个请求就感觉有点浪费了。
我想达到的效果是:只有静态文件有更新了,我才向后台发请求获取资源,不更新就直接获取本地的数据(强制缓存)。
问题是:每次访问页面时,如何知道静态资源是否更新了呢?
我的项目使用的是webpack,webpack最终会把打包后的js文件,创建
那么是否可以,html文件不缓存,每次都是向服务器获取最新数据,只强制缓存静态资源呢?
因为我的项目是用nginx存放前端代码的,所以看了下nginx是否支持分文件设置缓存策略的。答案是肯定的。
// nginx.configserver { listen 80; server_name localhost; location /my-app/assets/ { try_files $uri $uri/ /index.html last; alias /app/html/assets/;
# 配置强制缓存
add_header Cache-Control max-age=90000; } location /my-app/libs/ { try_files $uri $uri/ /index.html last; alias /app/html/libs/;
# 配置强制缓存 add_header Cache-Control max-age=90000; } location /my-app/ { try_files $uri $uri/ /index.html last; alias /app/html/; index index.html index.htm;
# 配置无需缓存 add_header ETag ""; add_header Last-Modified ""; add_header Cache-Control "no-store"; proxy_cache_revalidate on; }}
我们强制缓存了assets,libs文件夹下的静态文件,html未缓存。这样,每次访问我们项目时,都会从服务器获取html文件,在获取js等文件时,会判断html中的主js已存在在本地浏览器缓存(根据js文件名的hash值后缀),直接取出,没有,去服务器获取并存入本地缓存。
经验证,异步组件代码变更后,打包生成的主js文件,也会改变hash值,所以不需要担心不是直接引用的异步组件获取不到最新代码的问题。
渲染层面
部分引自:
-
动态引入模块代码。
-
组件库中组件按需引入。
-
巧用computed和watch
-
HTML文档结构层次尽量少,最好不深于六层
-
JS 脚本尽量后放
-
样式结构层次尽量简单
-
少量首屏样式使用内联方式放在标签内
-
在脚本中尽量减少DOM操作,尽量访问离线DOM样式信息,避免过度触发回流
-
减少通过 JS 代码修改元素样式,尽量使用修改
class名方式操作样式或动画 -
尽量减少浏览器重排和重绘的一些情况发生
-
2020年了!就不要使用
table布局了 -
CSS 动画中尽量只使用
transform和opacity,不会发生重排和重绘 -
隐藏在屏幕外,或在页面滚动时,尽量停止动画
-
尽可能只使用 CSS 做动画,CSS动画肯定比 JS 动画要好很多
-
避免浏览器的隐式合成
-
改变复合层的尺寸
首屏加提速优化点
减小包体积
- 页面分包进行懒加载
- 组件库按需加载
- 按条件动态引入工具库
- 压缩图片资源
- 开启gzip压缩
网络请求优化
- 利用http2
- 图片懒加载
- 利用CDN缓存静态资源或图片
利用浏览器缓存
- 强制缓存
- 协商缓存
开启服务端渲染
- ssr