Astro

内容优先的 Web 框架 - 默认零 JS,岛屿架构,React/Vue/Svelte 可混用

TL;DR

一句话:Astro 是内容驱动网站的框架——默认零 JavaScript,只对需要交互的部分注水。

核心优势

  • 默认零 JS - 纯静态 HTML,100 分 Lighthouse
  • 孤岛架构 - 只注水交互组件
  • 用任何框架 - React、Vue、Svelte、Solid 共存
  • 内容集合 - 类型安全的 Markdown/MDX

Core Concepts

概念 1:孤岛架构

组件默认是静态的。选择性地添加交互:

---
import ReactCounter from './Counter.jsx';
import VueModal from './Modal.vue';
---

<!-- 静态 - 不发送 JS -->
<h1>我的博客</h1>
<p>这段内容是纯 HTML</p>

<!-- 孤岛 - 只有这些有 JS -->
<ReactCounter client:visible />  <!-- 可见时注水 -->
<VueModal client:load />         <!-- 页面加载时注水 -->
<ReactCounter client:idle />     <!-- 浏览器空闲时注水 -->

概念 2:.astro 组件

默认服务端渲染。frontmatter 写逻辑,模板写标记:

---
// 构建时运行(服务端)
const response = await fetch('https://api.example.com/posts');
const posts = await response.json();
---

<ul>
  {posts.map(post => (
    <li><a href={`/blog/${post.slug}`}>{post.title}</a></li>
  ))}
</ul>

<style>
  /* 作用域隔离到此组件 */
  li { margin-bottom: 0.5rem; }
</style>

概念 3:内容集合

用 Zod 验证的类型安全内容:

// src/content/config.ts
import { defineCollection, z } from 'astro:content';

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    date: z.date(),
    tags: z.array(z.string()).optional(),
  }),
});

export const collections = { blog };
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---

Quick Start

创建项目

npm create astro@latest my-blog
cd my-blog

项目结构

src/
├── pages/          # 基于文件的路由
│   ├── index.astro     → /
│   ├── about.astro     → /about
│   └── blog/[slug].astro → /blog/:slug
├── components/     # 可复用组件
├── layouts/        # 页面布局
└── content/        # 内容集合

运行

npm run dev
# 打开 http://localhost:4321

Gotchas

文件路由规则

src/pages/
├── index.astro           → /
├── about.astro           → /about
├── blog/index.astro      → /blog
├── blog/[slug].astro     → /blog/my-post
└── [...slug].astro       → /any/nested/path(通配)

选择正确的 client 指令

<!-- 最常用 - 进入视口时加载 -->
<Component client:visible />

<!-- 关键交互 - 立即加载 -->
<Component client:load />

<!-- 非关键 - 浏览器空闲时加载 -->
<Component client:idle />

<!-- 仅特定媒体查询 -->
<Component client:media="(max-width: 768px)" />

动态路由需要 getStaticPaths

---
// src/pages/blog/[slug].astro
export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map(post => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
---

When to Use

适合

  • 博客和文档站点
  • 营销/落地页
  • 内容为主的网站
  • 对性能要求高的站点

不适合

  • 高交互应用(仪表盘、SPA)
  • 实时应用
  • 需要客户端路由的应用

对比

特性AstroNext.jsGatsby
默认 JS完整 React完整 React
框架锁定ReactReact
构建速度中等
适用场景内容应用+内容内容

Next Steps

Cheatsheet

模式代码
静态组件<Component />
可见时注水<Component client:visible />
加载时注水<Component client:load />
空闲时注水<Component client:idle />
添加集成npx astro add react
构建npm run build
预览npm run preview