导读
网页性能优化建议:升级到 http2 协议、gizp 压缩、强缓存。
升级到 http2 协议
http2 相对 http1.1 有以下几个优势
- 多路复用:允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息,合并多个请求为一个的优化将不再适用。
- 首部压缩:移除了请求中的一些啰嗦首部,你可以通过很少的 IP package,承载数十个乃至上百个的请求,更符合最小数据量的理想化原则。
- 服务端推送:服务器可以向客户端推送所需要的资源,避免不必要的 Round Trips。
- 新的二进制格式(Binary Format),HTTP1.x 的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多。基于这种考虑 HTTP2.0 的协议解析决定在 应用层(HTTP/2)和传输层(TCP or UDP)之间采用二进制格式,实现方便且健壮。在 应用层(HTTP/2)和传输层(TCP or UDP)之间。
import spdy from "spdy";
spdy
.createServer(
{
key: fs.readFileSync("./privkey.pem"),
cert: fs.readFileSync("./fullchain.pem"),
spdy: {
protocols: ["h2"],
},
},
app
)
.listen(3100);
http2 目前主流浏览器都需要 ssl 证书,推荐一个在线 https 证书申请网站
gzip 压缩
需要发送header中带Accept-Encoding: gzip,deflate的请求
客户端
webpack 配置
const CompressionPlugin = require('compression-webpack-plugin')
// config
plugins: [
// gzip
new CompressionPlugin({
algorithm: 'gzip',
threshold: 10240,
minRatio: 0.8
})
]
vite 配置
import viteCompression from "vite-plugin-compression";
// config
plugins: [
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: "gzip",
ext: ".gz",
}),
],
服务端
tomcat 中修改${TOMCAT_HOME}/conf/server.xml
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
compression="on" //开启
compressionMinSize="2048" // 进行压缩的最小值,低于该值的文件不进行压缩(单位B,默认2048,即默认2k)
noCompressionUserAgents="gozilla,traviata"//不需要进行压缩的浏览器,当浏览器类型为指定的类型时,不进行压缩
compressableMimeType="text/css" />// 需要压缩的文件类型(多个类型以逗号分隔)
node 中配置
const compression = require('compression')
// 在其他中间件前使用
app.use(compression())
http 强缓存
客户端
webpack 配置
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js',
path: path.resolve(__dirname, '../dist'),
},
vite 默认配置就行
服务端
express 配置
app.use((req, res, next) => { // 将 index.html 设为 no-cache
if(~req.url.indexOf('html')) {
res.setHeader('Cache-control', 'no-cache')
}
next()
})
app.use(express.static('dist', {
etag: false,
maxAge: 1000 * 60 * 60 * 24 * 365, // 缓存一年
})) // 将dist设为根目录
tomcat 配置
<filter>
<filter-name>ExpiresFilter</filter-name>
<filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
<init-param>
<param-name>ExpiresByType image</param-name>
<param-value>access plus 10 days</param-value>
</init-param>
<init-param>
<param-name>ExpiresByType text/css</param-name>
<param-value>access plus 10 days</param-value>
</init-param>
<init-param>
<param-name>ExpiresByType application/javascript</param-name>
<param-value>access plus 10 days</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>ExpiresFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
按需打包
各种第三方库只有用到的组件或函数才打包,vite 打包时 elements-plus 按需加载如下:
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
//vite.config.ts
plugins: [
vue(),
vueJsx(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: "gzip",
ext: ".gz",
}),
],
这样就不需要再 main.ts 中引用 elements-plus 了,在.vue 单文件组件中 template 中可以直接用 el-form 等标签,不过在 script 中还需 import
懒加载
异步路由懒加载:
const routes: Array<RouteRecordRaw> = [
{
path: "/",
name: "Detail",
component: Detail,
},
{
path: "/Verify",
name: "Verify",
component: () => import("@/components/Verify.vue"),//只有访问/Verify时才加载该组件
},
{
path: "/Success",
name: "Success",
component: () => import("@/components/Success.vue"),
},
];
图片懒加载 进入可视范围才加载
判断一个元素是否在可视区域,我们常用的有三种办法:
-
offsetTop、scrollTop
-
getBoundingClientRect
-
Intersection Observer
分包
根据实际项目情况,一个文件一般不超过 500k。 vite 配置
build: {
rollupOptions: {
output: {
manualChunks: {
vue: ["vue", "pinia", "vue-router"],
lodash:["lodash"],
echart:["echart"]
},
},
},
},