项目常见优化方式分类
1、网络优化 包括
HTTP2、DNS预解析、Preload、Prefetch等手段2、资源优化 包括
构建产物分析、资源压缩、产物拆包、按需加载等优化方式3、预渲染优化
服务端渲染(SSR) 、静态站点生成 (SSG)等
网络优化
HTTP2
为甚么采用HTTP2来进行网络优化?
1、HTTP1.1存在队头阻塞问题,同一个TCP管道中同一时刻只能处理一个HTTP请求,在当前请求没有处理完时,其它请求处于阻塞状态;
2、浏览器对于同一个域名下的兵法请求数量都有限制,Chrome中只允许6个请求发送,且不允许用户配置,当请求数量超过6个时,多出的请求只能排队等待发送。
HTTP2的优点?
1、多路复用 .HTTP2将数据分为多个二进制帧,多个请求和响应的数据帧在同一个TCP通道进行传输,解决了之前队头阻塞问题。
2、不存在同一域名并发请求数量限制
3、服务端推送能力可以让某些资源提前到达浏览器,比如对一个html 的请求,通过HTTP2可以同时将相应的js和css资源推送扫浏览器。
通过插件 vite-plugin-mkcer 在本地服务开启HTTP2
插件原理:HTTP2依赖TLS握手,插件会自动生成TLS证书,支持通过HTTPS的方式启动,vite会自动把HTTPS服务升级为HTTP2
当使用 vite 的proxy配置时,vite会将HTTP2降级为HTTPS,可通过插件
vite-plugin-proxy-middleware
解决该问题
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import mkcert from "vite-plugin-mkcert";
export default defineConfig({
plugins: [react(), mkcert()],
server: {
// https 选项需要开启
https: true,
},
});
vite-plugin-mkcert 插件仅用于开发阶段,在生产阶段需要对线上服务器进行配置,开启HTTP2
DNS解析
浏览器向跨域的浏览器发送请求时,首先会进行DNS解析,将服务器域名解析为对应的IP地址。通过dns-prefeth技术将这一过程提前,降低DNS解析的延迟时间。
<!-- href 为需要预解析的域名 -->
<link rel="dns-prefetch" href="https://fonts.googleapis.com/">
dns-prefetch会与preconnect 搭配使用,前者用来解析 DNS,而后者用来会建立与服务器的连接,建立 TCP 通道及进行 TLS 握手,进一步降低请求延迟。
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
<link rel="dns-prefetch" href="https://fonts.gstatic.com/">
preconnect 的 link 标签一般需要加上 crorssorigin(跨域标识),否则对于一些字体资源
preconnect会失效
DNS解析
可以通过 Preload方式进行预加载,在资源使用之前进行加载,使资源更早的到达浏览器。
//声明 `href` 和 `as` 属性,分别表示资源地址和资源类型
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">
对于原生ESM模块,浏览器提供了modulepreload来进行预加载
<link rel="modulepreload" href="/src/app.js" />
通过配置vite 一键开启 modulepreload 的 Polyfill
// vite.config.ts
export default {
build: {
polyfillModulePreload: true
}
}
Prefetch 浏览器空闲时去预加载其他页面资源 (浏览器兼容性差)
<link rel="prefetch" href="https://B.com/index.js" as="script">
//浏览器会在 A 页面加载完毕之后去加载`B`这个域名下的资源,
//如果用户跳转到了`B`页面中,浏览器会直接使用预加载好的资源,从而提升 B 页面的加载速度
资源优化
1、产物分析报告
首先需要安装 rollup-plugin-visualizer依赖
pnpm i rollup-plugin-visualizer -D
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { visualizer } from "rollup-plugin-visualizer";
export default defineConfig({
plugins: [
react(),
visualizer({
// 打包完成后自动打开浏览器,显示产物体积报告
open: true,
}),
],
});
// 执行 pnpm run build 后会生成stats.html 文件
2、资源压缩
JS压缩
// vite.config.ts
export default {
build: {
// 类型: boolean | 'esbuild' | 'terser'
// 默认为 `esbuild`
minify: 'esbuild',
// 产物目标环境 ,vite默认是modules , 即如下的 browserlist ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1']
// 为了线上的稳定性,推荐将 target 参数设置为`ECMA`语法的最低版本es2015或者es6
target: 'modules',
// 如果 minify 为 terser,可以通过下面的参数配置具体行为 // https://terser.org/docs/api-reference#minify-options
terserOptions: {}
}
}
css 压缩
export default{
build:{
//设置CSS的目标环境
cssTarget:''
}
}
vite 在默认情况下会使用ESbuild 对CSS进行压缩,不需要对 cssTarget进行配置;
但是在需要兼容 安卓微信的webview时,需要将build.cssTarget 设置为 chrome61, 防止 vite 将rgba()颜色转化为#RGBA 十六进制符号的形式,出现样式问题
图片压缩
图片压缩需要安装插件
pnpm i vite-plugin-imagemin -D
//vite.config.ts
import viteImagemin from 'vite-plugin-imagemin';
{
plugins: [
// 忽略前面的插件
viteImagemin({
// 无损压缩配置,无损压缩下图片质量不会变差
optipng: { optimizationLevel: 7 },
// 有损压缩配置,有损压缩下图片质量可能会变差
pngquant: { quality: [0.8, 0.9], },
// svg 优化 svgo:
{
plugins: [
{ name: 'removeViewBox' },
{ name: 'removeEmptyAttrs', active: false }
]
}
})
]
}
插件已经生效,如下图:
产物拆包
打包的产物为什么需要拆包?
不对产物进行分包,代码会全部打包到同一个chunk文件中,
首屏加载的代码体积过大,即时是当前页面不需要的代码也会进行加载
线上缓存复用率低,改动一行代码会导致整个上次打包的结果缓存失效
vite 内置的拆包能力?
1、CSS 代码分割,实现一个chunk对应一个css文件
2、默认将应用的代码和第三方库的代码分别打包成两份产物,并对于动态import 的模块单独打包成一个chunk
// vite.config.ts
{
build: {
rollupOptions: {
output: {
// manualChunks 配置
manualChunks: {
// 将 React 相关库打包成单独的 chunk 中
'react-vendor': ['react', 'react-dom'],
// 将 Lodash 库的代码单独打包
'lodash': ['lodash-es'],
// 将组件库的代码打包
'library': ['antd', '@arco-design/web-react'],
},
},
}
},
}
打包结果,react为单独chunk ,如下图