我得老实跟你说:我们的旧 WordPress 网站很尴尬。不是因为它看起来很糟糕——实际上看起来还不错。但是在幕后?3.2 秒的交互时间,Lighthouse 性能评分徘徊在 58 左右,还有一堆插件让每次部署都感觉像在拆除炸弹。我们是一家网络开发机构。我们为客户构建快速网站。而我们自己的网站……并不快。

所以我们拆掉它,用 Astro 重建了。结果:四个 Lighthouse 类别中的完美 100 分——性能、可访问性、最佳实践和 SEO。不是在某个页面。是在每一个页面。这是我们如何做到这一点、过程中出了什么问题,以及我们会做什么不同的故事。

目录

WordPress 到 Astro:我们如何在重建中达到 Lighthouse 100

为什么我们离开 WordPress

看,WordPress 驱动了大约 43% 的网络。这不是个坏平台。我们为客户构建了大量 WordPress 网站,如果合适的话会继续这样做。但对于我们自己的机构网站——一个主要是静态的营销网站加博客——WordPress 的方式太过了。

这是我们的 WordPress 设置:

  • 主题:基于 Sage (Roots.io) 的自定义主题
  • 插件:14 个活跃插件,包括 Yoast SEO、WP Rocket、Advanced Custom Fields Pro、Gravity Forms 和其他几个
  • 托管:WP Engine Professional 计划,每月 $60
  • CDN:Cloudflare Pro,每月 $20
  • 构建复杂性:PHP 模板、Webpack 资源、MySQL 数据库

即使有 WP Rocket 进行积极缓存,我们的 Core Web Vitals 也很平庸。移动设备上的最大内容绘制 (LCP) 是 2.4 秒。累积布局偏移 (CLS) 是 0.12——不算糟糕,但也不好。而且每次更新插件时,都有可能会出问题。

真正的问题是什么?我们每月支付 $80 的托管费用来维护一个仅获得大约 3,000 次访问的网站。这流量不多,对于一个本质上是展示网站加博客的东西来说,这是一笔很大的费用。

临界点

最后一根稻草出现在 2025 年 1 月。WordPress 核心更新破坏了我们的自定义 Gutenberg 块。修复它需要更新 ACF Pro,这需要更新我们主题的 PHP 版本兼容性,这需要更新托管环境。本应是一个例行更新的事情变成了一整天的工作。

我看着我的团队说:"我们告诉客户要去无头架构。我们为什么不吃自己的狗粮呢?"

为什么我们选择 Astro

我们评估了四个重建选项:

框架 优点 缺点 我们的评估
Next.js 我们很熟悉,生态系统很好 对于内容网站来说太重了,需要服务器或边缘运行时 太重了
Astro 以内容为中心,默认不发送 JS,岛屿架构 生态系统较小,较新 完美契合
Eleventy 简单,快速构建,成熟 有限的组件模型,DX 不够现代 次选
Hugo 构建速度快如闪电,单一二进制文件 Go 模板令人痛苦,灵活性有限 不适合我们

我们为客户构建大量 Next.js 项目,这是我们对任何具有动态功能的东西的首选。但对于内容密集的营销网站?Next.js 无论如何都会发送 JavaScript 运行时。即使使用静态导出,您也在向浏览器发送 React。

Astro 的理念引起了我们的共鸣:发送 HTML,仅在需要时添加 JavaScript。他们的岛屿架构意味着您可以拥有一个完全交互式的 React 组件,坐在完全静态的 HTML 旁边,而静态部分则不发送任何 JavaScript。这正是我们需要的。

我们在整个 2024 年也在为客户做更多 Astro 开发工作,所以团队对框架很熟悉。这不是学习练习——这是一个我们已经信任的工具。

内容层问题

我们早期做出的一个决定:我们不会为自己的网站使用无头 CMS。对于客户项目,我们经常推荐 无头 CMS 设置,使用 Contentful、Sanity 或 Storyblok。但对于我们的博客,每个作者都是开发人员,对 Markdown 和 Git 很熟悉?Astro 中的内容集合与提交到仓库的 MDX 文件更简单、更快。

构建时没有 API 调用。没有内容交付网络。没有额外的服务来管理或付费。只是文件夹中的文件。

迁移策略

我们没有进行大爆炸式迁移。这是我们的分阶段方法:

第 1 阶段:内容审计(1 周) 我们使用 wp-cli 导出所有 WordPress 内容,并使用用 turndown(HTML 转 Markdown 转换器)加上一些正则表达式清理构建的自定义脚本将帖子转换为 MDX。当时我们有 47 篇博客文章。其中大约 12 篇已过时或表现不佳,所以我们将这些重定向到相关的较新内容,没有迁移它们。

第 2 阶段:Astro 中的设计系统(2 周) 我们将组件库重建为 Astro 组件。按钮、卡片、部分布局、导航——全部作为 .astro 文件。不需要任何框架。纯 HTML 和带有作用域样式的 CSS。

第 3 阶段:页面构建(2 周) 首页、能力页面、关于、联系、博客列表、个人博客文章、404。我们都用我们的组件库将它们构建为 Astro 页面。

第 4 阶段:性能调优(1 周) 这是 Lighthouse 100 工作真正发生的地方。下面有更多内容。

第 5 阶段:启动和重定向(2 天) 我们为每个旧 URL 设置了适当的 301 重定向,用 Screaming Frog 验证没有任何问题,向 Google Search Console 提交了新站点地图,并进行了 DNS 切换。

总时间表:大约 6 周的兼职工作,同时进行客户项目。

WordPress 到 Astro:我们如何在重建中达到 Lighthouse 100 - 架构

做出差异的架构决策

默认零 JavaScript

我们的整个网站总共发送大约 2KB 的 JavaScript。这不是打字错误。两千字节。其中大部分是用于移动导航切换和分析的小脚本。

这是我们的移动导航——没有框架,没有依赖:

---
// MobileNav.astro
---
<button id="menu-toggle" aria-expanded="false" aria-controls="mobile-menu">
  <span class="sr-only">切换菜单</span>
  <svg><!-- 汉堡菜单图标 --></svg>
</button>
<nav id="mobile-menu" hidden>
  <slot />
</nav>

<script>
  const toggle = document.getElementById('menu-toggle');
  const menu = document.getElementById('mobile-menu');
  
  toggle?.addEventListener('click', () => {
    const expanded = toggle.getAttribute('aria-expanded') === 'true';
    toggle.setAttribute('aria-expanded', String(!expanded));
    menu?.toggleAttribute('hidden');
  });
</script>

Astro 组件中的 <script> 标签会自动打包和去重。它很小,它是 vanilla JS,它在任何地方都有效。

CSS 策略:作用域样式 + 最小全局层

我们对组件级样式使用了 Astro 的内置作用域 CSS,以及一个单一的全局样式表(约 8KB 压缩)用于排版、重置、自定义属性和实用类。没有 Tailwind。我知道这是个有争议的看法。

我们喜欢在较大的应用程序和客户项目中使用 Tailwind。但对于这么小的网站,它增加了我们不需要的构建复杂性和文件大小。我们手写的 CSS 比 Tailwind 的输出要小,即使有清除也是如此。

/* 全局自定义属性 */
:root {
  --color-text: #1a1a2e;
  --color-bg: #ffffff;
  --color-accent: #e94560;
  --color-accent-dark: #c81e45;
  --font-body: 'Inter', system-ui, sans-serif;
  --font-heading: 'Cal Sans', var(--font-body);
  --max-width: 72rem;
  --space-unit: 0.25rem;
}

具有智能预加载的静态生成

每个页面都在构建时静态生成。我们使用 Astro 的内置 prefetch 集成在悬停时预加载链接,使导航感觉瞬间完成:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://socialanimal.dev',
  integrations: [mdx(), sitemap()],
  prefetch: {
    prefetchAll: false,
    defaultStrategy: 'hover',
  },
  build: {
    inlineStylesheets: 'auto',
  },
});

性能优化深度分析

达到 Lighthouse 100 不仅仅是选择正确的框架。Astro 给了你一个领先的开始,但最后 10-15 分需要深思熟虑的努力。这是我们所做的。

图像优化

Astro 的内置 <Image /> 组件处理响应式图像,自动格式转换(WebP/AVIF)、延迟加载以及适当的 width/height 属性以防止 CLS。

---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<Image 
  src={heroImage} 
  alt="Social Animal 开发团队正在处理无头架构"
  widths={[400, 800, 1200]}
  sizes="(max-width: 600px) 400px, (max-width: 900px) 800px, 1200px"
  format="avif"
  fallbackFormat="webp"
  quality={80}
  loading="eager"
/>

对于英雄图像特别是,我们使用 loading="eager",因为它在视口上方。其他所有内容默认获得 loading="lazy"

我们还查看了网站上的每个图像并问:这个真的需要是图像吗?几个装饰元素变成了 CSS 渐变或 SVG。例如,我们的英雄部分背景是一个 CSS 渐变,应用了通过一个微小的内联 SVG 应用的细微噪声纹理。

字体加载策略

字体是 Lighthouse 的杀手。这是我们的方法:

  1. 自己托管一切。 没有 Google Fonts CDN。我们下载了 Inter 和 Cal Sans,从我们自己的域提供。这消除了对 fonts.googleapis.com 的 DNS 查询、TCP 连接和 TLS 握手。

  2. 积极子集。 我们使用 glyphhanger 分析我们实际使用的字符,然后用 pyftsubset 对字体进行子集处理。我们的 Inter Regular WOFF2 从 96KB 降到了 18KB。

  3. 使用 font-display: swap 加上仔细选择的系统字体回退,该字体与指标紧密匹配,最大限度地减少交换期间的布局偏移。

  4. 预加载关键字体文件:

<link rel="preload" href="/fonts/inter-latin-400.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="/fonts/cal-sans-latin-600.woff2" as="font" type="font/woff2" crossorigin />

托管:Cloudflare Pages

我们从 WP Engine($60/月)迁移到 Cloudflare Pages(免费层)。是的,免费。我们的网站完全在 Cloudflare 免费计划的限制范围内——每月 500 次构建、无限带宽、无限请求。

Cloudflare Pages 从 Git 推送部署,从他们的全球边缘网络提供,并自动处理缓存头。对于我们的整个网站,构建时间平均 22 秒。相比之下,我们的 WordPress 设置中缓存清除本身可能花费更长时间。

每月托管成本从 $80 降到了 $0。

关键 CSS 内联

当您设置 build.inlineStylesheets: 'auto' 时,Astro 会自动内联小样式表。对于我们的页面,每个关键样式都内联在 <head> 中,这意味着没有渲染阻止的 CSS 请求。浏览器可以立即开始绘制。

第三方脚本纪律

这是大多数网站丢失完美分数的地方。每个第三方脚本都是一个潜在的性能灾难。我们无情地限制了我们的脚本:

  • 分析:从 Google Analytics(70KB+ JavaScript)切换到 Plausible Analytics(< 1KB 脚本,异步加载)。我们为 Plausible 支付 $9/月,数据质量对我们的需求来说真的更好。
  • 表格:我们位于 /contact 的联系表使用一个简单的 HTML 表,通过 Cloudflare Pages 函数进行服务器端处理。没有 JavaScript 表库。
  • 没有聊天小部件。 没有社交媒体嵌入。没有 cookie 同意横幅(我们不使用需要同意的 cookie)。

Lighthouse 100 成绩单

以下是我们截至 2025 年 5 月的实际 Lighthouse 分数,使用 Chrome DevTools 在受限连接(Lighthouse 默认移动模拟)上测量:

指标 分数
性能 100
可访问性 100
最佳实践 100
SEO 100
首次内容绘制 0.6s
最大内容绘制 0.8s
总阻止时间 0ms
累积布局偏移 0
速度指标 0.8s

0ms 的总阻止时间是我最喜欢的统计数据。零。基本上没有 JavaScript 阻止主线程。曾经。

前后对比:数字

指标 WordPress(之前) Astro(之后) 改进
Lighthouse 性能 58 100 +72%
LCP(移动) 2.4s 0.8s 快 3 倍
CLS 0.12 0 消除
TBT 380ms 0ms 消除
页面权重(首页) 1.8MB 142KB 小 92%
HTTP 请求 47 6 减少 87%
发送的 JavaScript 340KB 2KB 减少 99.4%
每月托管成本 $80 $9(仅 Plausible) 便宜 89%
构建/部署时间 3-5 分钟 22 秒 快 ~10 倍
首字节时间 420ms 18ms 快 23 倍

页面权重的减少甚至令我们感到震惊。从 1.8MB 到 142KB。这就是停止发送 jQuery、React、WP Rocket 的脚本加载器、Yoast 的架构标记注入器以及十四个插件样式表的结果。

我们一路上搞错的地方

这不是一帆风顺的。坦诚时刻。

错误 1:我们几乎过度工程化了内容管理

我们最初的本能是为博客设置 Sanity 作为无头 CMS。我们花了两天时间配置架构并设置 Sanity Studio,然后退一步问:"谁实际上会使用这个?"答案是……我们。开发人员。他们完全乐意在 VS Code 中编写 MDX。我们拆掉 Sanity,转向 Astro 内容集合。节省了持续的成本和复杂性。

错误 2:字体子集破坏了特殊字符

我们最初的字体子集太激进了。我们删除了我们认为永远不会使用的字符,然后发布了一篇包含 em dash 和几个花引号的博客文章,它们显示为方块。课程:用实际内容测试你的子集,而不仅仅是"ABCDEFG"。

错误 3:我们忘记了 OpenGraph 图像

我们推出时没有动态 OG 图像。当有人在 Twitter/X 或 LinkedIn 上分享博客文章时,它显示了一个通用的回退。我们必须回过头来使用 @astrojs/og(它在幕后使用 Satori)构建一个 OG 图像生成管道。应该在原始范围内。

错误 4:301 重定向映射有漏洞

尽管使用 Screaming Frog 映射旧 URL,我们仍然错过了一些外部网站被热链接的图像 URL。我们在启动约一周后在 Cloudflare 的分析中发现了这些,并添加了缺失的重定向。始终在迁移后检查您的服务器日志——Google Search Console 不会捕获所有内容。

您自己迁移的经验

如果您考虑从 WordPress 迁移到静态优先框架,这是我要告诉你的:

  1. 迁移前进行审计。 删除表现不佳的内容。迁移是修剪的绝好机会。

  2. 将工具与工作相匹配。 Astro 对我们来说很完美,因为我们主要是内容。如果您需要大量交互,Next.js 或类似框架可能更好。

  3. 不要复制粘贴你的旧架构。 我们没有尝试在 Astro 中复制我们的 WordPress 设置。我们从头开始重新考虑一切。我们是否真的需要表单插件?不,一个 <form> 元素加上一个无服务器函数就可以了。

  4. 事前测量,事后测量,持续测量。 我们在 GitHub Actions 中设置了一个 Lighthouse CI 作业,在每个拉取请求上运行。如果 PR 将任何分数降低到 95 以下,它会失败检查。

  5. 为"最后 5%"预算。 从 Lighthouse 85 到 95 很简单。从 95 到 100 需要字体子集、关键 CSS 分析、图像格式优化和第三方脚本审计。为此计划时间。

  6. 您的托管成本应该让您的旧设置感到尴尬。 如果您正在提供静态文件但仍在支付大量托管费用,那么出了问题。静态托管现在是一个商品。

如果您对像这样的迁移对您的项目会是什么样子感兴趣,请查看我们的 定价页面与我们联系。我们现在为多个客户完成了这个迁移路径,性能收益始终很显著。

常见问题

将 WordPress 网站迁移到 Astro 需要多长时间? 对于我们的网站(包括博客文章大约 50 页),大约花费了 6 周的兼职工作。有数百篇文章和复杂自定义文章类型的较大网站可能需要 8-12 周。实际开发通常比内容审计和重定向映射要快。

您可以用 Next.js 代替 Astro 获得 Lighthouse 100 吗? 这是可能的,但要困难得多。Next.js 即使对静态页面也会向浏览器发送 JavaScript 运行时(React 水合层)。您可以接近——95-99 的分数对于内容网站来说是可以通过仔细优化实现的。但 Astro 的零 JS 默认方法使内容网站的完美分数更容易实现。

WordPress 功能呢,比如联系表单和搜索? 联系表单可以使用普通 HTML 表单和无服务器函数后端(Cloudflare Pages 函数、Netlify 函数等)正常工作。对于搜索,我们使用带有 Pagefind 的客户端搜索,它在构建时生成搜索索引,仅发送 5KB 的 JavaScript。它快速且可以离线工作。

从 WordPress 迁移到 Astro 会伤害 SEO 吗? 如果处理正确,则不会。我们为每个 URL 设置了 301 重定向,尽可能保持了我们的 URL 结构,提交了新站点地图,并保留了所有结构化数据。我们的有机流量实际上在迁移后的三个月内增长了 23%,可能是由于 Core Web Vitals 的改进。

如何在 Astro 网站上处理动态内容,如博客评论? 我们的博客上没有评论——它们在 WordPress 上基本上都是垃圾邮件。如果您需要评论,Giscus(基于 GitHub Discussions)或 Hyvor Talk 等服务作为嵌入式组件可以很好地工作。它们作为 Astro 岛屿加载,因此不会影响初始页面加载。

Astro 对大型网站生产就绪吗? 绝对是。Astro 5.x(于 2024 年末发布)成熟且稳定。Porsche、Google、Microsoft 和 Netlify 等公司在生产中使用它。构建性能也能很好地扩展——具有数千页的网站在正确配置下在一分钟内构建。

与 WordPress 相比,持续维护是什么样的? 戏剧性地更少。没有插件更新、没有数据库维护、没有 PHP 安全补丁。我们每月通过 Dependabot PRs 更新 Astro 及其依赖关系大约一次。每次更新花费大约 5 分钟来审查和合并。相比之下,WordPress 更新跑步机。

非技术团队成员仍然可以在 Astro 网站上编辑内容吗? 使用我们的设置(Git 中的 MDX 文件),您需要熟悉 Markdown 和基本的 Git 工作流。对于拥有非技术编辑的团队,我们建议将 Astro 与无头 CMS(如 Sanity、Contentful 或 Storyblok)配对。编辑获得可视界面,您仍然获得静态生成的所有性能优势。