Communitygithub.com

ajelinek/skills-stash

專門用於撰寫或重構 Astro TypeScript 程式碼的技能:使用 Astro 處理靜態頁面與佈局,SolidJS 或 React 島嶼處理所有互動性,CSS Modules 獨立檔案、hydration 指令、內容集合、伺服器島嶼、隨需渲染、Astro Actions,以及可存取的語意化 HTML。當任務涉及共享 UI 結構、樣式、語意、可存取性或基礎元件決策時,請與 `ui-engineering` 技能一同使用。

skills-stash 是什麼?

此技能提供撰寫或重構 Astro TypeScript 程式碼的完整指導。它明確區分 Astro(負責靜態結構,如頁面、佈局與純展示區塊)與 SolidJS 或 React 島嶼(負責所有使用者互動、狀態管理與事件處理)。其中最關鍵的規則是:所有元件樣式必須使用獨立的 CSS Modules 檔案(styles.module.css),絕不能使用內聯樣式或 Astro 的 `<style>` 區塊。此外,技能涵蓋 Astro 專案的結構規範(如元件分類、命名慣例)、hydration 指令的選擇策略、Astro 5 內容集合的設定、伺服器島嶼與隨需渲染(SSR)的實作、以及 Astro Actions 的型別安全伺服器端函式。此技能支援所有 Astro 專案,並可與 `ui-engineering` 技能互補,適用於同時涉及共享 UI 基礎結構的任務。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ajelinek/skills-stash/tree/HEAD/astro.js

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

Astro

Astro 負責靜態結構:頁面、佈局以及純展示區域。 SolidJS 或 React 負責所有互動性:每個處理使用者輸入、管理狀態或回應事件的元件,都必須是一個框架島嶼(framework island),而非 .astro 檔案。

所有元件樣式皆使用 CSS Modules,且一律放在獨立的 styles.module.css 檔案中,絕不內嵌於 Astro <style> 區塊內。

何時使用此技能

  • 規劃新的 Astro 專案結構,或新增頁面與佈局區域
  • 建立 .astro 頁面、佈局或靜態展示區域
  • 判斷某個項目應放在 Astro 還是 SolidJS/React 島嶼中
  • 為島嶼選擇合適的 hydration 指令
  • 在 .astro 檔案或框架島嶼中應用 CSS Modules 樣式
  • 處理內容集合(src/content/、src/content.config.ts)
  • 將服務層資料傳入伺服器渲染的 Astro 頁面
  • 使用伺服器島嶼(server:defer)實現個人化的延遲渲染區域
  • 透過適配器與中介軟體設定隨需渲染(SSR)
  • 定義並呼叫 Astro Actions 以進行型別安全的伺服器端變更

Astro 與島嶼的核心架構決策

這是 Astro 專案中最重要的決策。

用途使用哪種技術
從資料渲染靜態 HTML — 無使用者互動.astro
頁面外殼、佈局容器、導覽結構.astro
內容區塊、部落格文章、行銷區域.astro
任何包含 onClick、onChange、表單狀態或反應式資料的元件SolidJS 或 React 島嶼
基礎 UI 元件(Button、Input、Modal、Alert 等)SolidJS 或 React 島嶼
任何讀取或寫入 store 或服務 hook 的元件SolidJS 或 React 島嶼

簡而言之的規則:

  • Astro 渲染結構與內容,但不處理使用者互動。
  • SolidJS 或 React 負責所有互動、所有表單狀態以及所有基礎互動式 UI 原語 — 即使只是觸發事件的簡單按鈕。
  • 不要在 .astro 檔案中建立互動式 UI。Astro 不具有反應性,嘗試在 .astro 檔案中加入互動性,會產生脆弱且難以測試的程式碼。

該選哪個框架 — SolidJS 還是 React?

專案應一致使用其中一個。請檢查 astro.config.mjs 中的設定整合(@astrojs/solid-js 或 @astrojs/react),並在整個專案中對所有島嶼使用該框架。請勿在同一個專案中混用兩個框架。

詳情請參閱 ./references/islands-and-hydration.md 以獲得完整的決策指南與 hydration 指令參考。

樣式規則 — 使用分離的 CSS Modules 檔案

這是此技能中最關鍵的規則。

每個 Astro 元件、頁面與佈局都使用 CSS Modules 進行範圍樣式設定。CSS 存在於獨立的檔案中 — 絕對不使用 Astro 的 <style> 標籤。

ComponentName/
├── index.astro         ← 元件邏輯與標記
└── styles.module.css   ← 此元件的所有樣式,一律使用獨立檔案
  • 永遠在 index.astro 旁建立 styles.module.css。
  • 絕對不要將樣式放在 Astro 的 <style> 區塊內。
  • 絕對不要使用內聯 style 屬性。
  • 在 frontmatter 區塊頂端匯入模組:import styles from './styles.module.css'
  • 使用 class:list 指令或直接類別繫結來套用類別:
    • <div class={styles.container}>
    • <div class:list={[styles.container, isActive && styles.active]}>
  • 使用語意化的類別名稱,不要堆疊工具類別。
  • 使用 CSS 自訂屬性(custom properties)來定義所有設計符記(顏色、間距、排版)。
  • 不使用 !important。不使用深度選擇器。不使用 ID 選擇器設定樣式。

詳情請參閱 ./references/styling-and-css-modules.md 以獲得符記策略、主題變數、響應式規則與動畫指引。 請參閱 ./examples/button-component/ 以獲得完整的 Button 範例與獨立的 CSS Module 檔案。

專案結構

src/
├── components/
│   ├── foundation/         # 互動式 UI 原語 — SolidJS 或 React,不是 .astro
│   │   ├── Button/
│   │   │   ├── index.tsx           ← SolidJS (.tsx) 或 React (.tsx)
│   │   │   └── styles.module.css
│   │   └── Input/
│   │       ├── index.tsx
│   │       └── styles.module.css
│   ├── layout/             # 靜態佈局結構 — .astro
│   │   ├── Header/
│   │   │   ├── index.astro
│   │   │   └── styles.module.css
│   │   └── Footer/
│   │       ├── index.astro
│   │       └── styles.module.css
│   └── features/           # 互動式功能區域 — SolidJS 或 React
│       └── SomeFeature/
│           ├── index.tsx           ← 島嶼元件
│           └── styles.module.css
├── layouts/
│   └── BaseLayout/
│       ├── index.astro             ← 佈局外殼永遠是 .astro
│       └── styles.module.css
├── pages/
│   ├── index/
│   │   ├── index.astro             ← 頁面永遠是 .astro
│   │   └── styles.module.css
│   └── [dynamic]/
│       ├── index.astro
│       └── styles.module.css
├── content/
│   ├── blog/
│   └── [collection-name]/
├── content.config.ts   ← Astro 5 集合綱要與載入器
├── store/
│   ├── repository/
│   ├── service/
│   └── config.ts
├── styles/
│   ├── tokens/
│   │   ├── _colors.css
│   │   ├── _spacing.css
│   │   └── _typography.css
│   ├── global.css
│   └── themes/
│       ├── light.css
│       └── dark.css
└── utils/

命名慣例:

  • .astro 頁面與佈局:PascalCase/ 資料夾,內含 index.astro
  • 框架島嶼元件:PascalCase/ 資料夾,內含 index.tsx
  • 頁面:kebab-case/ 資料夾,內含 index.astro 或 [dynamic]/ 內含 index.astro
  • CSS Module 檔案:一律命名為 styles.module.css — 每個元件目錄一個
  • 工具函式:kebab-case.ts

詳情請參閱 ./references/project-structure.md 以獲得目錄職責與命名慣例的完整說明。

Astro 元件樣式

.astro 檔案僅用於靜態結構。它們從 props 與資料渲染 HTML — 不處理事件或管理狀態。

  • 在 frontmatter 區塊中使用 interface Props 定義型別化 props。
  • 透過 Astro.props 存取 props。
  • 保持元件小型且單一職責。
  • 偏好組合而非 prop drilling。
  • 保持表達式簡單;將複雜邏輯移至 frontmatter 變數。
  • 使用語意化的 HTML 元素 — <section>、<article>、<nav>、<main>、<header> — 而不是通用的 <div> 容器(當元素具有語意意義時)。
---
import styles from './styles.module.css'

interface Props {
  title: string
  subtitle?: string
}

const { title, subtitle } = Astro.props
---

<section class={styles.hero} aria-label={title}>
  <h1 class={styles.title}>{title}</h1>
  {subtitle && <p class={styles.subtitle}>{subtitle}</p>}
  <slot />
</section>

詳情請參閱 ./references/component-patterns.md 以獲得 frontmatter 慣例、slot 用法與 Astro API 參考。

基礎元件 — SolidJS 或 React,不是 Astro

基礎 UI 原語(Button、Input、Alert、Modal、Select、Toggle 等)永遠以 SolidJS 或 React 元件建構。它們絕對不是 .astro 檔案。

原因: 基礎元件處理使用者事件、管理焦點、暴露 onClick 與 onChange 回呼,有時還包含內部狀態。這些在 .astro 檔案中都無法做到。將「按鈕」建構為 .astro 會產生無法以型別安全、可重複使用方式回應點擊的靜態 HTML。

決策規則:

  1. 原語已存在 — 直接使用。
  2. 原語接近需求但缺少某個 prop — 擴展現有的原語。
  3. 原語不存在 — 在 components/foundation/ 中以 SolidJS 或 React 元件建立它之後再使用。絕不要在頁面或功能元件中內嵌一次性互動元素。

所有基礎元件必須一致、可存取且強型別。請參考 solid.js 或 react 技能以了解島嶼元件內適用的實作慣例。

島嶼與 Hydration

每個互動式元件都是一個島嶼。從 .astro 頁面與佈局中使用 client:* 指令掛載島嶼。選擇能滿足互動需求的最小指令。

指令使用時機
client:load必須在頁面載入時立即互動
client:idle可以等到瀏覽器空閒時再處理
client:visible僅在其進入視口時才需要 hydrate
client:media="(query)"僅在特定視口尺寸下互動
client:only="solid-js" 或 client:only="react"需要瀏覽器 API 才能渲染;跳過 SSR

預設使用 client:visible 或 client:idle。僅在使用者會立即互動的 UI(主要表單、導覽下拉選單、驗證頁面)上使用 client:load。

島嶼元件始終擁有自己的 styles.module.css:

components/features/ContactForm/
├── index.tsx          ← SolidJS 或 React 島嶼
└── styles.module.css  ← 獨立的 CSS Module,與其他規則相同

從 Astro 頁面掛載島嶼:

---
import styles from './styles.module.css'
import ContactForm from '../../components/features/ContactForm/index.tsx'

const { prefillEmail } = Astro.props
---

<section class={styles.section}>
  <h2 class={styles.heading}>聯絡我們</h2>
  <ContactForm client:visible prefillEmail={prefillEmail} />
</section>

詳情請參閱 ./references/islands-and-hydration.md 以獲得完整的決策指南、框架特定注意事項與資料傳遞規則。

內容集合

內容集合是管理 Markdown、MDX 與結構化資料檔案的標準方式,並提供完整的 TypeScript 型別安全性。

Astro 5 主要變更:

  • 設定檔位於 src/content.config.ts(非 src/content/config.ts)
  • 集合使用 loader — 從 astro/loaders 匯入的 glob() 或 file()
  • render(entry) 是從 astro:content 匯入的函式(非 entry.render())
  • 從 astro:content 匯入 z,而非直接從 zod 匯入
// src/content.config.ts
import { defineCollection, z, reference } 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(),
    pubDate: z.coerce.date(),
    draft: z.boolean().default(false),
  }),
})

export const collections = { blog }

在頁面中渲染:

---
import { getEntry, render } from 'astro:content'
const post = await getEntry('blog', Astro.params.slug)
const { Content } = await render(post)
---
<Content />

詳情請參閱 ./references/content-collections.md 以獲得完整 API:載入器、跨集合參照、自訂載入器、執行時期集合與動態路由模式。

伺服器島嶼、SSR 與 Actions

伺服器島嶼 (server:defer)

將個人化或動態的 .astro 元件延遲處理,同時立即提供頁面外殼。需要適配器。

<UserCart server:defer>
  <span slot="fallback">···</span>
</UserCart>

延遲的元件在伺服器端執行並串流輸出。用於原本會阻塞靜態頁面傳遞的使用者特定 UI(購物車數量、通知、個人化問候語)。

隨需渲染 (SSR)

透過 export const prerender = false(混合模式)將頁面加入伺服器渲染,或全域設定 output: 'server'。

SSR 頁面可以存取 Astro.cookies、Astro.request、Astro.redirect() 與 Astro.locals(由中介軟體填入)。

中介軟體

在 src/middleware.ts 中定義請求攔截邏輯:

import { defineMiddleware } from 'astro:middleware'

export const onRequest = defineMiddleware(async (context, next) => {
  context.locals.user = await getUser(context.cookies.get('session')?.value)
  return next()
})

Astro Actions

在 src/actions/index.ts 中定義型別安全的伺服器端函式,可從島嶼或 HTML 表單呼叫:

// src/actions/index.ts
import { defineAction, ActionError } from 'astro:actions'
import { z } from 'astro:content'

export const server = {
  newsletter: {
    subscribe: defineAction({
      input: z.object({ email: z.string().email() }),
      handler: async ({ email }) => {
        await addSubscriber(email)
        return { success: true }
      },
    }),
  },
}

從島嶼中呼叫:

import { actions } from 'astro:actions'
const { data, error } = await actions.newsletter.subscribe({ email })

使用 isInputError(error) 來區分 Zod 驗證錯誤與處理器錯誤。

詳情請參閱 ./references/server-rendering.md 以獲得完整內容:渲染模式、適配器設定、中介軟體、伺服器島嶼、隨需 API、表單動作、錯誤碼、型別化環境變數 (astro:env) 與視圖轉場。

Astro API 參考

  • Astro.props — 型別化的元件 props
  • Astro.params — 動態路由參數 ([slug]、[...path])
  • Astro.request — 伺服器端請求物件(標頭、cookie、URL)
  • Astro.url — 目前頁面 URL
  • getStaticPaths() — 列舉靜態網站生成的路徑
  • getEntry() / getCollection() — 內容集合查詢

服務層資料流程

Astro 頁面與佈局是在 frontmatter 區塊中呼叫服務或儲存庫函式的正確位置。元件應以 props 形式接收資料。

  • 在頁面 frontmatter 中取得資料,而非在元件內部。
  • 將資料以型別化 props 向下傳遞。
  • 元件不得直接呼叫儲存庫或外部 API。
  • 將驗證與業務邏輯保留在服務層。

可存取性

  • 當元素具有意義時,使用語意化的 HTML 元素。
  • 在真正提供額外語意資訊的地方加入 ARIA 屬性。
  • 確保所有互動式元素皆具有可存取的名稱。
  • 維持可見的焦點狀態。
  • 互動式元素的最小觸控目標大小為 44px。
  • 尊重 prefers-reduced-motion。
  • 在頁面內容中按邏輯順序安排標題層級(h1 → h2 → h3)。

詳情請參閱 ./references/accessibility-patterns.md 以獲得 ARIA 模式、表單標籤與標題階層指引。

支援檔案

  • ./references/styling-and-css-modules.md CSS Modules 規則、符記策略、主題變數、響應式與動畫。

  • ./references/islands-and-hydration.md 決定是否為島嶼、選擇哪個框架、hydration 指令選擇指南、資料傳遞規則、框架特定注意事項。

  • ./references/component-patterns.md Astro frontmatter 慣例、slot 用法、元件組合模式、Astro 物件 API。

  • ./references/content-collections.md 定義集合(Astro 5 語法)、查詢與渲染條目、跨集合參照、自訂載入器。

  • ./references/server-rendering.md 渲染模式(靜態、混合、伺服器)、適配器設定、中介軟體、伺服器島嶼、Astro Actions、表單動作、錯誤代碼、astro:env、檢視轉場。

  • ./references/accessibility-patterns.md ARIA 模式、表單標籤、錯誤訊息、標題階層、焦點管理、prefers-reduced-motion。

  • ./examples/button-component/ 完整的 Button 範例,使用 SolidJS 或 React 與獨立的 CSS Module 檔案。

  • ./examples/contact-form/ 包含表單驗證的 ContactForm 島嶼,使用 Astro Actions 進行型別安全的伺服器端處理。

相關技能