Vue3 零基础每日笔记(078):首屏加载速度优化汇总——清单化方案

一、前言

性能篇收官汇总:前面散落的优化点(050/064/072/073/075/076/077)串成一张"首屏速度"作战地图。拿到"首屏 5 秒"的烂项目,按清单从上往下打,这一篇就是执行手册。

二、先诊断:首屏到底慢在哪

打开 Chrome DevTools → Network,刷新页面看瀑布图,按四步定位:

text 复制代码
1. 看总量:底栏 Total 体积多大?(> 5MB 就有硬伤)
2. 看大头:按 Size 排序,谁占最大?(大 JS 包 / 大图 / 字体)
3. 看时序:JS 是不是串行等待?(main.js 下载完才开始拉 chunk)
4. 看渲染:Performance 录制,白屏段在等什么?(接口阻塞渲染?)

常见病根排序:包太大 > 图片太大 > 串行请求 > 服务端慢。对症下药才有意义,别上来就盲改。

三、优化清单(按性价比排序)

3.1 包体积层(收益最大)

优化 出处 要点
路由懒加载 050 篇 所有页面 () => import(),首页只发首页的包
组件懒加载 072 篇 富文本/图表等重组件 defineAsyncComponent
UI 库按需导入 064 篇 unplugin 自动按需
分包 manualChunks 077 篇 库走长缓存,发版只更新业务包
gzip 预压缩 077 篇 体积立减 60%+,几乎零成本
库替换 077 篇 moment→dayjs(-280KB)、lodash→lodash-es(支持 tree-shaking)

3.2 渲染体验层(感知提速)

优化 出处 要点
骨架屏 075 篇 白屏变成"内容形状预告"
图片懒加载 075 篇 首屏只加载可视区图片
长列表虚拟化 074 篇 首屏 DOM 数量封顶
loading 骨架先行 075 篇 接口慢≠界面慢,占位先行

3.3 交互层(防卡顿)

优化 出处 要点
防抖节流 076 篇 搜索/滚动不再疯狂触发
keep-alive 缓存 073 篇 返回不重渲染
事件清理 037 篇 防内存泄漏(越用越卡)

四、预加载:让"下一步"提前出发

分包/懒加载的代价是"用到才请求",预加载就是把代价补回来:

4.1 Vite 自动做了什么

html 复制代码
<!-- Vite 构建后 index.html 里自动出现:-->
<link rel="modulepreload" href="/assets/vendor-xxx.js" />
<!-- 首页路由 chunk 也会被分析并预加载:现代浏览器解析 HTML 时就提前下载 JS -->

默认已够用,不用手写。

html 复制代码
<!-- index.html -->
<!-- 提前建立与接口服务器的连接(DNS + TCP + TLS) -->
<link rel="preconnect" href="https://api.example.com" />

<!-- 预解析第三方 CDN 的 DNS -->
<link rel="dns-prefetch" href="https://cdn.example.com" />

<!-- 预加载关键资源(如首屏大图、字体) -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin />

原则:只预加载"几乎必然要用"的资源,预加载没人看的东西是负优化。

4.3 关键接口并行

ts 复制代码
// ❌ 串行:user 1s + menu 1s + notice 1s = 3s
const user = await getUser()
const menu = await getMenu(user.uid)
const notice = await getNotice()

// ✅ 能并行的并行:总耗时 = 最慢的 1s
const [userRes, menuRes, noticeRes] = await Promise.all([
  getUser(), getMenu(), getNotice()
])

菜单如果依赖 uid:user 先行,menu + notice 并行------分析依赖关系再决定谁能并行(059 篇 Promise.all 的实战落点)。

五、缓存策略:让"第二次访问"飞起来

浏览器缓存的分层设计(Nginx 配置视角):

nginx 复制代码
# 带 hash 的静态资源:内容变 → 文件名变 → 可以放心"永久缓存"
location /assets/ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

# index.html:永不长缓存(★ 发版入口,缓存错了用户永远在旧版本)
location = /index.html {
    add_header Cache-Control "no-cache";   # 每次都向服务器确认是否更新
}

原理:Vite 打包的文件名自带内容 hash(app-3f8b2c.js),内容变了名字就变------assets 缓存一年也不会出旧版本,只要 index.html 不被缓存,用户永远拿到最新入口。

六、SSR 概念引入:什么时候该换架构

前端优化的天花板:CSR(现有方案)的 HTML 是空壳,必须等 JS 下载执行完才有内容。

方案 首屏 HTML 适用 成本
CSR(SPA) 空壳 <div id="app"> 中后台、交互密集 低(本系列方案)
预渲染 prerender 构建时生成完整 HTML 官网、落地页(内容固定) 低
SSR 服务器实时渲染完整 HTML C 端内容页、SEO 刚需 高(Nuxt / 服务端运维)

判断口诀:

text 复制代码
内部系统、要登录 → CSR 足够,把本篇清单打满
官网/落地页内容固定 → 预渲染(vite-plugin-ssr / prerender)
C 端内容页、SEO 重要(商城/资讯) → SSR(Nuxt 3,Vue 官方生态,另开系列)

SSR 的本质:把"渲染"从浏览器搬到服务器,用户拿到 HTML 就能看,代价是服务器成本和开发复杂度------性能优化清单没打满之前,别急着上 SSR。

七、踩坑记录

  1. 只优化不测量:改完不录 Performance/不对比 Network,不知道有没有用------每次优化记录前后数据
  2. index.html 被强缓存:用户永远加载旧版本入口,发版不生效------no-cache 只对 index.html,assets 才长缓存
  3. 预加载滥用:preload 十几个资源抢带宽,关键路径反而慢------预加载"必然用"的少数资源
  4. Promise.all 一个失败全崩:首屏数据互相独立时用 allSettled 或分别 catch(059 篇提过)
  5. 优化顺序反了 :先折腾 SSR/微前端等大手术,基础清单没打满------性价比从上往下,包体积永远第一
  6. 混淆首屏慢和接口慢:Network 里 DOMContentLoaded 快但内容晚出 = 接口慢,优化方向完全不同(接口在 060-063 篇)

八、今日小结

  • 先诊断后优化:Network 四步定位(总量/大头/时序/渲染)
  • 清单三层:包体积(最大收益)→ 渲染体验(感知提速)→ 交互防卡
  • 预加载补懒加载的代价:modulepreload 自动、preconnect/preload 手动、接口并行
  • 缓存关键:assets 永久缓存(hash 文件名)+ index.html no-cache
  • 架构选择:CSR 够用打满清单,内容站才考虑预渲染/SSR(Nuxt)

下篇预告

性能篇完结,进入生态扩展篇:VueUse 必会工具集 top20------防抖、剪贴板、本地存储、鼠标跟踪全都有现成的,开发效率直接起飞。下一篇 079。

相关推荐
ZZHow10244 小时前
Ascend C算子开发(高级)笔记
c++·人工智能·笔记·深度学习·华为云
PC2005-cloud5 小时前
Mysql学习笔记:InnoDB Cluster 集群从零搭建实战,基于 Docker 实现高可用读写分离架构
笔记·学习·mysql
小陈phd5 小时前
深入理解agent学习笔记(七)——动态提示词与Skills
笔记·学习
我命由我123455 小时前
田野笔记极简理解
经验分享·笔记·学习·职场和发展·求职招聘·职场发展·学习方法
小陈phd6 小时前
深入理解agent学习笔记(六)——提示工程-优化系统提示词
笔记·学习
霖霖7146 小时前
【ESP32笔记】RGB灯WS2812实验
笔记·单片机·mcu·物联网
Aurora_eye6 小时前
Git 笔记
笔记·git
yi0116 小时前
DAY28: LeetCode 111. 二叉树的最小深度
人工智能·笔记·python·算法·leetcode·二叉树·递归
xxwl5857 小时前
三、区域赛算法模版第三章---字符串相关算法
笔记·学习·算法