跳至內容
Fumadocs

部落格

為您的應用程式加入部落格。

安裝

npx @fumadocs/cli@latest add blog

此指令會將元件安裝至 components/blog,並將文章相關的工具函式安裝至 lib/blog.ts。

請使用 blogPageSchema 為您的文章定義一個集合,並註冊作者:

import { defineConfig } from 'astro/config';
import fumadocs from '@fumadocs/astro';

export default defineConfig({
  integrations: [
    fumadocs({
      components: './src/components/mdx.tsx',
      collections: {
        docs: { dir: 'content/docs' },
        blog: { dir: 'content/blog' },
      },
    }),
  ],
});

請將文章撰寫在 content/blog 目錄下:

content/blog/hello-world.mdx
---
title: Hello World
description: My first post.
date: 2026-10-12
tags: [Announcement]
authors: [fuma]
image: /blog/hello-world.png
---
欄位說明
date發布日期,文章會依此排序
tags每個標籤在 /blog/tags 下都有專屬頁面
authors作者的鍵,無法識別的鍵會直接視為作者名稱
image封面圖片 URL,會顯示在文章卡片上

頁面

getPosts() 會解析頁面的作者與標籤,並依日期由新到舊排序。請在首頁版面配置底下的路由中算繪這些頁面。

文章

---
import Layout from '@/layouts/Layout.astro';
import { BlogPosts } from '@/components/blog-posts';
import { blogAuthors, blogSource } from '@/lib/source';
import { getPosts } from '@/lib/blog';
---

<Layout title="Blog">
  <BlogPosts
    client:load
    pathname={Astro.url.pathname}
    params={Astro.params}
    posts={getPosts(blogSource.getPages(), blogAuthors)}
  />
</Layout>

文章

findPost() 會找出指定的文章,以及其前後較新與較舊的文章。若傳入 toc,浮動面板會顯示目錄和分享按鈕。

---
import type { GetStaticPaths, InferGetStaticPropsType } from 'astro';
import Layout from '@/layouts/Layout.astro';
import { BlogPostPage } from '@/components/blog-post';
import { blogAuthors, blogSource } from '@/lib/source';
import { findPost, getPosts } from '@/lib/blog';

export const getStaticPaths = (() => {
  const posts = getPosts(blogSource.getPages(), blogAuthors);

  return blogSource.getPages().map((page) => ({
    params: { slug: decodeURI(page.slugs[0]) },
    props: { page, ...findPost(posts, page.url)! },
  }));
}) satisfies GetStaticPaths;

type Props = InferGetStaticPropsType<typeof getStaticPaths>;

const { page, post, newer, older } = Astro.props;
const { body: Content, toc } = await page.data.load();
---

<Layout title={post.title} description={post.description}>
  <BlogPostPage
    client:load
    pathname={Astro.url.pathname}
    params={Astro.params}
    post={post}
    newer={newer}
    older={older}
    toc={toc}
  >
    <Content />
  </BlogPostPage>
</Layout>

標籤

使用 getTags() 列出所有標籤:

---
import Layout from '@/layouts/Layout.astro';
import { BlogTagsPage } from '@/components/blog-tags';
import { blogSource } from '@/lib/source';
import { getPosts, getTags } from '@/lib/blog';
---

<Layout title="All Tags">
  <BlogTagsPage
    client:load
    pathname={Astro.url.pathname}
    params={Astro.params}
    tags={getTags(getPosts(blogSource.getPages()))}
  />
</Layout>

接著使用 getTagPosts() 取得特定標籤下的文章;若標籤不存在,則會回傳 undefined:

---
import type { GetStaticPaths, InferGetStaticPropsType } from 'astro';
import Layout from '@/layouts/Layout.astro';
import { BlogTagPage } from '@/components/blog-tag';
import { blogAuthors, blogSource } from '@/lib/source';
import { getPosts, getTagPosts, getTags } from '@/lib/blog';

export const getStaticPaths = (() => {
  const posts = getPosts(blogSource.getPages(), blogAuthors);

  return getTags(posts).map((tag) => ({
    params: { tag: tag.slug },
    props: getTagPosts(posts, tag.slug)!,
  }));
}) satisfies GetStaticPaths;

type Props = InferGetStaticPropsType<typeof getStaticPaths>;

const { tag, posts } = Astro.props;
---

<Layout title={tag.name}>
  <BlogTagPage
    client:load
    pathname={Astro.url.pathname}
    params={Astro.params}
    tag={tag}
    posts={posts}
  />
</Layout>

國際化

將某個語系的頁面傳入 getPosts(),例如 blogSource.getPages(lang)。

標籤頁面的 URL 由 lib/blog.ts 中的 getBlogUrl 產生。請將您的 i18n 設定傳給它,使其與載入器的 URL 保持一致:

lib/blog.ts
import { i18n } from '@/lib/i18n';

export const getBlogUrl = createGetUrl('/blog', i18n);

若要為您的文章發布 RSS 摘要,請參閱 RSS 摘要。

How is this guide?

最後更新於