1-CDN加速
在项目中引入vite-plugin-cdn-import
包即可,然后像下面这样使用
js
import importToCDN from 'vite-plugin-cdn-import'; // CDN引入
export default function (isBuild) {
// 开发环境不使用CDN
if (!isBuild) return importToCDN({ modules: [] });
return importToCDN({
modules: [
// {
// name: 'element-plus',
// var: 'ElementPlus',
// path: 'https://cdn.bootcdn.net/ajax/libs/element-plus/2.3.12/index.full.min.js',
// css: 'https://cdn.bootcdn.net/ajax/libs/element-plus/2.3.12/index.min.css'
// },
],
});
}
哪些方面可以使用cdn加速呢?一些比较大的图片或者不常改变的文件和SDK包等,比如element-plus
或者vue
还有echarts
都可以放上去。(一般建议放公司cdn上,免费的容易挂)
2-按需加载
一些常用的ui库或者lodash库都可以实现按需加载,不必全局引入,比如使用element-ui
,可以像下面这样使用:
js
import AutoImport from 'unplugin-auto-import/vite'; // 自动引入api
import Components from 'unplugin-vue-components/vite'; // 自动引入组件
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'; // ElementPlusResolver 去看文档 里面有介绍有那些ui库可以直接使用 直接看官网也有
export default function () {
return [
AutoImport({
dts: false,
imports: ['vue', 'pinia', 'vue-router', '@vueuse/core'],
resolvers: [ElementPlusResolver()],
}),
Components({
dts: false,
extensions: ['vue'],
include: [/\.vue$/],
dirs: ['src/components/'],
resolvers: [ElementPlusResolver()],
}),
];
}
使用时直接拿来就用,不必再写引入语句了。
3-Gzip压缩
简单理解就是把代码再次压缩成.gz包,从而大大减少代码体积,提高加载速度,如下使用:
js
import viteCompression from 'vite-plugin-compression'; // 打包压缩
export default function () {
return viteCompression({
verbose: true, // 是否在控制台输出压缩结果
disable: false, // 是否禁用
// filter:()=>{}, // 过滤哪些资源不压缩 RegExp or (file: string) => boolean
threshold: 1024 * 50, // 体积大于50KB才会被压缩,单位 b
deleteOriginFile: false, // 压缩后是否删除源文件
algorithm: 'gzip', // 压缩算法
ext: '.gz', // 生成的压缩包后缀
});
}
打包后可以看到会出多.gz后缀的包,体积非常小。但是这个得配合后端nginx添加配置项目,如下:
js
//在nginx添加
http {
# 开启或者关闭gzip模块(on|off)
gzip_static on;
# gzip压缩比,1 压缩比最小处理速度最快,9 压缩比最大但处理最慢(传输快但比较消耗cpu)
gzip_comp_level 2;
}
4-将svg图转雪碧图
雪碧图的作用还是挺多的,比如减少HTTP请求数量,减小图像文件大小和提高渲染性能。作用还是挺大的,而且用起来也方便。在项目中引入vite-plugin-svg-icons
包即可(虽然这个包停止维护了,但是还是挺好用的)。 使用方式如下:
js
import path from 'path';
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
// 将svg图标生成雪碧图
export default function (isBuild) {
return createSvgIconsPlugin({
customDomId: '__svg__icons__',
iconDirs: [path.resolve(process.cwd(), 'src/assets/svgs')], // 指定需要缓存的图标文件夹
symbolId: 'icon-[dir]-[name]', // 指定symbolId格式
svgoOptions: isBuild,
});
}
具体的使用方式可以在github上找到这个包,里面有详细的使用说明,vue
和react
都有。
5-图片压缩
使用的是这个包vite-plugin-imagemin
,但是这个包国内比较难安装,可能需要科学上网才行。使用方式摘至另一个掘友的,代码如下:
js
import viteImagemin from 'vite-plugin-imagemin'
plugin: [
viteImagemin({
gifsicle: {
optimizationLevel: 7,
interlaced: false
},
optipng: {
optimizationLevel: 7
},
mozjpeg: {
quality: 20
},
pngquant: {
quality: [0.8, 0.9],
speed: 4
},
svgo: {
plugins: [
{
name: 'removeViewBox'
},
{
name: 'removeEmptyAttrs',
active: false
}
]
}
})
]
6-图片懒加载
这个懒加载的话,有一些现有的很好用的包比如vue-lazyload
或者lozad.js
都可以。这里我使用的是自定义的指令来实现图片懒加载,更加贴合实际项目需求,代码如下:
js
import { useIntersectionObserver } from '@vueuse/core'; // 判断当前元素是否在可视范围内
import defaultImg from '../assets/images/loading.svg'; // 加载时svg
import errorImg from '../assets/images/error-image.png'; // 加载错误时的图片
import noImg from '../assets/images/no-image.png'; // 没有图片时的默认图片
import api from '@/api';
const isImage = (url) => {
return ['data:image','.jpg','.png','.jpeg','.gif','.bmp','.pic','.svg'].find((item) => url.includes(item));
};
const getImgUrl = async (item) => {
if (!item) return '';
if (item.filePath) return item.filePath;
const url = await api.get(
'api',
{ '备用字段': item.serverName }
);
return url;
};
// 获取图片地址 当src上没有传值时,则从绑定的对象上获取filePath,如果没有filePath,则从绑定的对象上获取备用字段,再通过接口来获取 三重保险
const getPreviewImg = async (src,{ value }) => {
if (!src && !value) return '';
const url = src || (await getImgUrl(value[0]));
const str = url.toLowerCase();
if (isImage(str)) return url;
return noImg;
};
export default {
name: 'lazyLoad',
mounted(el,binding) {
if (!['IMG'].includes(el.nodeName)) return;
const { src } = el;
el.src = defaultImg;
const { stop } = useIntersectionObserver(el,([{ isIntersecting }]) => {
if (isIntersecting) {
el.onerror = () => {
el.src = errorImg;
el.onerror = null;
};
getPreviewImg(src,binding).then((url) => {
el.src = url;
});
stop();
}
});
},
};
7-页面缓存
js
<template>
<RouterView>
<template #default="{ Component }">
<div
v-tloading="store.getPageLoading"
loading-tip="加载中.."
>
<keep-alive :include="/.*content/">
<component :is="Component" />
</keep-alive>
</div>
</template>
</RouterView>
</template>
这里有两个优化,第一个是当页面正在加载中时,会显示loading效果,在页面加载完成后loading效果去除。第二个是缓存页面中导出名字包含content
字段的页面,同时需要时可以配合pinia
实现数据持久化
8-数据缓存
比如常见的后台页面,主要由查询框和表格组成,查询框的下拉数据过多,此时可以将这部分数据缓存到本地使用,具体方法如下:
js
// 在发起请求时判断是否有缓存,有则直接返回;没有则发起请求并将结果缓存
reauest(config,options) {
const cacheData = this.getCache(config);
if (cacheData) return cacheData;
const res = await this.requestxx(config);
this.setCache(config, res);
return res;
}
const responseMap = new Map(); // 返回结果缓存池
this.generateReqKey(config); // 用来将config转换成唯一的key
// 获取缓存数据
getCache(config) {
// 2、没取到返回null
const requestKey = this.generateReqKey(config);
const data = responseMap.get(requestKey) || null;
if (!data) return null;
// 3、取到判断过期状态,如果过期清除缓存返回null,否则返回缓存数据
if (data.time < Date.now()) {
responseMap.delete(requestKey);
return null;
}
return data.data;
}
// 设置缓存
setCache(config,data,cacheTime) {
if (cacheTime) {
const requestKey = this.generateReqKey(config);
responseMap.set(requestKey,{ time: Date.now() + cacheTime,data });
}
}
// 使用
export async function getDict(params) {
const res = await api.get('xx',{...params },{ cacheTime: 1000 * 60 * 60 * 24 });
return res;
}
注意,这里的缓存不是放在localStorage
里的,所以当页面强制刷新时还是会重复调用。这里缓存的意义是在页面不刷新的情况下缓存,页面的查询框数据不变,其他部分改变。结合业务需求,也可以做成localStorage
缓存并设置过期时间。
9-ssr
目前还不会,后续加上
10-DNS预解析
浏览器在向跨域的服务器发送请求时,首先会进行 DNS 解析,将服务器域名解析为对应的 IP 地址。我们通过 dns-prefetch
技术将这一过程提前,降低 DNS 解析的延迟时间,具体使用方式如下:
js
<!-- href 为需要预解析的域名 -->
<link rel="dns-prefetch" href="https://fonts.googleapis.com/">
一般情况下 dns-prefetch
会与preconnect
搭配使用,前者用来解析 DNS,而后者用来会建立与服务器的连接,建立 TCP 通道及进行 TLS 握手,进一步降低请求延迟。使用方式如下所示:
js
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
<link rel="dns-prefetch" href="https://fonts.gstatic.com/">
值得注意的是,对于 preconnect 的 link 标签一般需要加上 crorssorigin(跨域标识),否则对于一些字体资源
preconnect
会失效。
总结
有任何问题欢迎指正,加油!!!