基于 Astro 4.8 的博客系统完整实现 - 包含 AI 翻译与 E2E 测试的综合方案
基于 Astro Content Collections 构建的高性能博客系统实现记录。详细解析包含 Google Gemini API 的 AI 自动翻译、Playwright E2E 测试以及速率限制功能在内的全方位开发流程
概述
在最近的开发中,我们实现了一套基于 Astro 4.8.7 的综合博客系统。该系统不仅能展示 Markdown,还具备 AI 自动翻译、E2E 测试以及面向正式运营的各项功能,是一个现代化的技术博客平台。
在 WordPress 里跟小部件(Widget)搏斗的时代已经结束了。从现在起,翻译交给 AI,测试全自动化,工程师只要躺着睡觉就行了(开玩笑的)。
技术栈
核心技术
- Astro 4.8.7:基于群岛架构(Islands Architecture)的高速 SSG
- TypeScript:类型安全的开发环境
- Tailwind CSS:实用优先(Utility-first)的样式解决方案
- Alpine.js 3.14.0:轻量级前端 JavaScript
博客专用功能
- Content Collections:Astro 的类型安全内容管理
- 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 构建了自动翻译系统。这比拜托人工翻译要快得多,而且它还绝不抱怨。
// 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 次请求/分钟的保守限制
- 错误处理:基于指数退避的重试机制
- 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 回退(Fallback)
- 响应式图片尺寸(480w, 800w)
课题与解决方案
1. YAML Frontmatter 的转义问题
课题在于,翻译后的标题或描述中若包含特殊字符,会导致 YAML 解析错误。
作为解决方案,通过以下函数进行转义:
function escapeYAMLString(str) {
return str
.replace(/\\/g, "\\\\") // バックスラッシュを最初にエスケープ
.replace(/"/g, '\\"'); // ダブルクォートをエスケープ
}
2. API 速率限制应对
课题在于,由于 Gemini API 的限制会导致请求失败。
解决方案是指数退避与智能速率限制:
- 1 秒基础延迟
- 阶梯式延迟,最高至 60 秒
- 通过请求时间追踪进行事前限制
3. E2E 测试的稳定性
课题在于,动态内容会导致测试变得不稳定。
解决方案是利用 data-testid 属性来切实定位元素。
运营流程
新文章发布流程
- 撰写日文文章:在
/src/content/blog/ja/中创建 Markdown 文件 - AI 翻译:
npm run translate src/content/blog/ja/article-name.md - 运行测试:
npm run test:e2e - 构建:
npm run build - 部署:自动部署至 Firebase Hosting
质量保证
- 类型检查:利用 TypeScript 进行编译时检查
- Schema 校验:利用 Zod 进行内容校验
- E2E 测试:利用 Playwright 进行功能测试
心得体会
1. Content Collections 的威力
与传统基于文件的方式相比,类型安全性和开发体验有了大幅提升。尤其是修改 Schema 时的影响范围变得一目了然,使安全重构成为可能。
现在有 TypeScript 提醒“类型不对哦!”,再也不用因运行时错误而心惊肉跳了。太棒了。
2. AI 翻译的实用性
Google Gemini API 在技术文章上的翻译质量非常高,人工微调降到了最低限度。不过,专业术语的一致性仍需要持续改进。
当“npm”被翻译成“エヌピーエム(注:音译读音)”的时候真是让人哭笑不得。嘛,倒也不能算错就是了。
3. E2E 测试的重要性
我们切身感受到,即便是静态网站生成器,对于路由和元数据生成这类复杂功能而言,E2E 测试也是不可或缺的。
真想揍一顿过去那个觉得“既然是静态网站就不需要测试吧”的自己。
总结
通过实现这套博客系统,我们确认了在现代 JAMstack 架构中以下几点至关重要:
- 类型安全:通过 Content Collections 防患错误于设计之时(再也不用对着运行时错误流泪)
- 自动化:通过 AI 翻译与 E2E 测试实现运营高效化(逐步接管人类的工作)
- 性能:通过积极的优化实现高速化(极速之巅)
- 可维护性:通过清晰的架构实现可持续开发(造福未来的自己)
作为一个技术博客平台,我们自动化了从文章撰写到发布的整个流程,打造出了能让开发者专注于内容创作的环境。
换句话说,这下彻底找不到偷懒不更新博客的借口了。太好了……对吧?
想在贵公司推进本文的内容?
AI 受托开发的咨询,由 AI 接待「Cloudia」受理。
详细了解AI 基础设施与受托开发Support this article
If this article was helpful, please support us with a tip. You can choose any amount.
相关文章
从Git历史中能看到什么、看不到什么。用Grift核算了4个OSS
本文分开写:按明示的规则,从git历史中能数出什么,数不出什么。对4个真实OSS按仓库做了核算。这不保证人的能力,也不保证记录是完整的。
如何在实现中坚守“不评分、不排名”。Grift CLI在下一版本中确定的5项条件
Grift CLI承诺不给出分数或排名。在2026年10月的核对中发现,虽然在注释中写明了并非排名,但表格仍是按提交次数从多到少排列的。面向发包方、SES销售以及工程师,我们将以通俗易懂的方式阐述对0.8版本设定的5项验收条件。
AI开发与定制开发的估算陷入个人经验化的原因——将估算依据转化为公司资产的方法
本文将解析定制开发的估算因人而异的原因,并讲解如何利用GitHub实际业绩、市场行情和工时明细,打造具有充分说服力的估算依据。同时介绍Grift的应用思路。