我整理了一份 Vue 性能优化指南(给AI用的)
为什么做这个
说实话,这个项目是我自己用的。
工作这几年,遇到的性能问题基本都是类似的坑:接口瀑布流、bundle 越来越大、响应式乱用。每次踩完坑修好了,过段时间换个项目又踩一遍。
后来想着,干脆整理一份文档,自己查方便,也能给 AI 编码助手看(我现在用 Claude Code),这样审代码的时候能提前发现问题。
整理完发现,好像也可以分享出来,说不定有人也遇到过这些问题。
我踩过的坑
这几年写 Vue 项目(Vue 2/3 + Nuxt 都有),踩过不少坑:
接口请求变成瀑布流 一个 await 接一个 await,明明能并行的请求硬是串行了。用户抱怨页面慢,一查发现 3 个接口排队等了 750ms。
bundle 体积失控 每次加需求就往里塞代码,没人关心打包结果。等到首屏白屏 3 秒了,才发现 JavaScript 已经 300KB+。
响应式系统滥用 大对象直接 ref(),上千条商品数据,每个字段都变成响应式。渲染一卡一卡的,还以为是组件写得不好。
这些问题不是什么高深的优化,就是基本功。但忙起来就容易忽略,等出问题再改成本就高了。
怎么说呢,优化要分轻重
我发现很多人(包括以前的我)做性能优化会搞错重点。
举个例子:页面有 600ms 的请求等待时间,结果花一周优化 computed 缓存。首屏加载了 300KB 的 JavaScript,结果去优化循环少跑几次。
其实应该先解决大问题:
- 先干掉请求瀑布流 - 能并行就并行,该预加载就预加载
- 再砍 bundle 体积 - 代码分割、动态导入、tree-shaking
- 然后才是组件和响应式优化 - 减少不必要的渲染
我按这个思路把规则分成了 10 个类别,从 CRITICAL 到 LOW,总共 46 条。先把影响大的问题解决了,那些微优化可以慢慢来。
里面有什么
10 个类别,46 条规则:
- 消除异步瀑布流(CRITICAL)
- 包体积优化(CRITICAL)
- 服务端性能(HIGH)
- 客户端数据获取(HIGH)
- 响应式系统优化(MEDIUM-HIGH)
- 渲染性能(MEDIUM)
- Vue 2 特定优化(MEDIUM)
- Vue 3 特定优化(MEDIUM)
- JavaScript 性能(LOW-MEDIUM)
- 高级模式(LOW)
每条规则的格式:
- 影响等级(CRITICAL / HIGH / MEDIUM / LOW)
- 错误示例(我以前写过的错误代码)
- 正确示例(后来改成什么样)
- Vue 2/3 兼容性说明
举几个我踩过的坑
坑 1:不需要的 await 也在阻塞代码
以前写过这样的代码:
async function handleRequest(userId: string, skipProcessing: boolean) {
// 即使 skipProcessing=true,也会等待 userData
const userData = await fetchUserData(userId)
if (skipProcessing) {
// 立即返回,但前面已经浪费时间等待了
return { skipped: true }
}
// 只有这个分支使用 userData
return processUserData(userData)
}
问题是,即使 skipProcessing=true,还是会去请求 userData。白白浪费时间。
后来改成这样:
async function handleRequest(userId: string, skipProcessing: boolean) {
if (skipProcessing) {
return { skipped: true }
}
// 只在需要时才获取数据
const userData = await fetchUserData(userId)
return processUserData(userData)
}
其实很简单,但之前就是没注意到。
坑 2:大对象别直接用 ref
1000 条商品数据,每条 10+ 个字段,以前直接 ref():
<script setup lang="ts">
import { ref } from 'vue'
// 1000 个商品,每个商品 10+ 字段,全部变成响应式
const products = ref<Product[]>([])
async function loadProducts() {
products.value = await fetchProducts()
// Vue 会递归遍历所有对象,添加响应式代理
}
</script>
渲染的时候卡得要命。后来发现应该用 shallowRef:
<script setup lang="ts">
import { shallowRef } from 'vue'
// 只有数组本身是响应式的,内部对象保持普通对象
const products = shallowRef<Product[]>([])
async function loadProducts() {
// 替换整个数组触发更新,无需深度响应式
products.value = await fetchProducts()
}
</script>
shallowRef 只让数组本身响应式,内部对象保持普通对象。更新时替换整个数组就能触发响应,省了大量性能开销。
几个真实案例(我遇到过的)
案例 1:别对同一个数组循环多次
之前接手一个项目,发现同一个商品列表循环了 5 次:
// 错误:5 次独立遍历
const discounted = products.filter(p => p.discount > 0)
const inStock = products.filter(p => p.stock > 0)
const featured = products.filter(p => p.featured)
const totalValue = products.reduce((sum, p) => sum + p.price, 0)
const avgPrice = totalValue / products.length
看着就难受。后来改成一次循环:
// 正确:一次遍历
const stats = products.reduce((acc, product) => {
if (product.discount > 0) acc.discounted.push(product)
if (product.stock > 0) acc.inStock.push(product)
if (product.featured) acc.featured.push(product)
acc.totalValue += product.price
return acc
}, { discounted: [], inStock: [], featured: [], totalValue: 0 })
const avgPrice = stats.totalValue / products.length
商品少的时候看不出来,数据一多性能差距就很明显了。
案例 2:独立的请求不要排队
用户详情页,三个互不依赖的接口,结果在串行调用:
// 错误:串行:总耗时 = 300ms + 200ms + 250ms = 750ms
const user = await fetchUser(userId) // 300ms
const posts = await fetchUserPosts(userId) // 200ms
const comments = await fetchUserComments(userId) // 250ms
改成并行之后:
// 正确:并行:总耗时 = max(300ms, 200ms, 250ms) = 300ms
const [user, posts, comments] = await Promise.all([
fetchUser(userId),
fetchUserPosts(userId),
fetchUserComments(userId)
])
总耗时从 750ms 降到 300ms,页面快了一半多。这种优化投入产出比最高。
案例 3:长列表用 CSS content-visibility
1000+ 条评论的页面,初始渲染很慢:
<!-- 错误:所有评论立即渲染 -->
<div v-for="comment in comments" :key="comment.id">
<CommentCard :comment="comment" />
</div>
后来加上 content-visibility:
<!-- 正确:浏览器跳过屏幕外的渲染 -->
<div
v-for="comment in comments"
:key="comment.id"
class="comment-item"
>
<CommentCard :comment="comment" />
</div>
<style>
.comment-item {
content-visibility: auto;
contain-intrinsic-size: auto 200px;
}
</style>
浏览器会跳过屏幕外的渲染,初始加载快了 5-10 倍,滚动也流畅多了。这个 CSS 属性真的好用。
怎么用
直接看
# 克隆仓库
git clone https://github.com/ursazoo/vue-best-practices.git
# 安装依赖
npm install
# 构建 AGENTS.md
npm run build
克隆下来,直接看 rules/ 目录下的规则文件。每个文件都是独立的,包含问题说明、代码示例和解决方案。
也可以看构建好的 AGENTS.md,把所有规则整合在一起,方便搜索。
集成到 AI 编码助手
如果你也在用 Claude Code、Cursor 这类 AI 工具写代码,可以集成进去:
npx add-skill vue-best-practices
AI 审查代码的时候,如果发现性能问题(比如请求瀑布流、过度响应式),会参考这些规则给出优化建议。我现在就是这么用的,挺方便。
Vue 2 还是 Vue 3
都支持。每条规则都标注了版本兼容性:
- Vue 2 & 3 通用:基础的性能优化技巧
-
Vue 3 Only:用了
<script setup>、shallowRef、Suspense等新特性 -
Vue 2 Only:针对 Vue 2 的特定优化(比如
Object.freeze())
老项目也能用,新项目能用得更充分。
项目地址
GitHub: github.com/ursazoo/vue…
欢迎贡献
这是个开源项目。如果你在生产环境踩过坑、有更好的优化方案,欢迎提 Issue 或 PR。
特别是:
- 实际项目中遇到的性能问题
- 现有规则的改进建议
- Vue/Nuxt 新版本的优化技巧
项目信息:
- 46 条规则,10 个类别
- 按影响程度排序(先解决大问题)
- 支持 Vue 2/3 和 Nuxt
- 适配 AI 编码助手
希望对你有帮助。