前言
前段时间把项目的构建工具由vue-cli换成了vite,发现开发体验提升了不少,启动速度直接起飞,但是vite真的就是完美的,没有问题吗?这不,用了没多久就遇到了vite的一个硬伤问题——开发环境页面首次加载会很慢。但是相对于webpack启动慢无法解决,这个问题应该至少是可以解决的,接下来我们一起来分析下问题的原因并尝试解决。
分析问题
问题复现
开发环境下,首次进入页面的时候会很慢,特别是切换页面的时候,特别明显,需要等待一定的时间才会跳转,体验很差,下图为部分资源的请求,请求的资源很多,组件之可能会有些依赖关系,这样渲染的时长就可能会是多个请求的时长的叠加。
分析原因
为了提高效率,我们先问下GPT Vite的原理吧,下面是GPT的回答:
由上面的原理得出,vite在本地构建服务的时候,是基于ES modules,也就是不需要对代码进行过多的处理,所以冷启动会非常的快,其次基于浏览器的原生模块加载机制,按需加载,就是在需要的时候才会加载资源,到这里想必大家已经知道了问题的根源所在了。
解决问题
查找解决方案
知道问题的原因了,那么解决起来就好办了,按照解决问题的流程来办,查资料一般是最高效的。
于是我赶紧向GPT大佬请教方案,让我感到意外的是和GPT扯了一上午,并没有什么收获,难道是我问问题的姿势不对,导致它没有理解到位?
于是我就赶紧问度娘、问谷歌,找到了一些蛛丝马迹,尝试之后发现无效,可能根本就不是解决这个问题的。
这么明显的问题竟然没有人解决(可能是觉得不影响生产环境就将就着用吧)?我想起我微信里还有几个大佬群,于是我把问题抛向群里,用过vite的都表示有这个问题,但是没有解决。
到这里,只能放弃CV大法了,进入解决问题流程的下一环节了,自己干。
仔细想一想,其实解决这个问题的应该是不难的,只要在空挡期把项目的所有资源全部加载缓存就可以了
尝试解决问题
这里准备写一个vite的插件,在标签的底部插入一个脚本加载需要加载的资源。
这里就不多废话了,直接上插件的代码:
const fs = require('fs')
// 查找文件
function getFiles (e: string) {
const arr: string[] = []
const dirents = fs.readdirSync(e, { withFileTypes: true })
for (const dirent of dirents) {
if (dirent.isDirectory()) arr.push(...getFiles(e + dirent.name + '/'))
else {
arr.push(e + dirent.name)
}
}
return arr
}
// 插入加载文件脚本
export const setPreLoadFile = (options: { pathList: string[], preFix: string } = { pathList: [], preFix: '' }) => {
if (options.pathList && options.pathList.length) {
let res: string[] = []
options.pathList.forEach(path => {
res = res.concat(getFiles(path))
})
let linkStr = `
<script>
setTimeout(() => {
function preLoadSource(url){
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = function() {
if (xhr.status === 200) {
console.log('预加载成功');
} else {
console.error('预加载失败');
}
};
xhr.send();
}\n
`
res.forEach(item => {
linkStr += `preLoadSource('${options.preFix + item.substring(1)}')\n`
})
linkStr += '})\n</script>'
return {
name: 'preload-file',
transformIndexHtml (dom) {
return dom.replace('</body>', `${linkStr}</body>`)
}
}
}
}
使用插件:
import { setPreLoadFile } from './vite-plugin-preload'
export default defineConfig(({ mode }) => ({
plugins: [
// 设置预加载文件,提升页面首次加载速度(仅开发环境需要)
mode === 'development' && setPreLoadFile({
pathList: [ // 需要提前加载的资源目录
'./src/views/',
'./src/components/'
],
preFix: '/cflow' // 项目根路径
})
]
}))
解决效果
使用插件之后,我们再看下和问题复现时对应的那张图
由上图可以发现,很多资源已经被重定向到了缓存,请求时间大大减小,页面切换也丝滑了很多,开发体验又上升了一个档次