Astro 架站筆記(三):如何製作文章列表?簡介 Content Collections
前一篇文章我們討論了如何透過 Astro 的 Layouts 並使用 Markdown 來建立文章,而這些文章如果是放在 src/pages/
下,則能夠自動被 Astro 產生對應的 URL,進而能在瀏覽器中讀起。
但是要建立部落格,則勢必要有個入口的頁面來羅列這些文章的標題和連結,如果要每次新增一篇文章的時候都修改這個入口頁面,顯然不太方便,偶爾新刪修文章時忘了修改這個頁面,標題連結等資訊就會對不上了。
一個合格的 Static Site Generator 都會包含「取得文章列表」的功能,那就讓我們來看看 Astro 是怎麼做到這件事的。
Import Meta Glob
先來看看最簡單的方式,在 Astro 官方的 Create a blog post archive 中就有這樣的教學:透過 import.meta.glob()
來取得列表。
我們可以先在 pages/posts
底下建立幾篇 Markdown 所撰寫的文章,然後新增一個我們要作為入口頁面的檔案為 posts.astro
,架構大致如下:
1 | ├── src |
接著修改 posts.astro
:
1 | --- |
這裡的重點就在於 import.meta.glob('./posts/.md')
這段,可以將所有 ./posts/ 底下的檔案匯入 Array 中,而 Astro 是透過 Vite 來建置網站,import.meta.glob
就是 Vite 所提供的 Glob Import API,用來找出符合條件的檔案。
不單單只是 md 的副檔名,也可以透過 .{md,mdx,tsx}
的方式來一次讀取不同種類的檔案,以及設定 Lazy Loading 或 Eager Loading(一次載入或分批載入。但是在 SSG, Static Site Generator 的情境下,由於都是產出靜態檔案,等同於使用 Eager Loading)等等。
然而這樣的 API 有個比較重大的的缺點,如果你習慣於寫 TypeScript 的話,就要手動寫型別來防呆。接下來要談的另外一種方式,就是比較建議的 API - getCollection()
。
Content Collections
Astro 官方文件 Content collections 中,也明確指出這種方式因為有 TypeScript 來輔助型別的檢查,是管理相同架構資料的最佳策略,雖然在初期的設定比 Glob Import 的方式多了一些,但是後續的管理就安全有效的多。
那麼,何謂 Content collections?即是 Astro 用來管理有結構資訊的功能。Collections 是存在專案某目錄下的一群結構化資料,包含 Markdown、MDX、YAML、JSON 等,也可以是外部如資料庫、CMS 等資料源。
要實際使用 Content collections 來建立部落格文章列表,並能從列表連結進入內文,我們需要新增以下資料夾及檔案:
1 | src/ |
首先第一個是 content.config.ts
,在 Astro v5 之前可以統一放到 src/content/
底下,但是新版本的 Astro 則必須在 src/
下直接建立 content.config.ts
(雖然目前有向下兼容的機制)。
這個檔案中需要定義 Collection 的 Loader(必填)及 Schema(選填,但強烈建議使用),內容如下:
1 | import { defineCollection, z } from 'astro:content'; |
我們在透過 glob
這個 Loader 將某目錄下的 mdx
都取出,並定義了這些檔案都有含 title
等資訊的 Schema。
其中 z.
開頭的是 Astro 所使用的 Zod 這個 Library,目的是作為 Schema 的驗證工具,例如在建置階段的 Markdown 中的 Frontmatter 進行驗證(純 TypeScript 僅在編譯階段檢查,在建置時:例如動態讀取檔案後就無法做檢查)。
再來是第二點是 src/pages/blog/[id].astro
,這是產出每篇部落格文章的模板,其中 [id].astro
中的 id
是每個 Collection entry 的唯一值,預設為檔名(以我們的例子就有 first-post
及 second-post
),實際內容如下:
1 | --- |
我們首先需要 Export 一個稱作 getStaticPaths()
的函式,回傳一個包含 params
和 props
的陣列,裡面傳入 id 和 post 內容。
Astro 會使用 getStaticPaths()
來建立每篇文章的靜態路由,由於放置在 src/pages
底下的內容會自動被 Astro 產出 URL,[id].astro
就會是每篇文章的路徑,如 /blog/first-post
。有了 URL 後,再來就是把 post 中的內容透過 render(post)
得到能渲染的資訊就完成了。
如此一來,我們只要在第三點的 src/content/blog
中繼續新增 .mdx
的文章內容,專注在內容的創作本身即可。