跳至主要內容

Astro 靜態網站框架:零 JavaScript 的極致效能

Astro 靜態網站框架:零 JavaScript 的極致效能

在追求 Web 效能的道路上,Astro 提出了一個大膽的理念:預設不傳送任何 JavaScript 到瀏覽器。只有在真正需要互動性的地方,才選擇性地注水(hydrate)客戶端元件。這個「島嶼架構(Islands Architecture)」讓 Astro 在效能測試中幾乎橫掃一切。

Astro 的核心理念

傳統的 SPA 框架(React、Vue)把所有 JavaScript 打包後送到瀏覽器,即使頁面大部分是靜態內容。Astro 反其道而行:

傳統 SPA:整頁 JavaScript → 瀏覽器執行 → 渲染畫面
Astro:伺服器渲染 HTML → 瀏覽器直接顯示 → 只在需要時載入 JS

安裝與建立專案

# 建立新專案
npm create astro@latest my-blog

# 互動式設定精靈會詢問:
# - 使用哪個模板(空白、部落格、文件...)
# - 是否使用 TypeScript
# - 是否安裝依賴

cd my-blog
npm run dev

Astro 檔案語法

.astro 檔案分為兩個部分:

---
// Component Script(在伺服器端執行,類似 frontmatter)
import Header from '../components/Header.astro';
import BlogPost from '../components/BlogPost.astro';

// 可以使用任何 Node.js API
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
const title = "我的部落格";
---

<!-- Component Template(HTML + JSX 語法混合)-->
<html lang="zh-TW">
  <head>
    <meta charset="utf-8" />
    <title>{title}</title>
  </head>
  <body>
    <Header />
    <main>
      {posts.map(post => (
        <BlogPost title={post.title} url={`/posts/${post.slug}`} />
      ))}
    </main>
  </body>
</html>

內容集合(Content Collections)

Astro 的內容集合是管理 Markdown 文章的強大功能:

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

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.date(),
    author: z.string().default('匿名'),
    tags: z.array(z.string()).default([]),
    cover: z.string().optional(),
  }),
});

export const collections = { blog };
---
title: "我的第一篇文章"
description: "這是文章的描述"
pubDate: 2026-03-04
author: "王小明"
tags: ["JavaScript", "Astro"]
---

# 我的第一篇文章

這是文章內容...
---
// pages/blog/index.astro
import { getCollection } from 'astro:content';

const posts = await getCollection('blog');
const sortedPosts = posts.sort(
  (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);
---

<main>
  {sortedPosts.map(post => (
    <article>
      <h2><a href={`/blog/${post.slug}`}>{post.data.title}</a></h2>
      <p>{post.data.description}</p>
      <time>{post.data.pubDate.toLocaleDateString('zh-TW')}</time>
    </article>
  ))}
</main>

島嶼架構(Islands)

這是 Astro 最獨特的功能——你可以在靜態頁面中嵌入互動式的 React/Vue/Svelte 元件:

# 安裝框架整合
npx astro add react
npx astro add vue
---
// 混合使用多個框架的元件!
import ReactCounter from '../components/Counter.tsx';
import VueSearch from '../components/Search.vue';
import StaticCard from '../components/Card.astro';  // 靜態元件,無 JS
---

<main>
  <!-- 靜態元件:不傳送任何 JS -->
  <StaticCard title="靜態卡片" />

  <!-- 立即注水:頁面載入後立即互動 -->
  <ReactCounter client:load />

  <!-- 可見時注水:進入視窗才載入 JS -->
  <VueSearch client:visible />

  <!-- 閒置時注水:瀏覽器閒置時載入 -->
  <ReactCounter client:idle />

  <!-- 媒體查詢注水:符合條件時載入 -->
  <ReactCounter client:media="(max-width: 768px)" />
</main>

路由系統

Astro 使用基於檔案的路由:

src/pages/
├── index.astro          → /
├── about.astro          → /about
├── blog/
│   ├── index.astro      → /blog
│   └── [slug].astro     → /blog/:slug(動態路由)
└── api/
    └── posts.ts         → /api/posts(API 端點)

動態路由

---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content';

export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map(post => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await post.render();
---

<article>
  <h1>{post.data.title}</h1>
  <Content />
</article>

API 端點

// src/pages/api/posts.ts
import type { APIRoute } from 'astro';
import { getCollection } from 'astro:content';

export const GET: APIRoute = async () => {
  const posts = await getCollection('blog');
  return new Response(JSON.stringify(
    posts.map(p => ({ slug: p.slug, title: p.data.title }))
  ), {
    headers: { 'Content-Type': 'application/json' },
  });
};

部署

Astro 可以部署為靜態網站或 SSR 應用:

# 靜態部署(預設)
npm run build
# 輸出到 dist/ 資料夾,可部署到任何靜態托管服務
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';

export default defineConfig({
  output: 'server',  // 啟用 SSR
  adapter: vercel(),
});

效能表現

Astro 網站的典型 Lighthouse 分數:

指標 Next.js(SPA) Astro
Performance 70-85 95-100
LCP ~2.5s ~0.8s
TBT ~300ms ~0ms
JS 大小 200-500KB 0-20KB

適用場景

最適合 Astro 的場景:

  • 部落格、技術文件、行銷頁面
  • 內容導向的網站
  • 追求極致 SEO 和 Core Web Vitals 的專案

不適合 Astro 的場景:

  • 高度互動的 Web App(如 Figma、Google Docs)
  • 需要複雜客戶端狀態管理的應用

總結

Astro 重新定義了靜態網站生成器的可能性。它讓你用熟悉的 React/Vue 語法開發,卻能輸出接近純 HTML 的高效能頁面。對於內容導向的網站,Astro 幾乎是目前最佳的選擇,兼顧了開發體驗和最終效能。

分享這篇文章