mcpField
O
optimize

optimize

github.com/aladicf开发561 次安装8 周前更新
代码仓库

关于 optimize

帮助团队优化 Web 界面的性能技能。它建议先测量并定位瓶颈,再处理加载、渲染、动画、React 和网络开销。

主要功能

  1. 01测量性能并分析瓶颈
  2. 02优化图片、字体与代码包
  3. 03提供渲染和动画优化指导
  4. 04React 性能分析与优化
  5. 05改进网络请求与加载

适用场景

  1. 01排查交互响应缓慢
  2. 02降低页面初始加载开销
  3. 03改善长列表渲染
  4. 04调查布局与动画问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/aladicf/better-react-web-ui --skill optimize

安装后在 Claude Code 中输入/optimize确认已加载。

详细介绍

识别并修复性能问题,打造更快速、流畅的用户体验。

如果图像性能问题涉及截图尺寸、图标缩放、裁剪策略或用户上传媒体的处理,请参阅图像处理。 如果性能问题源于测量大量换行文本块、虚拟化变高列表、反复调整大小后重新布局,或文本密集型 UI 热路径中的 DOM 读取(如 offsetHeight / getBoundingClientRect()),请参阅文本布局预测。 如果优化工作的重点是 LCP、INP 或 CLS,且需要更深入的子项拆解,或关于实测与实验室测量的指导,请参阅核心 Web 指标参考。 如果项目需要对超长列表进行虚拟化,且技术栈尚未确定,那么对于受支持的 React 项目,优先默认使用 TanStack Virtual 作为无头虚拟化层。如果项目已使用其他虚拟化层,则优先保留现有方案。

必须完成的准备工作

阅读 frontend-design,并遵循其中的上下文收集流程。复用可用上下文,只针对会造成重大影响的信息缺口进行询问。此外,还要了解:目标设备、性能限制,以及哪些用户交互让人感觉缓慢。

评估性能问题

了解当前性能并找出问题:

  1. 测量当前状态:
    • 核心 Web 指标:LCP、FID/INP、CLS 分数
    • 加载时间:可交互时间、首次内容绘制时间
  • 交互延迟:筛选、搜索、保存、打开面板、自动补全及其他重复操作的响应时间
  • 包大小:JavaScript、CSS、图像的大小
  • 运行时性能:帧率、内存使用量、CPU 使用率
  • 网络:请求数量、负载大小、瀑布图
  1. 找出瓶颈:
    • 哪些地方很慢?(初始加载?交互?动画?)
    • 是什么导致的?(图像过大?JavaScript 开销过高?布局抖动?)
    • 问题有多严重?(能否察觉?是否恼人?是否阻塞操作?)
  • 影响哪些用户?(所有用户?窄屏布局用户?网络连接较慢的用户?)

重要:优化前后都要测量。过早优化会浪费时间。只优化真正重要的问题。

优化策略

制定系统的改进计划:

交互速度的多尔蒂阈值

常规交互应保持用户操作流畅。力求让用户立即看到响应,并尽可能让交互在大约 400ms 内完成。

如果处理时间会超过这个范围:

  • 在约 100ms 内提供即时反馈(按下、激活、加载、乐观状态)
  • 尽早流式传输或显示部分内容,而不是等到全部完成
  • 为常见操作路径预取可能访问的下一屏或数据
  • 优先使用骨架屏、乐观 UI 和渐进式渲染,避免空等和通用加载指示器

对于高频操作,如果界面可以通过响应用户意图来保持操作流畅,就不要只依赖加载指示器作为主要体验。

加载性能

优化图像:

  • 使用现代格式(WebP、AVIF)
  • 使用合适的尺寸(不要为 300px 的显示区域加载 3000px 的图像)
  • 对首屏以下的图像进行延迟加载
  • 首屏中立即可见的图像应立即加载。使用已安装框架推荐的图像处理约定,为可能的 LCP 图像设置优先级。请参阅浏览器图像加载。
  • 使用响应式图像(srcset、picture 元素)
  • 压缩图像(通常 80-85% 的质量损失难以察觉)
  • 使用 CDN 加快传输速度
<img
  src="hero.webp"
  srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
  sizes="(max-width: 400px) 400px, (max-width: 800px) 800px, 1200px"
  loading="eager"
  fetchpriority="high"
  alt="Hero image"
/>

现代图像格式策略(AVIF 和 WebP):

在视觉质量相当的情况下,AVIF 通常比 WebP 小 30-50%。WebP 的基础兼容性更广。两种格式都应使用,并提供回退方案:

<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="Hero image" loading="eager" fetchpriority="high">
</picture>

实用规则:

  • 对主视觉图片、大型背景图和以照片为主且最需要节省体积的图库生成 AVIF
  • 保留 WebP 作为回退格式,以兼容更多浏览器
  • 对体积很小的图标或简单图形,不要使用 AVIF,因为编码开销可能超过节省的空间
  • 尽可能使用能自动处理格式协商的图片 CDN
  • 在低端设备上测试 AVIF 解码速度;这种格式体积更小,但解码速度可能比 WebP 慢

减小 JavaScript 包体积:

  • 代码拆分(按路由、按组件)
  • Tree shaking(移除未使用的代码)
  • 移除未使用的依赖项
  • 延迟加载非关键代码
  • 使用动态导入加载大型组件
// Lazy load heavy component
const HeavyChart = lazy(() => import('./HeavyChart'));

优化 Tailwind 输出:

  • 保持 Tailwind 类名静态可发现,以便构建过程只生成正在使用的工具类
  • 避免使用范围过广的 safelist 和运行时构建的类字符串,以免生成大量输出
  • 相较于临时样式方案,优先使用 Tailwind 主题令牌、工具类和变体
  • 仅对能从隔离中受益的独立区域使用 CSS containment 工具类或 Tailwind 任意属性

优化字体:

  • 使用 font-display: swap 或 optional
  • 对字体进行子集化(仅保留所需字符)
  • 预加载关键字体
  • 适当时使用系统字体
  • 限制加载的字体粗细
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap; /* Show fallback immediately */
  unicode-range: U+0020-007F; /* Basic Latin only */
}

字体子集化策略:

子集化会移除未使用的字形,大幅减小文件体积。完整的拉丁字体可能有 200KB;同一字体经过 Basic Latin 子集化后,体积可降至 20-30KB。

方法:

  • 静态子集化:按语言或文字系统(拉丁文、西里尔文、CJK)生成独立字体文件,并通过 unicode-range 仅提供页面所需的字体
  • 动态子集化:使用 Google Fonts 等服务,或使用可自托管的子集化工具按需生成字体切片
  • 关键字形子集化:对于首屏主视觉文本,仅保留标题中使用的字符并预加载该字体文件
/* Latin-only subset for body text */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-latin.woff2') format('woff2');
  font-display: swap;
  unicode-range: U+0020-007F, U+00A0-00FF;
}

/* Extended subset for other scripts, loaded only when needed */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-cyrillic.woff2') format('woff2');
  font-display: swap;
  unicode-range: U+0400-04FF;
}

子集化工具:

  • 使用 pyftsubset(fonttools)进行精确的手动子集化
  • 使用 subfont 在构建时自动进行子集化
  • 使用 glyphhanger 提取 HTML/CSS 中使用的字形

Tailwind 交付策略:

让 React 框架和 Tailwind 流程负责生成样式的交付。目标是让生成的 Tailwind 输出保持精简并适配路由,而不是添加手写的样式加载模式。

重要性:

  • 大量生成的 Tailwind 输出可能会延迟 First Contentful Paint
  • 范围过广的 safelist 和动态类名构造往往会生成未使用的工具类
  • 框架级打包比手动预加载样式模式更可靠

实现方法:

  • 保持工具类为字面量,或使用 clsx 等框架支持的辅助工具,并提供已知的类名字符串
  • 保持 safelist 范围精简,并记录说明
  • 拆分负载较重的路由和 islands,使其 React、媒体和组件库代码仅在需要时加载
  • 在性能优化过程中验证生成的 Tailwind 输出体积
  • 对 React、Next.js、React Router、TanStack Start、Vite React 或 Astro React islands,使用框架推荐的 Tailwind 集成方式

优化加载策略:

  • 优先加载关键资源(对非关键资源使用 async/defer)
  • 预加载关键资源
  • 预获取可能访问的后续页面
  • 使用 service worker 实现离线支持和缓存
  • 使用 HTTP/2 或 HTTP/3 实现多路复用

使用容器查询实现组件级响应式布局:

容器查询可让组件根据自身容器的大小而非视口进行适配。这样可以减少对页面级断点覆盖的需求,并提高组件的可复用性。

适用场景:

  • 组件会出现在多个上下文中(侧边栏、主列、模态框)
  • 组件布局应取决于可用空间,而非设备宽度
  • 希望减少页面级断点的数量

请参阅 容器查询参考,了解语法、实用模式和浏览器支持。 性能说明:

  • 容器查询的运行时开销极小;它们与媒体查询一样在合成器上运行
  • 除非确实需要同时查询两个维度,否则优先使用 container-type: inline-size,而不是 size
  • 避免在每个元素上都创建包含上下文;仅在组件需要查询其容器时创建
渲染性能

避免布局抖动:

// ❌ Bad: Alternating reads and writes (causes reflows)
elements.forEach(el => {
  const height = el.offsetHeight; // Read (forces layout)
  el.style.height = height * 2; // Write
});

// ✅ Good: Batch reads, then batch writes
const heights = elements.map(el => el.offsetHeight); // All reads
elements.forEach((el, i) => {
  el.style.height = heights[i] * 2; // All writes
});

优化渲染:

  • 使用 Tailwind 包含工具类或 [contain:*] 任意属性划分独立区域
  • 尽量减少 DOM 深度(层级越浅,速度越快)
  • 减少 DOM 大小(元素越少越好)
  • 对较长的列表使用 content-visibility: auto
  • 对超长列表使用虚拟滚动——架构尚未确定时优先选择 TanStack Virtual;如果项目已有虚拟化方案,则优先保留现有方案
  • 对文本密集且高度可变的列表或卡片,如果真正的瓶颈是文本换行,优先使用预测式文本测量,避免反复实时读取 DOM 高度

减少绘制和合成:

  • 使用 transform 和 opacity 制作动画(由 GPU 加速)
  • 避免对布局属性进行动画处理(width、height、top、left)
  • 仅当测量结果表明临时且作用范围狭窄的 will-change 能改善动画瓶颈时才添加;之后将其移除。单纯缺少 will-change 并不是问题。
  • 尽量缩小绘制区域(越小越快)
动画性能

GPU 加速:

/* ✅ GPU-accelerated (fast) */
.animated {
  transform: translateX(100px);
  opacity: 0.5;
}

/* ❌ CPU-bound (slow) */
.animated {
  left: 100px;
  width: 300px;
}

流畅的 60fps:

  • 目标是每帧耗时 16ms(60fps)
  • 使用 requestAnimationFrame 实现 JS 动画
  • 对滚动处理程序进行防抖/节流
  • 尽可能使用 Tailwind 工具类、兼容 Tailwind 的关键帧或 WAAPI
  • 避免在动画期间运行耗时较长的 JavaScript

Intersection Observer:

// Efficiently detect when elements enter viewport
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // Element is visible, lazy load or animate
    }
  });
});
React 优化

React 专项:

  • 在添加记忆化之前,先分析具有代表性的交互。引入手动缓存前,先与项目的 React Compiler 配置保持一致。
  • 当重复渲染成本高且 props 不变已被测量证实为瓶颈时,使用 memo()
  • 对经测量确认计算开销较大的计算使用 useMemo()。仅当稳定的函数标识能带来已证实的优化,或消费者有此要求时,才使用 useCallback()
  • 对较长的列表进行虚拟化
  • 对路由进行代码拆分
  • 除非内联回调的标识变化造成了经测量确认的问题,否则保留内联回调。
  • 使用 React DevTools Profiler

React 框架模式:

  • 尽量减少可避免的重复渲染
  • 对开销较大的操作进行防抖
  • 在分析结果表明有价值时,对计算出的值进行记忆化
  • 使用框架推荐的模式延迟加载路由和组件
网络优化

减少请求:

  • 合并小文件
  • 使用 SVG 精灵图存放图标
  • 内联较小的关键资源
  • 移除未使用的第三方脚本

优化 API:

  • 使用分页(不要一次加载所有内容)
  • 使用 GraphQL 仅请求所需字段
  • 压缩响应(gzip、brotli)
  • 使用 HTTP 缓存头
  • 使用 CDN 提供静态资源

针对慢速连接进行优化:

  • 根据连接情况进行自适应加载(navigator.connection)
  • 乐观地更新 UI
  • 对请求进行优先级排序
  • 渐进增强

Core Web Vitals 优化

最大内容绘制(LCP < 2.5s)
  • 优化首屏主视觉图片
  • 保持生成的 Tailwind 输出精简,并避免在 LCP 元素出现前加载不必要的路由或 island 代码
  • 预加载关键资源
  • 使用 CDN
  • 使用服务器端渲染
首次输入延迟(FID < 100ms)/ INP(< 200ms)
  • 拆分长任务
  • 延迟执行非关键 JavaScript
  • 使用 Web Worker 处理繁重计算
  • 减少 JavaScript 执行时间
累积布局偏移(CLS < 0.1)
  • 为图片和视频设置尺寸
  • 不要在现有内容上方注入内容
  • 使用 Tailwind aspect-ratio 工具类
  • 为广告/嵌入内容预留空间
  • 避免导致布局偏移的动画
/* Reserve space for image */
.image-container {
  aspect-ratio: 16 / 9;
}

性能监控

可使用的工具:

  • Chrome DevTools(Lighthouse、Performance 面板)
  • WebPageTest
  • Core Web Vitals(Chrome UX Report)
  • Bundle 分析器(webpack-bundle-analyzer)
  • 性能监控工具(Sentry、DataDog、New Relic)

关键指标:

  • LCP、FID/INP、CLS(Core Web Vitals)
  • 可交互时间(TTI)
  • 首次内容绘制(FCP)
  • 总阻塞时间(TBT)
  • Bundle 大小
  • 请求数

重要:在真实设备和真实网络条件下进行测量。使用快速网络连接的宽屏本地浏览器并不能代表真实情况。

切勿:

  • 不经测量就进行优化(过早优化)
  • 为了性能牺牲无障碍性
  • 在优化过程中破坏功能
  • 到处使用 will-change(会创建新的图层并占用内存)
  • 延迟加载首屏内容
  • 忽视重大问题,只优化微小问题(先优化最大的瓶颈)
  • 忽视受限浏览器的性能(硬件通常较慢、CPU 预算更紧张、网络连接更慢)

验证改进效果

测试优化是否生效:

  • 优化前后指标:比较 Lighthouse 分数
  • 真实用户监控:跟踪真实用户的体验改进
  • 不同设备:在低功耗粗指针设备和主流精确指针浏览器上测试
  • 慢速连接:限速至 3G,测试体验
  • 无回归问题:确保功能仍然正常
  • 用户感知:使用起来是否感觉更快?

请记住:性能是一项功能。快速的体验给人的感觉是响应更灵敏、更精致、更专业。系统地优化,严格地测量,并优先提升用户感知到的性能。

评论

支持 Markdown