跳转至

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

七、同类工具对比

特性AstroNext.jsGatsbyHugo
默认JS
框架多框架ReactReactGo模板
SSR支持支持有限不支持
内容管理内置集合自定义GraphQL内置
构建速度极快极快
适合场景内容站全栈应用内容站纯静态

选型建议:内容为主的网站首选 Astro(极快且灵活);全栈应用选 Next.js;纯静态极速构建选 Hugo。


参考资料Astro 官方文档 | GitHub | Astro 模板