工程 5 分钟阅读

Astro 4.8 博客系统完整实现 - 包含 AI 翻译和 E2E 测试的全面方法

基于 Astro Content Collections 实现高性能博客系统的开发记录。详细介绍使用 Google Gemini API 进行 AI 自动翻译、Playwright E2E 测试以及速率限制功能的全面开发过程。

Terisuke
Share this article:

概述

最近的开发工作中,我们基于 Astro 4.8.7 实现了一个功能全面的博客系统。这个系统不仅仅是简单的 Markdown 显示,而是一个现代化的技术博客平台,集成了 AI 自动翻译、端到端(E2E)测试以及为实际运营而设计的各项功能。

告别了 WordPress 中与小部件(Widgets)的纠缠。现在,你可以让 AI 来翻译,自动化测试,然后让工程师们安心睡觉(开玩笑的)。

技术栈

核心技术

  • Astro 4.8.7: 基于 Islands Architecture 的高速静态站点生成器 (SSG)
  • TypeScript: 类型安全的开发环境
  • Tailwind CSS: 采用 Utility-first 方式进行样式设计
  • Alpine.js 3.14.0: 轻量级前端 JavaScript 框架

博客专属功能

  • Content Collections: Astro 中提供类型安全的 Content 管理功能
  • Google Gemini API: AI 自动翻译引擎
  • Playwright: 端到端 (E2E) 测试自动化工具
  • remark-link-card-plus: 生成丰富的链接卡片

核心架构实现

1. Content Collections 设计

我们从传统的 Markdown 文件管理转向了 Astro 的 Content Collections。这样就再也不用担心“咦?这个 frontmatter 的写法是不是对的?”了:

// src/content/config.ts
const blogCollection = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    category: z.enum(['ai', 'engineering', 'founder', 'lab']),
    tags: z.array(z.string()).default([]),
    lang: z.enum(['ja', 'en']).default('ja'),
    featured: z.boolean().default(false),
  }),
});

优点:

  • 构建时进行类型验证,防止元数据错误
  • 热重载 (Hot reloading),实现实时更新
  • 自动化的 Schema 验证

2. AI 翻译系统设计

我们利用 Google Gemini API 构建了自动翻译系统。过去需要数天才能完成的人工翻译,现在 AI 可以在几秒钟内搞定,而且还不抱怨:

// scripts/translate-blog.js
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
const model = genAI.getGenerativeModel({
  model: "gemini-2.5-flash-lite-preview-06-17"
});

async function translateBlogPost(japaneseContent) {
  const prompt = `Translate the following Japanese blog post to English.
  Translate technical terms appropriately and make it readable English:

${japaneseContent}`;

  const result = await model.generateContent(prompt);
  return result.response.text().trim();
}

特点:

  • 速率限制: 保守地设置为每分钟 15 个请求
  • 错误处理: 采用指数退避 (Exponential Backoff) 策略进行重试
  • YAML 安全性: 对 frontmatter 进行恰当的转义处理

3. 速率限制系统

为了 API 的稳定运行,我们实现了速率限制功能。这样就不会被 Google 警告“你请求太多了!”:

// scripts/rate-limiter.js
class RateLimiter {
  constructor({ requestsPerMinute = 15, maxRetries = 3 }) {
    this.requestsPerMinute = requestsPerMinute;
    this.maxRetries = maxRetries;
    this.requestTimes = [];
  }

  async executeWithRetry(operation, description) {
    for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
      try {
        await this.checkRateLimit();
        return await operation();
      } catch (error) {
        if (attempt === this.maxRetries) throw error;
        await this.backoff(attempt);
      }
    }
  }
}

4. E2E 测试实现

我们使用 Playwright 实现了对博客功能的全面测试。不能再简单地认为“能跑就行”了:

// e2e/blog.spec.ts
test.describe('Blog functionality', () => {
  test('should navigate to Japanese blog', async ({ page }) => {
    await page.goto('/blog/');
    await expect(page.locator('h1')).toContainText('技術ブログ');
  });

  test('should display OGP image for blog posts', async ({ page }) => {
    await page.goto('/blog/');
    const firstPost = page.locator('[data-testid="blog-post"]').first();
    await firstPost.click();

    const ogImage = page.locator('meta[property="og:image"]');
    await expect(ogImage).toHaveAttribute('content', /\/og\/.*\.svg/);
  });
});

性能优化

压缩与优化设置

// astro.config.mjs
integrations: [
  compress({
    CSS: true,
    HTML: {
      'remove-comments': true,
      'minify-js': true,
      'minify-css': true
    },
    JavaScript: true,
    SVG: true
  }),
  compressor({
    gzip: true,
    brotli: true
  })
]

图片优化

  • 以 AVIF 格式提供图片
  • 提供 WebP 作为回退选项
  • 响应式图片尺寸(480w, 800w)

挑战与解决方案

1. YAML Frontmatter 转义问题

挑战: 当翻译后的标题或描述包含特殊字符时,会导致 YAML 解析错误。

解决方案:

function escapeYAMLString(str) {
  return str
    .replace(/\\/g, "\\\\") // 先转义反斜杠
    .replace(/"/g, '\\"');   // 再转义双引号
}

2. API 速率限制应对

挑战: Gemini API 的限制导致请求失败。

解决方案: 指数退避与智能速率限制

  • 基于秒的延迟
  • 最大延迟扩展至 60 秒
  • 通过追踪请求时间进行预先限制

3. E2E 测试的稳定性

挑战: 动态内容导致测试不稳定。

解决方案: 使用 data-testid 属性进行可靠的元素定位。

运营流程

新文章发布流程

  1. 创建日语文章: 在 /src/content/blog/ja/ 目录下创建 Markdown 文件。
  2. AI 翻译: 运行 npm run translate src/content/blog/ja/article-name.md
  3. 执行测试: 运行 npm run test:e2e
  4. 构建: 运行 npm run build
  5. 部署: 自动部署到 Firebase Hosting。

质量保证

  • 类型检查: 通过 TypeScript 在编译时进行检查。
  • Schema 验证: 使用 Zod 进行内容验证。
  • E2E 测试: 使用 Playwright 进行功能测试。

学习心得

1. Content Collections 的强大之处

与传统的基于文件管理相比,类型安全性和开发体验得到了极大的提升。特别是,当 Schema 发生变更时,影响范围会变得非常清晰,使得重构更加安全。

现在 TypeScript 会“报错”告诉你“类型不匹配!”,这样就再也不会因为运行时错误而惊慌失措了。太棒了。

2. AI 翻译的实用性

Google Gemini API 在技术文章翻译方面的质量非常高,大大减少了人工微调的工作量。但专业术语的一致性方面仍需持续改进。

当我看到“npm”被翻译成“エヌピーエム”(NPM 的日语音译)时,我笑了。虽然也不能说错,但确实有点意思。

3. E2E 测试的重要性

即使是静态站点生成器,对于路由、元数据生成等复杂功能,E2E 测试也必不可少。

真想给自己两巴掌,过去居然认为“静态网站不需要测试”。

性能结果

  • 首次内容绘制 (First Contentful Paint): 0.8 秒
  • 最大内容绘制 (Largest Contentful Paint): 1.2 秒
  • 累积布局偏移 (Cumulative Layout Shift): 0.05
  • 总包体大小: 45KB (gzip 压缩后)

总结

通过这次博客系统实现,我们再次确认了现代 JAMstack 架构在以下几方面的关键作用:

  1. 类型安全: 通过 Content Collections 在设计阶段就防止错误(再也不会因为运行时错误而哭泣)。
  2. 自动化: AI 翻译和 E2E 测试提高了运营效率(正在逐渐取代人类的工作)。
  3. 性能: 通过积极的优化实现极速加载(速度之巅)。
  4. 可维护性: 清晰的架构带来了可持续的开发(对未来的自己更友好)。

作为技术博客平台,我们实现了从文章撰写到发布的全流程自动化,为开发者创造了一个可以专注于核心内容创作的环境。

换句话说,这意味着我再也没有借口偷懒不更新博客了。这…太美好了吗?

Support this article

If this article was helpful, please support us with a tip. You can choose any amount.

Secure payment via Stripe

相关文章

阅读文章
韓国語ブログ404ページ
工程

【全五语种支持】从仅日英到支持中韩西的3小时激战记

原以为支持五语种,实则只有两种的震撼事实。与 Claude Code 一起,飞速实现中文、韩文、西班牙语支持的全记录。

#多言語化 #i18n +4
阅读文章
Google Cloud Platform ロゴ
工程

整个 Google Cloud 项目一天之内完成组织间迁移,我的经验总结

大家好,我是 Terisuke。

#Google Cloud #DevOps +3
阅读文章
高性能Webサイトのイメージ
工程

挑战阿部宽的官网后,我构建了一个超棒的网站

我自诩为“拥有最快下载速度的网站的男人”,一直以来都在挑战阿部宽的官网。结果,我构建了一个超越单纯速度竞争的、真正高性能的网站。顺带一提,阿部宽的网站至今仍然很快。致以敬意。

#Astro #Alpine.js +3