Presto 网站架构
Presto 官网(Presto-homepage)是基于 Astro 5 的纯静态站点,部署在 Vercel 平台, 通过 CI/CD 与主仓库(Presto)联动,实现版本号同步和 Showcase 静态文件自动更新。 截至 2026 年 3 月。
系统全景
技术栈总览
| 层级 | 技术 | 版本 | 来源 | 用途 |
|---|---|---|---|---|
| 框架 | Astro | ^5.17.1 | package.json | 静态站点生成器 |
| 语言 | TypeScript | ^5.9.3 | package.json | 类型安全 |
| 前端框架 | 无 | — | 架构决策 | 纯 Astro 组件 + vanilla JS |
| CSS | 自定义 CSS | — | global.css | CSS 变量 + 暗色模式 |
| 字体 | 系统字体栈 | — | global.css | 无外部字体依赖 |
| 部署 | Vercel | — | vercel.json | 托管 + CDN |
| HTML 压缩 | compressHTML | true | astro.config.mjs | 减小体积 |
| 包管理器 | npm | — | package-lock.json | 依赖管理 |
系统字体栈
--font-sans:
system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", "Noto Sans SC", Roboto,
Oxygen, Ubuntu, Cantarell, sans-serif;
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;页面路由和组件职责
页面路由结构
| 路由 | 文件 | 说明 |
|---|---|---|
/ | src/pages/index.astro | 首页,包含所有主要区块 |
/developers | src/pages/developers/index.astro | 开发者页面,43KB 内容丰富的技术文档 |
/templates | src/pages/templates/index.astro | 模板商店,iframe 嵌入 Presto 的商店 UI |
/showcase/* | public/showcase/ | Presto 构建的预渲染静态文件 |
组件架构
src/
├── components/
│ ├── Header.astro # 导航栏(36KB)
│ ├── Hero.astro # 首屏(版本号、下载按钮)
│ ├── Features.astro # 功能特性展示
│ ├── Showcase.astro # 实时 UI 展示(iframe)
│ ├── Download.astro # 下载区域(多平台检测)
│ └── Footer.astro # 页脚
├── layouts/
│ └── Layout.astro # 全局 HTML 壳(i18n 检测、滚动动画)
└── styles/
└── global.css # 全局样式(CSS 变量、响应式断点)组件职责
| 组件 | 文件大小 | 职责 |
|---|---|---|
| Header | 36KB | 导航栏、双语切换、响应式菜单、滚动时样式变化 |
| Hero | 7.5KB | 首屏标题、版本号(自动同步)、下载按钮、背景渐变 |
| Features | 6KB | 功能特性网格布局,支持图标 + 双语描述 |
| Showcase | 17KB | 产品展示轮播,5 个 iframe 嵌入 Presto 真实 UI 组件 |
| Download | 16KB | 下载区域、多平台检测(macOS/Windows/Linux)、版本号(自动同步) |
| Footer | 2KB | 页脚链接、版权信息 |
关键架构决策
1. Showcase iframe 嵌入
What: 首页的 Showcase 区域通过 iframe 嵌入 Presto 应用的真实 UI 组件(非截图)。
Why:
- 真实交互体验:用户可以实际操作 Presto 界面,而非静态图片
- 自动更新:Presto 构建新的 showcase 静态文件后,通过 CI 自动同步到官网
- 减少维护成本:无需手动截屏和替换图片
- 性能优化:
loading="lazy"+sandbox="allow-scripts allow-same-origin"安全沙箱
实现细节(src/components/Showcase.astro):
<iframe
src={s.iframeSrc}
loading="lazy"
sandbox="allow-scripts allow-same-origin"
class="showcase-iframe"
title={s.en}
></iframe>5 个 showcase 场景:
/showcase/editor-gongwen— 编辑器 · 公文/showcase/editor-jiaoan— 编辑器 · 教案/showcase/batch— 批量转换/showcase/templates— 模板管理/showcase/drop— 拖入文件
2. 模板商店 iframe 嵌入
What: /templates 页面通过 iframe 嵌入 Presto 的 /showcase/store-templates,商店 UI 由 Presto 仓库维护。
Why:
- 职责分离:模板商店的业务逻辑属于主应用,官网只负责展示
- 一致性:模板商店 UI 与 Presto 桌面端保持一致
- 独立更新:商店 UI 更新无需修改官网代码
- 减少重复:避免在两个仓库维护相同的商店 UI
3. 版本号自动同步
What: sync-release.yml 在 Presto 发布新版本时自动更新 Hero.astro 和 Download.astro 中的版本号。
Why:
- 避免手动错误:版本号不一致会导致用户下载错误版本
- 减少维护成本:发布流程自动化,无需手动修改官网代码
- 及时性:Presto 发布后立即触发版本号更新
实现机制:
- Presto 仓库发布新版本 →
repository_dispatch事件release-published sync-release.yml下载 release 资产,创建 homepage release- 使用
sed更新版本号:
# Download.astro
sed -i "s/^const version = '.*';$/const version = '${VER}';/" src/components/Download.astro
# Hero.astro
sed -i "s/最新版本 v[0-9][0-9.]*/最新版本 v${VER}/" src/components/Hero.astro
sed -i "s/Latest v[0-9][0-9.]*/Latest v${VER}/" src/components/Hero.astro- 自动 commit 并 push,触发 Vercel 自动部署
4. 双语系统
What: 所有文本用 <span class="zh"> + <span class="en"> 包裹,通过 CSS 切换。
Why:
- 简单高效:无需 i18n 框架,纯 CSS 实现
- 避免 FOUC(Flash of Unstyled Content):Layout.astro 中通过 inline script 在渲染前检测语言
- 性能优化:无需额外的 JavaScript 切换逻辑
- 易于维护:所有文本集中在组件内,无需外部翻译文件
实现机制(src/layouts/Layout.astro):
<script is:inline>
(function () {
var stored = localStorage.getItem("presto-lang");
var lang = stored || (navigator.language.startsWith("zh") ? "zh" : "en");
document.documentElement.lang = lang;
})();
</script>CSS 切换逻辑(src/styles/global.css):
html[lang="en"] .zh {
display: none;
}
html[lang="zh"] .en {
display: none;
}5. 暗色模式
What: 纯 CSS @media (prefers-color-scheme: dark) 自动切换,无 JS 切换按钮。
Why:
- 跟随系统:用户的系统设置自动应用,无需手动切换
- 性能优化:无 JavaScript 运行时开销
- 简化代码:无需维护主题状态和切换逻辑
- CSS 变量:所有颜色通过 CSS 变量定义,切换流畅
实现机制(src/styles/global.css):
:root {
--color-bg: #ffffff;
--color-text: #0f172a;
--color-accent: #2563eb;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #09090b;
--color-text: #fafafa;
--color-accent: #60a5fa;
}
}6. 零框架策略
What: 不使用 React/Vue/Svelte 等前端框架,纯 Astro 组件 + inline vanilla JS。
Why:
- 性能优先:纯静态 HTML,无 hydration 开销
- 简化构建:无需前端框架的复杂构建配置
- 减少 bundle 大小:无需加载框架运行时
- SEO 友好:所有内容在构建时渲染为静态 HTML
- 维护成本低:无框架版本升级和依赖兼容问题
仅有的 JavaScript:
- i18n 语言检测(inline script,15 行)
- 滚动动画 IntersectionObserver(inline script,30 行)
- Showcase 轮播逻辑(inline script,在 Showcase.astro 内)
部署流程和 CI 联动
Vercel 自动部署
Presto-homepage 连接到 Vercel 平台,每次 main 分支有新的 commit 时自动触发构建和部署。
配置(vercel.json):
cleanUrls: true— 无 .html 后缀- 安全头:
X-Content-Type-Options: nosniffX-Frame-Options: SAMEORIGINReferrer-Policy: strict-origin-when-cross-originPermissions-Policy: camera=(), microphone=(), geolocation=()Content-Security-Policy:default-src 'self'; script-src 'self' 'unsafe-inline';style-src 'self' 'unsafe-inline'; img-src 'self' data:;frame-src 'self'; connect-src 'self'; font-src 'self'
CI 工作流联动
sync-release.yml
触发条件:
- Presto 仓库发布新版本(
repository_dispatch: release-published) - 手动触发(
workflow_dispatch,需指定 tag)
步骤:
- 解析 tag(从
client_payload或inputs) - 从 Presto 仓库下载 release 资产(需要
PRESTO_PAT) - 创建 homepage release(同名 tag,复制 release notes)
- 更新版本号(Download.astro + Hero.astro)
- 自动 commit 并 push
sync-showcase.yml
触发条件:
- Presto 仓库构建 showcase 完成(
repository_dispatch: showcase-updated) - 手动触发(
workflow_dispatch)
步骤:
- 清理旧文件(
rm -rf public/_app public/showcase) - 从 Presto 仓库下载 artifact(
showcase-static,需要PRESTO_PAT) - 复制到
public/目录 - 自动 commit 并 push
响应式设计
断点列表
| 断点 | 说明 |
|---|---|
| 1024px | 平板横屏 |
| 900px | 平板竖屏 |
| 768px | 大手机 / 小平板 |
| 640px | 手机横屏 |
| 560px | 大手机竖屏 |
| 480px | 小手机竖屏 |
IntersectionObserver 滚动动画
实现(src/layouts/Layout.astro):
document.addEventListener("DOMContentLoaded", function () {
var els = document.querySelectorAll(".animate-on-scroll");
if (!("IntersectionObserver" in window)) {
// 降级处理:直接显示所有元素
els.forEach(function (el) {
el.classList.add("is-visible");
});
return;
}
var observer = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("is-visible");
observer.unobserve(entry.target); // 只触发一次
}
});
},
{ threshold: 0.05, rootMargin: "0px 0px -20px 0px" },
);
els.forEach(function (el) {
observer.observe(el);
});
});CSS 动画(src/styles/global.css):
.animate-on-scroll {
opacity: 0;
transform: translateY(16px);
transition:
opacity 0.6s ease,
transform 0.6s ease;
}
.animate-on-scroll.is-visible {
opacity: 1;
transform: translateY(0);
}Showcase iframe 缩放
Showcase iframe 固定宽度 1200px,通过 JavaScript 动态缩放以适应容器宽度:
function scaleIframes() {
var containers = document.querySelectorAll(".slide-image");
for (var i = 0; i < containers.length; i++) {
var iframe = containers[i].querySelector(".showcase-iframe");
if (!iframe) continue;
var cw = containers[i].offsetWidth;
var scale = cw / 1200;
iframe.style.transform = "scale(" + scale + ")";
containers[i].style.height = Math.round(800 * scale) + "px";
}
}性能优化
构建时优化
- compressHTML: true — Astro 自动压缩 HTML
- 系统字体栈 — 无外部字体加载,避免 FOUT
- 纯静态站点 — 无服务器端渲染,CDN 直接缓存
运行时优化
- lazy loading iframe — Showcase iframe 延迟加载
- IntersectionObserver — 只在可见时触发动画
- CSS 变量 — 暗色模式切换无重绘开销
- will-change: transform — 轮播动画 GPU 加速
Vercel 优化
- 全球 CDN — 静态资源就近分发
- HTTP/2 — 多路复用,减少连接开销
- 自动压缩 — Gzip/Brotli 压缩
开发命令
# 本地开发服务器(localhost:4321)
npm run dev
# 构建静态站点到 dist/
npm run build
# 预览构建产物
npm run preview相关文档
- 软件架构 — Presto 主应用的组件边界和数据流
- CI/CD 流水线 — Presto 仓库的完整 CI/CD 配置
- Presto-homepage/CLAUDE.md — 官网开发约束和约定
