Lighthouse 95+ 优化实战:SaaS 性能指南

实现 Lighthouse 95+ 得分的分步指南,覆盖 Core Web Vitals、SSR 优化、代码分割和图片优化策略,帮助 SaaS 应用提升转化率。

Alex Chen
Alex Chen
June 5, 202611 min read
其他语言:Deutsch · English

TL;DR: 达成 Lighthouse 95+ 不是在追逐一个数字——而是在构建一个直接影响 SaaS 转化率的高性能体验。本指南涵盖 Core Web Vitals 优化、流式 SSR、Critical CSS、代码分割、图片优化和缓存策略,每条建议均可落地并已在生产环境验证。文末附 30 条检查清单。


引言:为什么 Lighthouse 95+ 对 SaaS 如此重要

在 SaaS 领域,每毫秒都至关重要。Google 的研究反复证明,移动端页面加载延迟 1 秒,转化率下降高达 20%。对于一款月 ARPU 为 100 美元、月新增注册 1 万人的 B2B SaaS 产品,这一延迟意味着每年超过 200 万美元的收入损失。

但影响远不止于此:

  • SEO 排名: Google 将 Core Web Vitals 作为排名信号。Lighthouse 得分低于 50 的网站难以获得有竞争力的排名。
  • 用户信任: Lighthouse 得分与用户感知的可靠性高度相关。
  • 广告投放效率: Google Ads 质量得分越低,每次点击成本越高。

Lighthouse 95+ 是一个复合增长杠杆,同时作用于获客、激活和留存。


理解 Core Web Vitals

指标衡量内容目标值
LCP (Largest Contentful Paint)加载性能<= 2.5s
CLS (Cumulative Layout Shift)视觉稳定性<= 0.1
INP (Interaction to Next Paint)交互响应<= 200ms

性能预算:从第一天起设定目标

为以下指标定义预算:

  • JavaScript 打包体积: 关键路由 150 KB(压缩后),上限 300 KB
  • 可交互时间: 3G 网络下 < 3s
  • LCP: < 2.0s
  • 单页总重量: < 500 KB(压缩后)

在 CI 中强制执行:

javascript
// lighthouse-budget.js
module.exports = {
  ci: {
    collect: { numberOfRuns: 3, settings: { preset: 'desktop' } },
    assert: {
      assertions: {
        'categories:performance': ['error', { minScore: 0.95 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
        'total-blocking-time': ['error', { maxNumericValue: 200 }],
      },
    },
  },
};

LCP 优化

1. 流式 SSR

流式 SSR 将 HTML 逐步推送给浏览器,通过立即渲染首屏内容显著改善 LCP。关于流式 SSR 的底层原理,可参阅我们的流式 SSR 深度解析。TanStack Start 开箱即支持流式 SSR:

tsx
const router = createRouter({
  routeTree,
  defaultPreload: 'intent',
  // Streaming is enabled by default in TanStack Start
});

部署在 Cloudflare Workers 上时,流式 SSR 利用边缘基础设施将 TTFB 降至最低,并从距离用户最近的节点交付 HTML,进一步放大了服务端渲染的性能优势。

2. Critical CSS

将首屏内容所需的 CSS 内联,其余延迟加载:

html
<head>
  <style>
    /* Critical CSS — inline above-the-fold styles */
    header, .hero, .cta-button { /* essential styles */ }
  </style>
  <link rel="preload" href="/styles/full.css" as="style"
        onload="this.onload=null;this.rel='stylesheet'" />
  <noscript><link rel="stylesheet" href="/styles/full.css" /></noscript>
</head>

3. 字体加载

使用 font-display: swap 并预加载主字体:

css
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-display: swap;
  font-weight: 100 900;
}

在 HTML head 中预加载:

html
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin />

4. 优化 LCP 元素

  • 预加载: <link rel="preload" as="image" href="/hero.webp" />
  • 使用响应式图片适配不同视口
  • 不要对 LCP 元素使用懒加载

CLS 优化

1. 设置明确尺寸

html
<img
  src="/dashboard-screenshot.webp"
  width="1200"
  height="675"
  alt="Dashboard preview"
  loading="lazy"
/>

2. 字体后备指标

css
@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial');
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

3. 为动态内容预留空间

css
.newsletter-signup-placeholder {
  min-height: 120px;
  /* Reserve space while async content loads */
}

JavaScript 优化

1. 基于路由的代码分割

TanStack Router 原生支持基于路由的代码分割:

tsx
// routes/dashboard.tsx
export const Route = createLazyRoute('/dashboard')({
  component: DashboardComponent,
});

2. Tree Shaking

  • 使用命名导入:import { useQuery } from '@tanstack/react-query'
  • 标记无副作用的包:"sideEffects": false

3. 懒加载非关键代码

html
<script>
  window.addEventListener('load', () => {
    setTimeout(() => {
      const script = document.createElement('script');
      script.src = 'https://widget.example.com/loader.js';
      script.async = true;
      document.body.appendChild(script);
    }, 3000);
  });
</script>

图片优化

1. 使用 srcset 的响应式图片

html
<img
  src="/hero-1200.webp"
  srcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1200.webp 1200w"
  sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
  width="1200" height="675" alt="Product dashboard"
/>

2. 现代格式:WebP 和 AVIF

html
<picture>
  <source srcset="/hero.avif" type="image/avif" />
  <source srcset="/hero.webp" type="image/webp" />
  <img src="/hero.jpg" width="1200" height="675" alt="Hero" />
</picture>

缓存策略

1. CDN 缓存

Cache-Control: public, max-age=31536000, immutable  # Versioned assets
Cache-Control: public, max-age=3600, s-maxage=86400  # HTML pages

2. TanStack Query 缓存

tsx
const { data } = useQuery({
  queryKey: ['pricing-plans'],
  queryFn: fetchPricingPlans,
  staleTime: 5 * 60 * 1000,
  gcTime: 30 * 60 * 1000,
});

30 条性能检查清单

关键项

  • 已识别并预加载 LCP 元素
  • 所有图片均设置了明确宽高
  • Critical CSS 已内联,完整 CSS 延迟加载
  • 自定义字体使用 font-display: swap
  • 无阻塞渲染的第三方脚本
  • LCP 图片使用 WebP/AVIF + 响应式 srcset
  • 服务器响应时间(TTFB)< 800ms
  • 已实现基于路由的代码分割
  • 已移除或延迟加载未使用的 JavaScript
  • 首屏大图未使用懒加载

高优先级

  • 所有光栅图片已转换为 WebP 或 AVIF
  • 已调优字体后备指标
  • 第三方嵌入元素已预留空间
  • 分析类脚本在 onLoad 后加载
  • 已识别并拆分耗时任务(>50ms)
  • JavaScript 打包使用 Brotli 压缩
  • 静态资源使用 immutable 缓存头
  • CDN 已为所有资源类型配置
  • TanStack Query staleTime 设置合理
  • Service Worker 缓存 API 响应

中优先级

  • 所有图片使用懒加载(LCP 元素除外)
  • 关键域名添加 preconnect 提示
  • 分析类域名添加 dns-prefetch
  • HTML 已压缩
  • CSS 已压缩并清除未使用规则
  • 首屏无阻塞渲染的 JS
  • 关键 API 路由已预加载
  • 谨慎使用 will-change
  • 每次页面加载的 301 重定向最小化
  • 在每个 PR 中运行 Lighthouse CI

结语

Lighthouse 95+ 的意义在于构建一个快速、可靠、令人愉悦的用户体验,从而直接推动 SaaS 业务增长。方法论是系统化的:

  1. 写代码前先设定预算
  2. 在实验室和真实环境中持续测量
  3. 优化关键路径: 流式 SSR、Critical CSS、字体加载、图片
  4. 控制 JavaScript: 路由分割 + 延迟加载
  5. 激进缓存所有内容

从检查清单开始,先抓关键项。在每个 PR 中运行 Lighthouse CI。你的用户——和你的收入——都会为此感谢你。完整的优化型 SaaS 应用部署实战演示,请参阅 TanStack Start 部署指南。