Astro SEO
審計並改善 Astro 網站的 SEO 設定,涵蓋 Astro SEO: the definitive guide 中描述的完整技術棧。本技能涵蓋九個面向——技術基礎、結構化資料、內容、網站結構、效能、Sitemap 與索引、代理程式探索、重新導向和分析——並針對任何缺失或薄弱的部分產生可直接套用的程式碼。
本技能的核心主幹是 @jdevalk/astro-seo-graph。大多數的修復都會透過它來實現。如果專案尚未使用此套件,安裝它會是第一個建議。
程式碼食譜(recipes)位於 AGENTS.md —— 當你需要實作特定修復時,請閱讀該檔案。此檔案包含工作流程和審計檢查清單。
工作流程
- 偵測專案 — 確認這是一個 Astro 網站並了解其結構。
- 審計 — 為九個類別評分,並產出可操作的發現。
- 改善 — 產生或修改檔案以填補差距。食譜位於
AGENTS.md。 - Metadata 檢查 — 對技能產生的每個簡短字串(標題、描述、schema
description欄位、常見問題解答、frontmatter 摘要)調用metadata-check。 - 驗證 — 執行建置,確認驗證通過,提醒使用者關於非檔案性質的任務(Search Console、Bing Webmaster Tools、IndexNow 金鑰驗證)。
階段 0:偵測專案
在審計前確認基本事項:
astro.config.mjs/astro.config.ts存在。package.json將astro列為依賴項。site:已在astro.config中設定 — Canonical、Sitemap 和 OG 圖片的 URL 都由此衍生。如果遺失、為空或設為http://localhost,請將其標記為阻塞性問題,優先於其他任何事項處理。這是最常見的單一錯誤配置。- 內容集合位於
src/content/(或舊版的src/pages/markdown)。 - 部署目標 — 讀取
package.json、vercel.json、netlify.toml、wrangler.toml或public/_headers以確定主機。這將驅動階段 2 中的重新導向和標頭語法。 @jdevalk/astro-seo-graph是否已安裝? 如果是,請記錄版本號以及已連接的功能(grep 搜尋<Seo、seoGraph(、createSchemaEndpoint、createSchemaMap、FuzzyRedirect、createIndexNowKeyRoute、createMarkdownEndpoint、createApiCatalog、gitLastmod)。使用npm view @jdevalk/astro-seo-graph version檢查已安裝版本與 npm 上最新版本是否一致。 如果專案落後,建議在審計功能差距前的階段 2 進行升級——該套件會定期發布新的預設值和修復,而過時的版本可能是任何審計發現的合理原因。階段 2 會根據此結果分支處理。- 網站是否為多語言? 檢查
astro.config中的i18n或src/content/下的多個語言目錄。如果是,則 hreflang 很重要;如果否,則跳過。
只詢問你無法偵測到的資訊。不要詢問使用者該網站的主題——請讀取 astro.config.mjs 和首頁內容。
階段 1:審計
每個類別滿分為 10 分。對於每個類別,請給出 2 到 4 個具體的發現,並引用實際的程式碼或配置。在每個類別中,檢查項目按以下等級劃分:
- 必須 — 出貨阻塞器。此處失敗會導致明顯的 SEO 倒退。
- 應該 — 標準做法。跳過會損失觸及率。
- 可選 — 前瞻性或情境性的。有用,但並非每個網站的基準。
對於小型個人部落格,跳過可選檢查,除非使用者要求完整處理。
1. <Seo> 元件與 head metadata (/10)
- 必須 — 所有 head metadata 使用單一元件(而非分散在各個佈局中)。
- 必須 —
astro.config中的site:已設定為生產環境的 origin。 - 必須 — Canonical URL 衍生自
site配置,並已去除追蹤參數。 - 必須 — 當
noindex為 true 時,省略 canonical(根據 Google 的建議)。 - 必須 — 遺漏 SEO 欄位時的備用鏈:
seo.title → title → siteName;seo.description → excerpt → first paragraph。頁面出現空白標題或描述是備用鏈損壞的最常見症狀。 - 應該 —
robotsmeta 包含max-snippet:-1、max-image-preview:large、max-video-preview:-1。 - 應該 — 當 Twitter 標籤與 Open Graph 重複時將其抑制(Twitter 會自動回退)。
- 應該 — 在多語言網站上存在
hreflang替代連結。如果網站是單一語言則跳過。 - 可選 — 使用
@jdevalk/astro-seo-graph的<Seo>元件而非手動編寫的。(手動編寫但涵蓋上述所有內容的也可以;本技能傾向於推薦此套件,因為它預設處理了備用鏈和 robots 規則。)
2. 結構化資料 / JSON-LD 圖譜 (/10)
- 是單一的扁平
Article物件,還是具有多個實體的連結@graph? - 實體是否使用
@id引用連接? WebSite、Blog/WebPage、Person/Organization、BlogPosting/Article、BreadcrumbList、ImageObject是否都在相關處存在?- 信任訊號:
publishingPrinciples、copyrightHolder、copyrightYear、knowsAbout、SearchAction? - 在 Rich Results Test 和 ClassySchema 中驗證通過?
3. 內容集合與 SEO Schema (/10)
- 內容集合是否使用 Zod schema 定義?
@jdevalk/astro-seo-graph的seoSchema是否強制執行標題(5-120)和描述(15-160)的字元長度?- 必要欄位(
publishDate、title、excerpt)是否在建置時強制執行? - 去除 Markdown 後的
articleBody是否在 schema endpoints 中公開(最多 10,000 字元)?
4. Open Graph 圖片 (/10)
- 每個頁面都有 OG 圖片,還是很多遺漏?
- 1200×675(Google Discover 最小寬度 1200px,16:9 比例)?
- 在建置時透過 satori + sharp 生成,還是手動的?
- JPEG(社交平台不穩定支援 WebP/AVIF)?
- OG URL 是否自動從 slug 衍生出路徑?
- 渲染後的 HTML 中的每個
<img>是否都有alt屬性(或裝飾性圖片使用alt=""/role="presentation")?seoGraph()上的validateImageAlt在 1.1.0 及以上版本中會在建置時捕獲此問題。
5. Sitemap 與索引 (/10)
- 必須 — 已安裝
@astrojs/sitemap,sitemap index 可訪問。 - 必須 —
robots.txt引用了 sitemap index。 - 必須 — RSS feed 存在(
@astrojs/rss),透過<link rel="alternate" type="application/rss+xml">宣告,包含完整的文章內容(非截斷的摘要)。 - 應該 — 透過
chunks選項按集合分拆(例如sitemap-posts-0.xml)——這使得在 GSC 中除錯索引問題變得容易得多。 - 應該 —
lastmod從 git 提交時間戳填充,而非 frontmatter 日期或 CI 檔案時間戳。@jdevalk/astro-seo-graph1.4.0 及以上版本導出了gitLastmod(filePath, { excludeCommits, depth })來實現此功能——它返回影響該檔案的最新非排除提交的提交者日期,如果 git 不可用則返回null。將其接入 sitemap 的serialize回呼。如果程式碼庫中有手動編寫的execSync('git log ...')輔助函式,請將其替換為套件導出的函式——該匯出函式能處理批次提交排除(如匯入、格式化等),這是單純的-1查詢無法做到的。 - 應該 — IndexNow 已整合並在每次建置時提交更新,金鑰驗證路由位於
/[key].txt。1.0.1 及以上版本預設排除/404的提交。根據生產主機環境來條件性地執行提交(例如process.env.CF_PAGES === '1' && CF_PAGES_BRANCH === 'main'、VERCEL_ENV === 'production'、CONTEXT === 'production')。無條件提交會在每次本機npm run build和預覽部署時都會向端點發送請求,而這些 URL 尚未由生產主機提供服務,這會導致金鑰被標記為無效(403)並強制輪換。
6. 代理程式探索 (/10)
- 應該 — Schema endpoints(
/schema/*.json)公開整個網站的 JSON-LD。 - 應該 — Schema map(
/schemamap.xml)列出所有 endpoints,並在robots.txt中包含Schemamap:指示。 - 應該 — 網站根目錄下的
llms.txt為 LLM 消費者列出頁面(標題 + 描述)。@jdevalk/astro-seo-graph0.9.0 及以上版本透過llmsTxt整合選項生成此檔案。 - 應該 — Markdown 格式的替代 URL(例如
/blog/post.md與/blog/post/並存),提供帶有 YAML frontmatter 的乾淨 Markdown,供 AI 代理程式消費而無需解析 HTML。@jdevalk/astro-seo-graph1.2.0 及以上版本提供了createMarkdownEndpoint用於路由,以及一個markdownAlternate: true的整合選項,它會在每個頁面上發出<link rel="alternate" type="text/markdown">。1.3.0 及以上版本增加了建置後驗證:整合會遍歷建置輸出,並移除任何目標.md檔案不存在的連結(每次出現會發出warn警告)——因此配置錯誤的 endpoint 會以建置警告的形式顯現,而不是將 404 發佈給使用者。配合 Cloudflare Transform Rule(使用wildcard_replace的 URL 改寫,無需Vary: Accept標頭——Cloudflare 會剝離自訂的 Vary 值),可以實現對Accept: text/markdown的內容協商,而無需 SSR。 - 應該 — 根據 RFC 9727 在
/.well-known/api-catalog提供 API 目錄。@jdevalk/astro-seo-graph1.4.0 及以上版本提供了createApiCatalog,它會自動將 schema endpoints 類型化為其https://schema.org/<Type>URL,並根據siteUrl將路徑轉換為絕對路徑。列出 schema endpoints、schemamap 以及任何網站特定的 API(如/ask、/feed.xml等)。RFC 已經定稿,因此格式是穩定的;採用率尚早,但成本只是一個路由檔案。 - 應該 — 在
robots.txt中包含 Content Signals 指示(例如Content-Signal: ai-train=yes, search=yes, ai-input=yes)。獨立於爬取存取權限來宣告對 AI 訓練、搜尋接地和 AI 輸入使用的偏好。規範是一個 IETF 草案,採用率尚早,但這只是每個網站都已有的檔案中的一行。 - 應該 — 在
/*上設定Link標頭指向探索檔案(sitemap、llms.txt、api-catalog、schemamap,以及網站發布的任何 MCP / A2A 卡片)。讀取回應標頭的代理程式無需解析 HTML 即可找到它們。在 Cloudflare Pages / Netlify 上,這是public/_headers;在 Vercel 上,這是vercel.json。 - 可選 — 在
/.well-known/mcp/server-card.json處的 MCP 伺服器卡片(SEP-1649)和/或在/.well-known/agent-card.json處的 A2A 代理程式卡片(A2A protocol)。僅當網站確實公開了 MCP 伺服器或 A2A 代理程式時相關。兩者都是靜態 JSON 檔案,用於宣告端點、能力和技能。否則跳過。 - 可選 — 指向對話端點的
<link rel="nlweb">。NLWeb 尚處於早期階段;這個標籤只有一行且值得擁有,但在 2026 年它不會成為評分障礙。 - 可選 — 在
/.well-known/ai-catalog.json處的 ARD (Agentic Resource Discovery) 目錄,列出該域名提供的內容(MCP 伺服器、A2A 代理程式、OKF 套件、網站特定 API)。v0.9 草案,因此可選——但它是 MCP / A2A 卡片和 OKF 套件得以發揮效用的探索層。兩個陷阱:基礎規範(Agent-Card/ai-catalog)將 media-type 欄位命名為mediaType,而 ARD 層(ards-project/ard-spec)將其命名為type——請發出兩個具有相同值的鍵,以便條目在兩種解讀下都能通過驗證(兩個規範都要求消費者忽略未知鍵)。ARD 還為每個條目增加了可選的representativeQueries陣列,包含範例提示。 - 可選 — OKF (Open Knowledge Format) 套件:一個由類型化的 Markdown 概念檔案組成的樹(每個頁面一個,路徑鏡像 canonical URL),打包為單一的
.tar.gz,中間有索引檔案。提供服務和探索明確不是 OKF 的目標——這是 ARD 目錄條目的用途。v0.9 草案,可選。目前還沒有註冊的媒體類型,因此過渡字串是application/okf-bundle+gzip(追蹤於 knowledge-catalog#111 和 ard-spec#27);將其標記為過渡性的,可能會改變。最好作為現有內容管道的另一個輸出生成,而不是手動維護的副本。
7. 效能 (/10)
- 預設為靜態輸出(在不需 SSR 的頁面上不使用 SSR)?
- 除非某個 island 需要,否則零客戶端 JS?
- 所有內容圖片都使用 Astro
<Image>元件(響應式 srcset、WebP、懶加載、非同步)? - 主要網頁字體以 woff2 格式預加載?
- 使用
defaultStrategy: 'viewport'的<ClientRouter />進行預取? - 位於
/_astro/下的雜湊化資產是否提供Cache-Control: public, max-age=31536000, immutable? No-Vary-Search回應標頭是否從快取鍵中剝離 UTM 參數?
8. 重新導向與錯誤處理 (/10)
- 是否為每個曾經存在且已移動的 URL 維護了
public/_redirects(或等效配置)? - 永久移動使用 301 而非 302?
- 來自
@jdevalk/astro-seo-graph的FuzzyRedirect元件是否已接入 404 頁面? - 404 頁面本身是否返回 404 狀態碼,而非 200?
9. 建置時驗證與內容品質 (/10)
- 必須 —
seoGraph()整合在每次建置時執行,並啟用validateH1和validateUniqueMetadata。對於 JSON-LD 驗證,請在seo-graph-core的assembleGraph()中傳遞warnOnDanglingReferences: true——這是在組裝時進行的檢查,並非一個整合選項。 - 應該 — 在
seoGraph()上啟用validateImageAlt、validateMetadataLength和validateInternalLinks(在 1.1.0 及以上版本中全部預設為true)。它們會捕獲遺失的替代文字、超出搜尋結果頁面範圍的標題或描述(預設值:標題 30-65,描述 70-200),以及導致 404 或尾部斜線不匹配的內部連結。如果專案使用 1.1.0,請升級到 1.1.1 或更高版本——該補丁版本修復了兩個驗證器錯誤:validateInternalLinks現在能正確識別public/資源作為有效目標(不再對/images/*或/fonts/*產生誤報),並且validateMetadataLength不再截斷包含中文字元的描述。
最終分數摘要
審計結束時,提供一個類似這樣的摘要表格:
| 類別 | 分數 | 高優先級發現 |
|---|---|---|
| 1. Head metadata | 8/10 | 一些頁面缺少 canonical;robots meta 未設定 max-snippet |
| 2. 結構化資料 | 6/10 | 缺少 WebSite、Person 圖譜;BreadcrumbList 未連接 |
| ... | ... | ... |
階段 2:改善
在 AGENTS.md 中為每個發現查找食譜。對於階段 1 中標記為「必須」的每一項,在繼續之前至少應收到一個針對它的提交。
對使用者:
- 具體列出你將建立的檔案和修改。
- 在被問到之前不要 git commit——使用者可能想要檢查你的工作。
- 對於 JavaScript/TypeScript 變更,請遵循專案現有的語法(例如,專案使用
function關鍵字時就不要使用箭頭函式;使用專案使用的引號類型等)。 - 在進行變更之前,請務必檢查
astro.config中的site:配置。 在所有常見的錯誤配置中,這是審計和修復的最重要的一個,所有其他工作都依賴於它。
不要手動編寫 <Seo> props 和 HTML 範本——使用 @jdevalk/astro-seo-graph 並從那裡進行配置。當你產生或修改一個元件時,請輸出整個新檔案,而不僅僅是片段。使用者需要查看上下文。
階段 3:Metadata 檢查
使用 metadata-check CLI 檢查所有在階段 2 中產生的簡短 SEO 字串:標題、描述、schema 描述、JSON-LD 文字欄位、常見問題解答答案、frontmatter 摘要。
這是最後的字串級別驗證。seoGraph() 的 validateMetadataLength 是一個很好的預提交掛鉤,但 metadata-check 是獨立的,並且提供可操作的邊界建議(「此描述為 152 個字元,剛好在範圍內,但您的網站平均摘要為 85 個字元——考慮將其縮短到 120 個字元以保持一致性」)。
不要在審計之前或期間運行 metadata-check——它檢查的是輸出,而不是現有狀態。
階段 4:驗證
- 運行
npm run build(或astro build)並確認沒有錯誤和意外警告。 - 如果技能製作了 sitemap 或 robots.txt,請檢查它們在
dist/中的輸出。 - 提醒使用者需要手動完成的事項:
- 將網站提交到 Google Search Console(如果尚未提交)。
- 登入 Bing Webmaster Tools 並添加網站(如果尚未添加)。Bing 引擎通常會自行發現網站,但驗證所有權可以解鎖更深入的資料和診斷工具。
- 驗證 IndexNow 金鑰(如果已啟用)。金鑰檔案會在建置時產生,但需要由搜尋引擎確認。
- 在需要處設定
cache-control標頭(Cloudflare Pages、Netlify 或 Vercel 使用者可能需要修改 UI 設定)。 - 如果新增了重定向,請確保基礎設施(Cloudflare、Vercel、Netlify)支援它們。
- 如果有大量已建立索引的內容,請檢查 Google Search Console 的涵蓋範圍報告,以發現此技能修復之外的異常情況。