Astro 網頁框架
概覽
此公開複製套件將 https://github.com/sickn33/antigravity-awesome-skills 中的 plugins/antigravity-awesome-skills/skills/astro 包裝成原生 Omni Skills 的編輯格式,同時不隱藏其來源。
當操作者需要上游工作流程、支援檔案和儲存庫上下文保持完整,同時公共驗證器和私人增強器繼續其正常下游流程時使用。
此複製套件保持複製的上游檔案完整,並使用 metadata.json 中的 external_source 區塊以及 ORIGIN.md 作為供審查的出處錨點。
Astro 網頁框架
未乾淨對應到公開標題的導入來源區段仍保留在下方或支援檔案中。重要的導入區段包括:運作方式、安全與安全注意事項、常見陷阱、限制。
何時使用此技能
使用此區段作為觸發過濾器。它應在操作者載入檔案、執行命令或發起拉取請求之前,明確設定啟用邊界。
- 當建立部落格、文件網站、行銷頁面或作品集時使用
- 當效能和 Core Web Vitals 是最高優先級時使用
- 當專案包含大量 Markdown 或 MDX 檔案時使用
- 當需要 SSG(靜態)輸出並可選擇性為動態路由啟用 SSR 時使用
- 當使用者詢問關於 .astro 檔案、Astro.props、內容集合或 client: 指令時使用
- 當請求明確符合導入來源的意圖時使用:使用 Astro 建立以內容為主的網站 — 預設零 JS、島嶼架構、多框架元件以及 Markdown/MDX 支援。
操作表
| 情況 | 從這裡開始 | 為何重要 |
|---|---|---|
| 首次使用 | metadata.json | 在觸碰複製的工作流程前,透過 external_source 區塊確認儲存庫、分支、提交和導入路徑 |
| 出處審查 | ORIGIN.md | 為審查者提供導入來源的純語言審計追蹤 |
| 工作流程執行 | SKILL.md | 從最小但能實質改變執行的複製檔案開始 |
| 支援上下文 | SKILL.md | 在未載入完整套件的情況下,加入下一個最相關的複製來源檔案 |
| 交接決策 | ## 相關技能 | 當任務偏離時,幫助操作者切換到更合適的原生技能 |
工作流程
此工作流程同時具有編輯和操作性質。它保持導入來源對操作者有用,同時滿足為下游增強器流程提供資料的公開接收標準。
- 確認使用者目標、導入工作流程的範圍,以及此技能是否仍是該任務的正確路由器。
- 在載入任何複製的上游支援檔案之前,先閱讀概覽和出處檔案。
- 僅載入那些能實質改變當前請求結果的參考資料、範例、提示或腳本。
- 執行上游工作流程,同時在工作筆記中明確保持出處和來源邊界。
- 根據上游期望和您在複製檔案中能指出的證據驗證結果。
- 當工作偏離此導入工作流程的核心時,升級或交接給相關技能。
- 在合併或關閉之前,記錄使用了什麼、改變了什麼,以及審查者仍需驗證的內容。
導入的工作流程筆記
導入:概覽
Astro 是一個專為內容豐富的網站設計的網頁框架 — 部落格、文件、作品集、行銷網站和電子商務。其核心創新是島嶼架構:預設情況下,Astro 向瀏覽器傳送零 JavaScript。互動式元件會以隔離的「島嶼」形式選擇性地進行水合。Astro 支援 React、Vue、Svelte、Solid 和其他 UI 框架同時存在於同一個專案中,讓您可以為每個元件選擇合適的工具。
導入:運作方式
步驟 1:專案設定
npm create astro@latest my-site
cd my-site
npm install
npm run dev
根據需要新增整合:
npx astro add tailwind # Tailwind CSS
npx astro add react # React 元件支援
npx astro add mdx # MDX 支援
npx astro add sitemap # 自動產生 sitemap.xml
npx astro add vercel # Vercel SSR 轉接器
專案結構:
src/
pages/ ← 基於檔案的 routing(.astro、.md、.mdx)
layouts/ ← 可重複使用的頁面外殼
components/ ← UI 元件(.astro、.tsx、.vue 等)
content/ ← 類型安全的內容集合(Markdown/MDX)
styles/ ← 全域 CSS
public/ ← 靜態資源(直接複製)
astro.config.mjs ← 框架配置
步驟 2:Astro 元件語法
.astro 檔案在頂部有一個程式碼圍欄(僅限伺服器端),下方是模板:
---
// src/components/Card.astro
// 此區塊僅在伺服器端執行 — 從不在瀏覽器中執行
interface Props {
title: string;
href: string;
description: string;
}
const { title, href, description } = Astro.props;
---
<article class="card">
<h2><a href={href}>{title}</a></h2>
<p>{description}</p>
</article>
<style>
/* 自動作用域至此元件 */
.card { border: 1px solid #eee; padding: 1rem; }
</style>
步驟 3:基於檔案的頁面和路由
src/pages/index.astro → /
src/pages/about.astro → /about
src/pages/blog/[slug].astro → /blog/:slug(動態)
src/pages/blog/[...path].astro → /blog/*(捕獲所有)
使用 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;
const { Content } = await post.render();
---
<h1>{post.data.title}</h1>
<Content />
步驟 4:內容集合
內容集合讓您可以類型安全地存取 Markdown 和 MDX 檔案:
// src/content/config.ts
import { z, defineCollection } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
date: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };
---
// src/pages/blog/index.astro
import { getCollection } from 'astro:content';
const posts = (await getCollection('blog'))
.filter(p => !p.data.draft)
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
---
<ul>
{posts.map(post => (
<li>
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
<time>{post.data.date.toLocaleDateString()}</time>
</li>
))}
</ul>
步驟 5:島嶼 — 選擇性水合
預設情況下,UI 框架元件會渲染為靜態 HTML,沒有 JavaScript。使用 client: 指令進行水合:
---
import Counter from '../components/Counter.tsx'; // React 元件
import VideoPlayer from '../components/VideoPlayer.svelte';
---
<!-- 靜態 HTML — 不向瀏覽器傳送 JavaScript -->
<Counter initialCount={0} />
<!-- 頁面載入時立即水合 -->
<Counter initialCount={0} client:load />
<!-- 當元件滾動到視野中時水合 -->
<VideoPlayer src="/demo.mp4" client:visible />
<!-- 僅在瀏覽器空閒時水合 -->
<Analytics client:idle />
<!-- 僅在特定媒體查詢時水合 -->
<MobileMenu client:media="(max-width: 768px)" />
步驟 6:佈局
---
// src/layouts/BaseLayout.astro
interface Props {
title: string;
description?: string;
}
const { title, description = '我的 Astro 網站' } = Astro.props;
---
<html lang="zh-TW">
<head>
<meta charset="utf-8" />
<title>{title}</title>
<meta name="description" content={description} />
</head>
<body>
<nav>...</nav>
<main>
<slot /> <!-- 頁面內容在此渲染 -->
</main>
<footer>...</footer>
</body>
</html>
---
// src/pages/about.astro
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout title="關於我們">
<h1>關於我們</h1>
<p>歡迎來到我們的公司...</p>
</BaseLayout>
步驟 7:SSR 模式(隨需渲染)
透過設定轉接器來啟用動態頁面的 SSR:
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'hybrid', // 'static' | 'server' | 'hybrid'
adapter: vercel(),
});
使用 export const prerender = false 選擇性地將個別頁面納入 SSR。
範例
範例 1:直接要求上游工作流程
使用 @astro-v2 來處理 <task>。從複製的上游工作流程開始,僅載入能改變結果的檔案,並在答案中保持出處的可見性。
說明: 當操作者需要導入的工作流程,但不需要整個儲存庫時,這是最安全的起點。
範例 2:要求基於出處的審查
根據 metadata.json 和 ORIGIN.md 審查 @astro-v2,然後解釋您會先載入哪些複製的上游檔案以及原因。
說明: 在審查或故障排除之前使用,當您需要精確、可審計的來源和檔案選擇解釋時。
範例 3:在執行前縮小複製的支援檔案範圍
使用 @astro-v2 進行 <task>。僅載入能改變結果的複製參考資料、範例或腳本,並在繼續之前明確命名這些檔案。
說明: 這使技能與漸進式揭露保持一致,而不是預設載入整個複製套件。
範例 4:建立審查套件
使用複製的上游檔案和出處審查 @astro-v2,然後在合併前總結任何差距。
說明: 當拉取請求等待人工審查且您想要一個可重複的審計套件時,這很有用。
導入的使用說明
導入:範例
範例 1:包含 RSS Feed 的部落格
// src/pages/rss.xml.ts
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';
export async function GET(context) {
const posts = await getCollection('blog');
return rss({
title: '我的部落格',
description: '最新文章',
site: context.site,
items: posts.map(post => ({
title: post.data.title,
pubDate: post.data.date,
link: `/blog/${post.slug}/`,
})),
});
}
範例 2:API 端點(SSR)
// src/pages/api/subscribe.ts
import type { APIRoute } from 'astro';
export const POST: APIRoute = async ({ request }) => {
const { email } = await request.json();
if (!email) {
return new Response(JSON.stringify({ error: '需要電子郵件' }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
await addToNewsletter(email);
return new Response(JSON.stringify({ success: true }), { status: 200 });
};
範例 3:作為島嶼的 React 元件
// src/components/SearchBox.tsx
import { useState } from 'react';
export default function SearchBox() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
async function search(e: React.FormEvent) {
e.preventDefault();
const data = await fetch(`/api/search?q=${query}`).then(r => r.json());
setResults(data);
}
return (
<form onSubmit={search}>
<input value={query} onChange={e => setQuery(e.target.value)} />
<button type="submit">搜尋</button>
<ul>{results.map(r => <li key={r.id}>{r.title}</li>)}</ul>
</form>
);
}
---
import SearchBox from '../components/SearchBox.tsx';
---
<!-- 立即水合 — 此島嶼是互動式的 -->
<SearchBox client:load />
最佳實踐
將產生的公開技能視為上游儲存庫周圍一個可審查的包裝層。目標是保持出處明確,並僅載入能實質改善執行的複製來源資料。
- ✅ 將大多數元件保持為靜態 .astro 檔案 — 僅水合必須互動的元件
- ✅ 對所有 Markdown/MDX 內容使用內容集合 — 您可以獲得類型安全性和自動驗證
- ✅ 對於折疊以下的元件,優先使用 client:visible 而非 client:load,以減少初始 JavaScript
- ✅ 使用 import.meta.env 來處理環境變數 — 將公開變數加上 PUBLIC_ 前綴
- ✅ 從 astro:transitions 新增 ,以實現流暢的頁面導航而無需完整的 SPA
- ❌ 不要在每個元件上都使用 client:load — 這會破壞 Astro 的效能優勢
- ❌ 不要在面向客戶端的模板中使用的 .astro frontmatter 中放置機密
導入的操作說明
導入:最佳實踐
- ✅ 將大多數元件保持為靜態
.astro檔案 — 僅水合必須互動的元件 - ✅ 對所有 Markdown/MDX 內容使用內容集合 — 您可以獲得類型安全性和自動驗證
- ✅ 對於折疊以下的元件,優先使用
client:visible而非client:load,以減少初始 JS - ✅ 使用
import.meta.env來處理環境變數 — 將公開變數加上PUBLIC_前綴 - ✅ 從
astro:transitions新增<ViewTransitions />,以實現流暢的頁面導航而無需完整的 SPA - ❌ 不要在每個元件上都使用
client:load— 這會破壞 Astro 的效能優勢 - ❌ 不要在面向客戶端的模板中使用的
.astrofrontmatter 中放置機密 - ❌ 在靜態模式下不要跳過動態路由的
getStaticPaths— 建置將會失敗
疑難排解
問題:操作者跳過了導入的上下文並給出過於通用的答案
症狀: 結果忽略了 plugins/antigravity-awesome-skills/skills/astro 中的上游工作流程,未能提及出處,或根本未使用任何複製的來源檔案。
解決方案: 重新開啟 metadata.json、ORIGIN.md 和最相關的複製上游檔案。首先檢查 external_source 區塊,然後在繼續之前重新陳述出處。
問題:導入的工作流程在審查中感覺不完整
…
[已截斷以進行翻譯]