初始化

This commit is contained in:
2026-03-05 21:27:11 +08:00
commit 130de0fd5d
140 changed files with 21972 additions and 0 deletions

View File

@@ -0,0 +1,215 @@
---
description: >
性能优化规范与审计流程。当用户讨论性能优化、报告页面慢、加载卡、
包体积大、Swoole 调优、数据库查询优化、缓存策略或 Core Web Vitals 时激活。
alwaysApply: false
---
# Performance Standards & Audit
> 本文件同时包含性能**诊断流程**和**编码规范**。
> 完整审计工作流见Read `.cursor/skills/performance-audit/SKILL.md`
## 诊断流程(用户报告性能问题时先走这里)
### 1. 性能基线
收集当前数据(前端 `npm run build` + `du -sh dist/`,后端路由数量)。
### 2. 四维度审计
**前端渲染** — 不必要重渲染、大列表虚拟化、图片压缩、按需导入
**网络请求** — 瀑布式请求、Redis 缓存、Axios 拦截、Nginx 缓存
**打包体积** — 大依赖、dynamic import、tree-shaking、barrel exports
**数据库查询** — N+1、缺少索引、未限制字段、未分页
### 3. 输出优化建议
按影响力排序,每个建议包含:预期收益 + 实施难度 + 具体代码。
### 诊断验证
- [ ] 优化前后有可量化对比
- [ ] 未引入功能回归
- [ ] Core Web Vitals 达标
---
## 性能指标目标
| 指标 | 目标 | 说明 |
|------|------|------|
| FCP | < 1.5s | 首次内容绘制 |
| LCP | < 2.5s | 最大内容绘制 |
| INP | < 200ms | 交互到下一帧 |
| API P95 | < 200ms | 后端接口响应 |
| API P99 | < 500ms | 后端接口响应(长尾) |
| DB Query | < 50ms | 单条数据库查询 |
| Redis | < 5ms | 缓存操作 |
---
## 前端性能
### Vite 构建优化
```typescript
// vite.config.ts
export default defineConfig({
build: {
target: 'es2015',
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
// 仅管理端:'element-plus': ['element-plus'],
'echarts': ['echarts'],
},
},
},
chunkSizeWarningLimit: 2000,
},
})
```
### 加载优化
- 路由懒加载: `() => import('@/views/module/page/index.vue')`
- 管理端 Element Plus 按需导入: `unplugin-vue-components` + `unplugin-auto-import`(用户端不使用 Element Plus
- 大列表虚拟化: `@tanstack/vue-virtual`
- 组件懒加载: `defineAsyncComponent()`
- 页面缓存: `<keep-alive :include="cachedViews">` 配合 worktab Store
### 资源优化
- 图片: WebP 格式 + 压缩 + CDN
- 图标: 管理端 `@element-plus/icons-vue` 按需导入;用户端使用 `lucide-vue-next`
- 字体: `font-display: swap` 避免阻塞
- Gzip: Nginx 开启 gzip 压缩
### 前端缓存策略
| 数据 | 方式 | TTL |
|------|------|-----|
| 产品列表 | Pinia + localStorage | 5 分钟 |
| 字典数据 | Pinia + localStorage | 1 小时 |
| 用户配置 | Pinia persist | 持久 |
| 路由/菜单 | Pinia persist | 持久 |
| 接口响应 | 不缓存(后端 Redis | — |
---
## 后端性能
### Swoole 调优
```php
// config/autoload/server.php
'settings' => [
'worker_num' => swoole_cpu_num() * 2,
'task_worker_num' => 4,
'max_request' => 10000,
'max_coroutine' => 100000,
'enable_coroutine' => true,
'open_tcp_nodelay' => true,
'socket_buffer_size' => 3 * 1024 * 1024,
'buffer_output_size' => 3 * 1024 * 1024,
'package_max_length' => 5 * 1024 * 1024,
],
```
### 数据库查询优化
| 规则 | 正确做法 | 反模式 |
|------|---------|--------|
| 避免 N+1 | `with(['customer', 'subOrders'])` | 循环中查询关联 |
| 明确列名 | `select('id', 'order_no', 'status')` | `SELECT *` |
| 分页 | 游标分页 `WHERE id > ? LIMIT ?` | `OFFSET` 深分页 |
| 批量操作 | `insert([...])` / `chunk(500)` | 循环单条 SQL |
| 索引 | 复合索引遵循最左前缀 | 过多单列索引 |
| 大表 COUNT | 缓存计数 / 近似值 | `COUNT(*)` 全表 |
### 缓存优化
```php
// Cache-Aside 模式 + TTL 抖动
$data = $cache->withCache("order:{$id}", 300, fn() => Order::find($id));
// 缓存失效:写操作后立即清除
$cache->invalidate("order:{$id}");
$cache->invalidatePattern('orders:list:*');
```
### 协程并发
```php
// 并行无依赖 I/O 操作
$parallel = new Parallel(10);
$parallel->add(fn() => $this->orderService->getStatistics($id));
$parallel->add(fn() => $this->paymentService->getPayments($id));
[$stats, $payments] = $parallel->wait();
```
---
## 服务器性能
### Nginx 优化
```nginx
# Gzip 压缩
gzip on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/typescript image/svg+xml;
# 静态资源长期缓存Vite 产物带 hash
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# HTTP/2
listen 443 ssl http2;
```
### 连接池调优
```php
// MySQL 连接池
'pool' => [
'min_connections' => 5,
'max_connections' => 50,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'max_idle_time' => 60,
],
// Redis 连接池
'pool' => [
'min_connections' => 5,
'max_connections' => 30,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
],
```
---
## 禁止事项
- 前端同步阻塞主线程的操作
- 未压缩的大图片 (> 200KB)
- 无限滚动不做虚拟化
- Swoole Worker 中执行阻塞 I/O (`file_get_contents`, `sleep`)
- 全表扫描无 WHERE 条件
- 事务内包含远程调用
- 单事务操作 > 1000 行