FW 編寫 Astro
範圍與初步決策
此技能適用於 Astro 特定的元件、路由、內容、渲染和整合。請勿 用它來規定 React 內部機制、後端架構或部署供應商;僅在必要時才搭配相關的框架/執行時期技能。
在編輯之前,請檢查 package.json、鎖定檔案、Astro 和適配器版本、astro.config.*、tsconfig、現有路由/版面/內容配置以及儲存庫腳本。遵循已安裝版本的說明文件和現有慣例。未經授權,請勿安裝整合、升級依賴項、部署或呼叫付費服務。
- 對於可以預先建置的內容,優先使用預先渲染的 HTML。在前端資料(Frontmatter)中,對預渲染路由而言,程式碼在建置時執行;對按需路由而言,在伺服器上執行;它不是瀏覽器程式碼。
- 僅在實際需要請求時的行為時才使用 SSR,例如已認證的內容或最新資料。SSR 需要一個相容的適配器。在支援當前模式的版本中,預設的靜態輸出可以透過
export const prerender = false將個別路由切換為 SSR;output: 'server'則使 SSR 成為預設值,並允許使用prerender = true例外。較舊版本的混合配置不同:請在遷移前檢查。 - 一個完全靜態的網站通常不需要適配器。請勿將 Astro 與 Cloudflare 畫上等號,也不要在靜態內容上強加 SSR。
- 保留無障礙性(accessibility)、跳脫(escaping)和信任邊界。請勿使用
set:html插入不受信任的 HTML;應在其實際輸入邊界對受信任格式的渲染進行清理。
原生元件與有效 Props
使用 .astro 元件來處理版面與靜態內容。當元件接受 props 時,宣告 Props 型別;不需要 props 的頁面則無需儀式性的介面。使用實際元素的屬性,有目的地轉發屬性,並避免使用帶有不兼容屬性集合的多型標籤。一個連結卡片可以使用文章內部的連結,而不是將 href 傳遞給 <article>。請勿將互動式控制項巢狀在包圍性的錨點元素內。
ASTRO-CARD — 完整的 src/components/Card.astro;不需要 CSS 函式庫:
---
import type { HTMLAttributes } from 'astro/types';
interface Props extends Omit<HTMLAttributes<'article'>, 'title'> {
title: string;
description?: string;
href?: string;
}
const { title, description, href, class: className, ...rest } = Astro.props;
---
<article {...rest} class:list={['card', className]}>
<h2>{href ? <a href={href}>{title}</a> : title}</h2>
{description && <p>{description}</p>}
<slot />
</article>
對明確的內容區域使用具名插槽(named slots),對條件式類別使用 class:list。分別驗證不受信任的連結目的地;字串型別並非 URL 驗證。
在框架 Islands 之前使用小規模瀏覽器行為
首先使用語意化 HTML(details、原生表單),然後在需要瀏覽器行為時使用小型的處理過 <script>。請勿為了切換選單而加入 React/Vue/Svelte。Astro 腳本會被打包/去重;選擇所有元件實例或使用限域的自訂元素。使用客戶端導航時,遵循已安裝路由器的生命週期,並避免重複的監聽器。前端資料的值不會自動在瀏覽器腳本中使用;僅透過明確的 DOM 屬性或 props 傳遞非機密資料。
ASTRO-BUTTON — 完整的 src/components/Counter.astro,適用於一般的全頁面導航:
<button type="button" data-counter aria-label="增加計數">0</button>
<script>
document.querySelectorAll<HTMLButtonElement>('button[data-counter]').forEach((button) => {
let count = 0;
button.addEventListener('click', () => {
button.textContent = String(++count);
});
});
</script>
當現有框架元件或大量互動狀態證明有必要使用,且已安裝相關整合時,才使用框架 Island。對於立即需要的行為選擇 client:load,對於非關鍵行為選擇 client:idle,對於螢幕外內容選擇 client:visible,對於實際依賴媒體的情況選擇 client:media。沒有 client:* 指令的元件僅渲染 HTML,不會進行框架水合(hydration)。client:only 會跳過伺服器渲染,需要一個有意的載入/備用體驗,而不是一個萬用解決方案。
內容集合遵循已安裝的版本
對重複的結構化內容使用集合,而不是對每個獨立的頁面。在編輯前檢查現有配置和條目標識符:
- Astro 5 引入了 Content Layer 載入器模型,通常放在
src/content.config.ts。舊專案可能使用src/content/config.ts和type: 'content'而非載入器。這些檔案位置/API 不可互換。 - 檢查已安裝的 Zod 匯出名稱。以下範例針對 Astro 5 從
astro:content匯出的z;當前說明文件使用astro/zod。請勿在缺少該模組的版本中機械式地取代引入。 - 載入器條目使用
id;請勿假設傳統的slug或entry.render()API。對於 Content Layer 渲染,請使用支援的render(entry)輔助函式。如果包含 MDX 檔案,則需要其整合。
ASTRO-COLLECTION-V5 — 適用於 Astro 5 且包含本地 Markdown 條目的完整 src/content.config.ts:
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };
ASTRO-COLLECTION-LIST — 與該集合配對的完整頁面 src/pages/blog/index.astro,並至少包含一個符合 schema 的 Markdown 條目:
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog', ({ data }) => !import.meta.env.PROD || !data.draft);
podcasts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---
<h1>部落格</h1>
<ul>{posts.map((post) => <li>{post.data.title}</li>)}</ul>
此列表刻意不發明日誌詳細頁面的 URL。如果要加入連結,請實作對應的動態路由和用於預渲染頁面的 getStaticPaths()。同時檢查詳細路由和列表頁面中的草稿狀態;僅在索引頁面中進行過濾並非存取控制。請求時的私有內容不得透過建置輸出或公開快取洩漏。
在地化、Canonical 與 404 的一致性
在更改路由之前,先制定 URL 策略:設定的生產環境 site、部署 base、結尾斜線/建置格式、在地化前綴、根目錄行為和備用行為必須與實際檔案和主機重定向保持一致。
- 使用基於資料夾的路由。在
prefixDefaultLocale: false的情況下,預設語言的頁面位於根目錄;其他語言會有資料夾。在true的情況下,所有語言都會有在地化資料夾,且根目錄索引仍需有意的處理。 - 在有用時使用版本支援的
astro:i18n輔助函式。配置不會翻譯內容或建立缺失的頁面。僅連結現有的翻譯;在切換語言時保留有意義的等效路徑。 - Canonical URL 應使用生產來源和選定的規範路徑名稱,而非來自
Astro.url.href的任意請求主機/查詢參數。為部署設定site;考慮base和結尾斜線正規化。設定文件的lang屬性,並且僅為具有相互連結的真實等效頁面發出hreflang替代方案。請勿將所有在地化版本 canonical 到英文。 - 當需要自訂錯誤頁面時,實作
src/pages/404.astro。在 SSR 路徑上回傳真實的 404 狀態碼,而不是一個成功的錯誤頁面主體。在靜態託管中,確認產生的 404 檔案是以狀態 404 提供服務。請勿對多頁面網站使用 SPA 備用方案,或將每個缺失的在地化路徑重定向到首頁。避免索引錯誤頁面,並且不要為每個缺失的 URL 提供自我 canonical。
ASTRO-CANONICAL-FRAGMENT — 部分版面範例,非獨立頁面。假設已設定 site 且當前路徑名稱已遵守儲存庫的 base/locale/slash 策略:
---
if (!Astro.site) throw new Error('請設定生產環境網站 URL');
const canonical = new URL(Astro.url.pathname, Astro.site);
---
<link rel="canonical" href={canonical} />
資產與部署邊界
對於需要處理的圖片,優先使用 src/assets/ 和 astro:assets 的 Image 元件。將需要不變 URL、robots.txt 和圖示的資產保留在 public/ 中;對於刻意傳遞/遠端的情況,普通的 <img> 是有效的。提供有意義的 alt 屬性(裝飾性圖片使用空字串)以及內建尺寸或等效的版面限制。將響應式圖片 API 與已安裝的版本匹配,並避免急切地載入所有圖片;僅優先處理真正在首屏之上的關鍵圖片。在啟用前檢查 SSR 圖片服務及其執行時期/成本需求。
僅在必要時使用現有主機的標頭/重定向機制。_headers 和 _redirects 是供應商特定的,並非 Astro 的通用需求。對於適配器 SSR,請遵循該適配器版本產生的輸出和執行時期綁定慣例,而不是手動編寫通用的靜態/SPA 配置。
驗證與回報
在獲得授權時,使用儲存庫現有的檢查/建置/測試腳本。檢查 Props 型別、產生的路由、集合驗證、草稿詳細頁面暴露、語言切換連結、Canonical 來源/查詢參數移除、base/slash 行為、未知路由狀態、鍵盤行為和瀏覽器主控台錯誤。成功的靜態建置並不能證明 SSR 執行時期相容性或生產環境重定向。回報實際執行的命令、版本假設、缺失的整合/內容測試檔案以及未驗證的託管行為。請勿將安裝、部署或觸發遠端服務作為隱含的驗證步驟。
來源與出處
這是作者個人的彙整,並非第三方技能的批量複製。僅閱讀與任務和已安裝版本相關的文件:
- 官方 Astro:元件與 Props、瀏覽器腳本、按需渲染。
- 官方 Astro:內容集合、Astro 5 遷移、i18n 路由、Cloudflare 適配器。
- astrolicious/agent-skills 是一個社群參考資源,並非官方 Astro 文件或相容性保證。請有選擇性地參考;官方版本匹配的 API 文件優先。