621 Astro 静态站点生成
一句话概述:Astro 是"内容优先"的 Web 框架,默认零 JavaScript 发送到浏览器,用"岛屿架构"按需加载交互组件,是博客、文档站、营销页的最佳选择。
核心知识点速查表
| 知识点 | 说明 |
|---|
| 最新版本 | Astro 5.16+(2026年) |
| 核心特性 | Islands Architecture、零JS默认、内容集合 |
| 框架兼容 | 可混用 React、Vue、Svelte、Solid 等 |
| 渲染方式 | SSG(静态)+ SSR(服务端)+ Server Islands |
| 内容格式 | Markdown、MDX、JSON、YAML |
| 适用场景 | 博客、文档站、营销页、电商展示 |
一、安装配置
# 创建 Astro 项目
npm create astro@latest my-site # 交互式创建(选模板和配置)
cd my-site
npm run dev # 启动开发服务器 http://localhost:4321
1.1 项目结构
my-site/
├── src/
│ ├── pages/ # 基于文件的路由
│ │ ├── index.astro # 首页 → /
│ │ ├── about.astro # 关于 → /about
│ │ └── blog/
│ │ ├── index.astro # 博客列表 → /blog
│ │ └── [slug].astro # 动态路由 → /blog/my-post
│ ├── layouts/ # 页面布局
│ ├── components/ # 组件(Astro/React/Vue 均可)
│ ├── content/ # 内容集合(Markdown 文章等)
│ │ └── blog/
│ │ ├── post-1.md
│ │ └── post-2.md
│ └── styles/ # 全局样式
├── public/ # 静态资源(直接复制到输出)
└── astro.config.mjs # Astro 配置
二、基本使用
2.1 Astro 组件
---
// src/pages/index.astro
// --- 三横线之间是"前置脚本",在服务端执行(不发送到浏览器)
// 白话:这部分代码只在构建时或服务端运行,像 Python 脚本一样
const title = "欢迎来到 Astro"; // 定义变量
const features = [ // 数据可以直接写在这里
{ name: "零 JS", desc: "默认不发送 JavaScript" },
{ name: "岛屿架构", desc: "按需加载交互组件" },
{ name: "多框架", desc: "混用 React/Vue/Svelte" }
];
// 可以直接 fetch 数据(构建时执行)
const res = await fetch('https://api.example.com/data');
const data = await res.json();
---
<html lang="zh-CN">
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<!-- 列表循环 -->
<ul>
{features.map(f => (
<li><strong>{f.name}</strong>:{f.desc}</li>
))}
</ul>
<!-- 条件渲染 -->
{data.length > 0 && <p>共 {data.length} 条数据</p>}
</body>
</html>
<style>
/* 样式自动局部作用域 */
h1 { color: #4c1d95; }
</style>
2.2 布局组件
---
// src/layouts/BaseLayout.astro
const { title, description = "Astro 网站" } = Astro.props; // 接收属性
---
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<meta name="description" content={description} />
<title>{title}</title>
</head>
<body>
<nav>
<a href="/">首页</a>
<a href="/blog">博客</a>
<a href="/about">关于</a>
</nav>
<main>
<slot /> <!-- 插槽:子内容放这里 -->
</main>
<footer>© 2026 我的网站</footer>
</body>
</html>
---
// src/pages/about.astro - 使用布局
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout title="关于我们">
<h1>关于我们</h1>
<p>这是关于页面的内容</p>
</BaseLayout>
2.3 内容集合(Content Collections)
// src/content.config.ts - 定义内容集合的 Schema
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders'; // Astro 5 使用 Content Layer API
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({ // 用 Zod 定义字段类型
title: z.string(), // 必填标题
date: z.date(), // 必填日期
tags: z.array(z.string()), // 标签数组
draft: z.boolean().default(false), // 是否草稿,默认 false
description: z.string().optional() // 可选描述
})
});
export const collections = { blog }; // 导出集合
---
# src/content/blog/first-post.md
title: "我的第一篇文章"
date: 2026-05-10
tags: ["astro", "教程"]
---
# 欢迎
这是我用 Astro 写的第一篇博客文章。
## 为什么选择 Astro
Astro 默认不发送 JavaScript,页面加载极快。
---
// src/pages/blog/index.astro - 博客列表页
import BaseLayout from '../../layouts/BaseLayout.astro';
import { getCollection } from 'astro:content';
// 获取所有非草稿文章,按日期倒序
const posts = (await getCollection('blog'))
.filter(post => !post.data.draft)
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
---
<BaseLayout title="博客">
<h1>博客文章</h1>
<ul>
{posts.map(post => (
<li>
<a href={`/blog/${post.id}`}>
<h2>{post.data.title}</h2>
<time>{post.data.date.toLocaleDateString('zh-CN')}</time>
</a>
</li>
))}
</ul>
</BaseLayout>
三、岛屿架构(Islands)
# 安装 React 集成(也可以装 Vue、Svelte 等)
npx astro add react # 自动配置 React 支持
// src/components/Counter.tsx - React 交互组件
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0); // React 的 useState
return (
<button onClick={() => setCount(count + 1)}>
点击次数: {count}
</button>
);
}
---
// src/pages/demo.astro - 使用岛屿架构
import Counter from '../components/Counter';
---
<h1>岛屿架构演示</h1>
<!-- 白话:client:load = 页面加载后立即执行 JS(变成交互式"岛屿") -->
<Counter client:load />
<!-- client:visible = 滚动到可见时才加载 JS(懒加载,节省流量) -->
<Counter client:visible />
<!-- client:idle = 浏览器空闲时加载 JS -->
<Counter client:idle />
<!-- 不加 client: 指令 = 只渲染 HTML,不发送 JS(默认行为) -->
<Counter />
3.1 Server Islands(Astro 5 新特性)
---
// 白话:Server Islands = 页面大部分静态缓存,小部分实时从服务器获取
// 适合:静态页面中嵌入个性化内容(如用户头像、推荐列表)
---
<h1>产品页面</h1>
<p>这是静态内容,可以被 CDN 缓存</p>
<!-- server:defer = 这部分内容延迟到请求时从服务器获取 -->
<UserGreeting server:defer>
<p slot="fallback">加载中...</p>
</UserGreeting>
四、高级用法
4.1 SSR 模式
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node'; // Node.js 适配器
export default defineConfig({
output: 'server', // 'static'(默认) | 'server' | 'hybrid'
adapter: node({ // 部署适配器
mode: 'standalone' // 独立 Node.js 服务器
})
});
// 白话:static = 所有页面构建时生成;server = 所有页面请求时渲染;hybrid = 混合(默认静态,按需 SSR)
4.2 API 端点
// src/pages/api/users.ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = async () => {
const users = [{ id: 1, name: '张三' }];
return new Response(
JSON.stringify(users), // 返回 JSON
{
status: 200,
headers: { 'Content-Type': 'application/json' }
}
);
};
export const POST: APIRoute = async ({ request }) => {
const body = await request.json(); // 获取请求体
return new Response(
JSON.stringify({ id: 2, ...body }),
{ status: 201 }
);
};
4.3 中间件
// src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
const start = Date.now();
const response = await next(); // 执行后续处理
const duration = Date.now() - start;
console.log(`${context.url.pathname} - ${duration}ms`); // 记录请求耗时
return response;
});
五、常见报错与解决
| 问题 | 解决 |
|---|
| React 组件没有交互 | 添加 client:load 或其他客户端指令 |
| 内容集合类型错误 | 检查 Markdown frontmatter 是否符合 Schema 定义 |
| 构建时 fetch 失败 | 确保 API 在构建时可访问,或改用 SSR 模式 |
| 图片未显示 | 放在 public/ 目录或使用 <Image /> 组件 |
六、速查表
| 操作 | 说明 |
|---|
| 创建项目 | npm create astro@latest |
| 开发模式 | npm run dev |
| 构建 | npm run build |
| 预览构建 | npm run preview |
| 添加集成 | npx astro add react/vue/svelte |
| 页面路由 | src/pages/路径.astro |
| 内容集合 | src/content/集合名/文件.md |
| 客户端加载 | client:load / client:visible / client:idle |
| API路由 | src/pages/api/路径.ts |
七、同类工具对比
| 特性 | Astro | Next.js | Gatsby | Hugo |
|---|
| 默认JS | 零 | 有 | 有 | 零 |
| 框架 | 多框架 | React | React | Go模板 |
| SSR | 支持 | 支持 | 有限 | 不支持 |
| 内容管理 | 内置集合 | 自定义 | GraphQL | 内置 |
| 构建速度 | 极快 | 快 | 慢 | 极快 |
| 适合场景 | 内容站 | 全栈应用 | 内容站 | 纯静态 |
选型建议:内容为主的网站首选 Astro(极快且灵活);全栈应用选 Next.js;纯静态极速构建选 Hugo。
参考资料:Astro 官方文档 | GitHub | Astro 模板