skip to content
技術筆記

使用 Astro 建構高效能部落格

從零開始架設技術部落格,Astro 6 + Tailwind CSS v4 + Vercel 完整攻略,附上完整程式碼與主題客製化技巧。

前言

架部落格這件事,選擇比努力重要。一個好的框架能讓你專注在內容上,而不是和工具糾纏。

Astro 就是這樣的存在。它是專為內容驅動網站設計的靜態框架,預設零 JavaScript,效能表現極為優秀。這篇文章用我的實際部落格為範例,帶你從零架設一個完整的技術部落格。

技術棧預覽:

  • Astro 6.0.8 + TypeScript
  • Tailwind CSS v4
  • 程式碼高亮:astro-expressive-code(dracula + github-light 雙主題)
  • 搜尋:Pagefind(純靜態全文搜尋)
  • 留言:Giscus(GitHub Discussions 驅動)
  • 部署:Vercel

初始化專案

Terminal window
# 建立新專案
npm create astro@latest
# 選擇範本(這裡用 Empty)
# 啟用 TypeScript / 安裝依賴 / 初始化 git
cd your-project
pnpm add astro @astrojs/check @astrojs/mdx @astrojs/rss @astrojs/sitemap
pnpm add -D @biomejs/biome @tailwindcss/typography

本部落格使用 Cactus 主題 為基底修改而來。


目錄結構

src/
├── assets/ # 圖片等靜態資源
├── components/ # Astro 元件
├── content/
│ ├── post/ # 文章(Markdown/MDX)
│ ├── note/ # 短筆記
│ └── tag/ # 分類標籤
├── data/ # 資料檔案
├── layouts/ # 頁面佈局
├── pages/ # 路由頁面
├── plugins/ # Vite 插件
├── styles/ # 全域樣式
├── types.ts # TypeScript 類型
├── utils.ts # 工具函式
└── content.config.ts # Content Layer 配置

Content Layer 設定

Astro 6 引入全新的 Content Layer API,用法更直覺:

src/content.config.ts
import { defineCollection } from "astro:content";
import { glob } from "astro/loaders";
import { z } from "astro/zod";
const post = defineCollection({
loader: glob({ base: "./src/content/post", pattern: "**/*.{md,mdx}" }),
schema: ({ image }) =>
z.object({
title: z.string().max(60),
description: z.string(),
coverImage: z.object({ alt: z.string(), src: image() }).optional(),
draft: z.boolean().default(false),
ogImage: z.string().optional(),
tags: z.array(z.string()).default([]),
publishDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
pinned: z.boolean().default(false),
}),
});
export const collections = { post };

Tailwind CSS v4 設定

Astro 6 配合 Tailwind CSS v4,設定方式大幅簡化:

Terminal window
pnpm add @tailwindcss/vite tailwindcss
astro.config.mjs
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
vite: {
plugins: [tailwindcss()],
},
});

src/styles/global.css 中直接使用 @theme 覆寫預設值:

@tailwind base;
@tailwind components;
@tailwind utilities;
@theme {
/* 主題色 */
--color-primary: #2a9d8f;
--color-primary-hover: #21867a;
--color-accent: #8338ec;
/* 字體 */
--font-sans: "Noto Sans TC", system-ui, sans-serif;
--font-mono: "Fira Code", monospace;
}

程式碼高亮:astro-expressive-code

語法高亮是技術部落格的靈魂,astro-expressive-code 是目前最優雅的方案:

Terminal window
pnpm add astro-expressive-code
astro.config.mjs
import expressiveCode from "astro-expressive-code";
export default defineConfig({
integrations: [
expressiveCode({
themes: ["dracula", "github-light"],
styleOverrides: {
borderRadius: "4px",
codeFontFamily: "Fira Code, monospace",
codeFontSize: "0.875rem",
frames: {
frameBoxShadowCssValue: "none",
inlineButtonBackground: "#2a9d8f",
inlineButtonForeground: "#ffffff",
},
},
}),
],
});

支援:

  • 標題檔名
  • 複製按鈕
  • 程式碼行高亮
  • 雙主題切換(淺色/深色)

搜尋功能:Pagefind

Pagefind 是一個純靜態的全文搜尋方案,不需要後端:

Terminal window
pnpm add -D pagefind

package.json 加入 postbuild 指令:

{
"scripts": {
"postbuild": "pagefind --site dist"
}
}

在搜尋頁面注入 Pagefind UI:

<div id="search" data-pagefind-body></div>
<link href="/pagefind/pagefind-ui.css" rel="stylesheet" />
<script src="/pagefind/pagefind-ui.js" is:inline></script>

OG Image 生成

社群分享的視覺效果很重要。使用 Satori 在建置時自動生成 OG 圖:

Terminal window
pnpm add satori satori-html @resvg/resvg-js
src/pages/og-image/[...slug].png.ts
import { ImageResponse } from "astro-og";
import satori from "satori";
import satoriHtml from "satori-html";
export async function GET({ props }: { props: { title: string } }) {
const font = await fetch(
"https://cdn.jsdelivr.net/font-fira-code@2/FiraCode-Regular.ttf"
).then((r) => r.arrayBuffer());
const html = satoriHtml(`
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; width: 100%; height: 100%; background: linear-gradient(135deg, #2a9d8f 0%, #8338ec 100%); padding: 40px;">
<h1 style="color: white; font-size: 48px; font-weight: bold; text-align: center;">${props.title}</h1>
</div>
`);
return new ImageResponse(satori(html, { fonts: [{ name: "Fira Code", data: font }] }), {
width: 1200,
height: 630,
});
}

Vercel 部署

Vercel 是 Astro 最順暢的部署選擇,支援 SSR 和靜態部署:

1. 安裝 Vercel CLI

Terminal window
pnpm add -g vercel

2. 建立 vercel.json

{
"buildCommand": "pnpm build",
"outputDirectory": "dist"
}

3. 部署

Terminal window
vercel --prod

自訂網域與 HTTPS

在 Vercel Dashboard 的 Domains 設定,自動附帶 SSL 憑證。


SEO 優化

Sitemap

Terminal window
pnpm add @astrojs/sitemap
astro.config.mjs
import sitemap from "@astrojs/sitemap";
export default defineConfig({
site: "https://your-blog.vercel.app",
integrations: [sitemap()],
});

robots.txt

Terminal window
pnpm add astro-robots-txt
import robotsTxt from "astro-robots-txt";
export default defineConfig({
integrations: [robotsTxt()],
});

自訂 Remark Plugin

技術文章常用 Callout、程式碼卡片等增強語法。寫一個簡單的 remark directive:

src/plugins/remark-admonitions.ts
import { visit } from "unist-util-visit";
export function remarkAdmonitions() {
return (tree) => {
visit(tree, "containerDirective", (node) => {
const data = node.data || (node.data = {});
data.hName = `div`;
data.hProperties = {
class: `admonition admonition-${node.name}`,
};
});
};
}

深色模式

Astro 配合 View Transitions 實現無閃爍的深色模式切換:

<script>
const theme = localStorage.getItem("theme");
if (theme === "dark" || (!theme && window.matchMedia("(prefers-color-scheme: dark)").matches)) {
document.documentElement.dataset.theme = "dark";
}
</script>

CSS 中使用 data-theme 屬性區分:

[data-theme="dark"] {
--bg: #282c35;
--text: #abb2bf;
}

效能監控

使用 Lighthouse 檢測分數,目標:全部 100。

常見優化:

  • 圖片使用 loading="lazy" + decoding="async"
  • 字體使用 font-display: swap
  • 靜態資源預測性載入
  • CSS 壓縮(cssnano)

結語

Astro 生態系已經非常成熟,現在架設技術部落格比以前容易太多了。從初始專案到完整上線,大概只需要一個下午的時間。

重點不是工具,而是開始寫。🎉


相關資源:

Share
已複製!