iT邦幫忙

2026 iThome 鐵人賽

DAY 17
0
Modern Web

用 Astro 打造 Content-first 前端網站:30 天從靜態內容到會員、資料庫與選型(3rd)系列 第 17

把前面學的拼成網站,Astro 專案骨架該先放什麼?

  • 分享至 

  • xImage
  •  

先補讀者路徑,再補元件。Astro 專案骨架至少要讓讀者知道網站在做什麼、從哪開始、怎麼找到內容,以及走到不存在的網址時怎麼回來。nav、hero、cards、404、footer 都要服務這條路徑。

這個 capstone 已經有 19 篇文章、搜尋、分頁、文章頁,以及 Actions、Auth、購物車等 demo;首頁卻仍是一條文章清單,header 只有站名,footer 還停在「最小可展示版」,也沒有自訂 404。讀者看得到內容,卻看不出這些頁面如何組成同一個網站。

先畫讀者怎麼走,再決定要拆哪些元件

先把既有 route 接成一條走得完的路:

首頁
├─ 依序閱讀 → /blog/page/1 → 文章 → 回文章列表
├─ 搜尋主題 → /blog → 篩選 → 文章
└─ 無效網址 → /404 → 首頁或搜尋

首頁先說明系列在做什麼,再把讀者導向兩種閱讀方式。Day 16:分頁與轉址建立的 /blog/page/1 適合從頭依序看;Day 14:文章搜尋 island建立的 /blog 適合已經知道關鍵字的人。文章頁的返回連結改指向分頁列表,避免把「回文章列表」連到已經改成入口的首頁。

404 也要接回這條路徑。頁面只寫「找不到」,讀者停在原地;補上首頁與搜尋兩個連結,人才走得回內容。

共用外框和首頁內容不要混在一起

Day 4:Layout 與 Slot建立的 BaseLayout.astro 負責完整 HTML、SEO 中繼資料與 <slot />。這些責任留在 layout,header 與 footer 這兩塊跨頁共用區域則拆成元件:

---
import SiteFooter from '../components/SiteFooter.astro';
import SiteHeader from '../components/SiteHeader.astro';

interface Props {
  title: string;
  description?: string;
  wide?: boolean;
}

const { wide = false } = Astro.props;
---

<body>
  <SiteHeader />
  <main class:list={{ 'site-main': true, 'site-main--wide': wide }}>
    <slot />
  </main>
  <SiteFooter />
</body>

SiteHeaderSiteFooter 每一頁都會出現,屬於共用外框;hero、能力卡與最近文章只屬於首頁,留在 index.astro 組合。元件邊界照責任切:跨頁外框放 layout,該頁內容留給 page,card 只有重複呈現時才拆成元件。

wide 採 opt-in。文章與一般頁預設使用 48rem 閱讀寬度,只有首頁打開 74rem 展示寬度。讓全站 main 一起拉寬,首頁三欄 cards 是好排了,每篇文章的行長也跟著失控。

首頁 cards 仍然是 build-time HTML

首頁已經能用 getCollection() 取得全部非草稿文章,不需要為 cards 建另一套資料來源:

---
const posts = await getCollection('blog', ({ data }) => !data.draft);
const latestPosts = posts
  .toSorted(
    (a, b) =>
      b.data.pubDate.valueOf() - a.data.pubDate.valueOf() ||
      b.data.day - a.data.day,
  )
  .slice(0, 6);
---

<HomeHero publishedCount={posts.length} />

{
  latestPosts.map((post) => (
    <ArticleCard
      href={`/blog/${post.id}`}
      day={post.data.day}
      title={post.data.title}
      description={post.data.description}
      tags={post.data.tags}
    />
  ))
}

同一份 collection 資料同時提供 hero 的完成篇數與最近 6 篇 cards。Day 10:Content Collections建立的 schema 統一規範內容欄位;ArticleCard.astro 只接顯示所需欄位,不接整包 entry。

這些 cards 輸出普通 <article><a>。排序與 HTML 生成都在 build 時完成;搜尋頁的即時篩選才需要 Vue island 和 client state。把靜態 card 改成 Vue,只會多送一份瀏覽器 JavaScript。

實際 build 後,首頁 HTML 找不到 <astro-island>。nav、hero、能力卡、文章 cards 與 footer 都是零 hydration 的靜態頁。

沒有作品資料,就不要先捏造作品系統

課程把這一段稱為 Portfolio Project,但目前 repo 沒有 project collection,也沒有作品縮圖。為了湊三張卡就新增資料模型、圖片 pipeline 與假作品,只會提早帶進資料與圖片問題。

首頁呈現三條可以查證的 capstone 能力線:

能力線 已存在的成果 Card 指向
Content system collection、文章 route、搜尋、分頁 Content Collections 文章
Interactive islands Vue 搜尋、表單與登入狀態 搜尋 island 文章
Server & data Actions、Turso、middleware、Better Auth Auth 策略文章

這三張「作品卡」帶讀者進入同一個 capstone 的三個切面,不把它們包裝成三個外部專案。Day 24:Better Auth 驗證策略等文章提供實作脈絡;theme toggle、正式部署與圖片策略仍留在各自的 Day。

另一種順序可以在一個上線中的多語系品牌官網看到。它已經有 /blog route,blog.scssblog-post.scss 也寫好了 .blog-list.blog-post.date 這些規則;文章資料尚未進來,沒有 Content Collection,也沒有任何 Markdown。

於是 blog 頁面的實作是把首頁複製一份改名:同樣兩張硬編碼的圖、同樣的背景、幾乎相同的 scoped 樣式,元件裡只多一行 console.log('Blog')。那兩份寫好的樣式檔沒有被任何地方 import,留在專案裡不會生效。

這個順序在當時有其理由:route 和樣式不依賴內容,可以先開;文章正本要等編輯流程或 CMS 決定。這個殼卻容易被當成「已經做好」;讀者打開 /blog,看到的仍是首頁。

內容站先替內容建立正本與 schema(Day 10Day 13 那條線),再讓 route 從資料長出來。內容還沒準備好時,先不要開那條 route,避免它指向不屬於自己的內容。

自訂 404 回答的是「接下來去哪」

把自訂 404 放在 src/pages/404.astro,靜態 build 會產生 404.html,多數部署服務會自動使用。頁面仍套用 BaseLayout,導覽、SEO 基礎與 footer 不會因為錯誤路徑消失:

---
import BaseLayout from '../layouts/BaseLayout.astro';

export const prerender = true;
---

<BaseLayout title="找不到這一頁">
  <h1>這條路徑沒有內容,但閱讀路徑還在。</h1>
  <a href="/">回到首頁</a>
  <a href="/blog">搜尋文章</a>
</BaseLayout>

Day 17 首頁桌面版,hero 下方依序呈現三張能力卡與最近文章

兩個出口就夠。改成列出錯誤代碼或 router 技術細節,讀者還是回不到內容。

響應式要跟著螢幕寬度重排

首頁展示區在寬螢幕使用三欄,中等寬度改兩欄,窄螢幕回到單欄。nav 也改成上下排列,連結列可以水平捲動,避免站名和三個入口互相擠壓。

Day 17 首頁窄螢幕版,導覽、進度卡與內容卡都改為單欄排列

樣式責任沿用 Day 6:scoped 與 global CSS的分法:顏色、寬度、間距 token 與 focus 樣式放全域;hero、nav、card 的外觀留在各自元件的 scoped <style>。調整單一 card 不會碰到文章排版;全站 token 的變更則同步影響所有頁面。

驗收骨架,看路徑和邊界

以下以 Node 24.16.0、Astro 7.1.1 於 2026-07-24 驗證:

  • npm run build 通過,產出首頁、20 篇文章、4 個分頁與 /404.html
  • 首頁產出不含 <astro-island>,新增骨架沒有增加 hydration。
  • //blog/blog/page/1、文章頁與 /404 都保有同一組主要導覽。
  • 桌面與窄螢幕下,hero、能力卡、文章 cards 和 nav 都能重排,沒有水平溢出。

Astro layout 與 <slot /> 的現行寫法可查 Layouts 官方文件,自訂 404 規則見 Astro Pages 官方文件,內容查詢則見 Content Collections 官方文件

首頁、nav、404 與 footer 現在指向同一組閱讀路徑,既有內容、互動與 server 功能也收進同一個入口。Day 18 接著處理圖片最佳化與媒體策略。

本日程式碼:step-17|只看這天的改動:step-16...step-17


上一篇
文章一多就要分頁與轉址,Astro 怎麼一次處理好?
下一篇
圖片只用原生 img 夠嗎?Astro Image/Picture 處理了什麼?
系列文
用 Astro 打造 Content-first 前端網站:30 天從靜態內容到會員、資料庫與選型(3rd)21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言