跳至主要内容

【Docusaurus】如何自動顯示 Docusaurus 文章列表

雖然 Docusaurus 有 Sidebar 可以很清楚地找到你要的文章,但我希望可以在首頁看到最新更新的文章列表,不過在 Docusaurus 沒有內建的功能或 API 可以顯示所有的文章,所以需要自己做一個自動爬蟲的 component。

想法概念

在找有沒有官方提供的 API 達到我要的功能時,有看到一個 useDocsSidebar() 的函式可以抓出 sidebar 的清單,決定從這裡下手。再利用裡面提供的各頁面的 url 去抓網頁的 HTML,篩選出我要的資料。

步驟大概是這樣:

  1. useDocsSidebar() 抓出所有頁面的 url 陣列。
  2. Promise.all() 同時 fetch 所有的靜態頁面文字檔。
  3. 使用原生 DOMParser() 轉成 HTML 格式,並抓取資料。
  4. 最後把 component 引入 mdx 檔。

Step1: useDocsSidebar()

先建一個 component 叫 DocList,使用 useDocsSidebar() 取出裡面的 items

import { useDocsSidebar } from "@docusaurus/theme-common/internal";

function DocList() {
const { items } = useDocsSidebar();
...
}

取出來後會長這樣



就是你的 Sidebar 的資料結構,這邊如果有很多層的話需要一層一層拆掉,可以用 lodash 的 flatMapDeep 解構。或是像我一樣不想裝套件,用 flatMap 加遞迴的方式拆開。

function formatDocList(items) {
return items.flatMap((item) => {
if (!item.items) {
return {
title: item.label,
id: item.docId,
href: item.href,
};
} else {
return formatDocList(item.items);
}
});
}

Step2: Promise.all()

整理完後,再抓出一個只有 href 的陣列,然後再用 Promise.all() 同時發出請求。

async function fetchDocs(docsList) {
const docUrlList = docsList.map(
(doc) => `https://jim876633.github.io${doc.href}`
);

const results = await Promise.all(
docUrlList.map((url) => fetch(url).then((res) => res.text()))
);
}

回傳的 result 就是含有所有頁面 HTML 文字的陣列。

Step3: DOMParser();

因為抓回來的是文字,比較難去取得想要的資訊,所以這邊用原生的 DOMParser() 去將文字轉成 HTML。

results.forEach((data, i) => {
// translate to html
const parser = new DOMParser();
const html = parser.parseFromString(data, "text/html");
const body = html.body;
});

抓到 body 的 DOM 後,就要來抓我要的更新日期,這邊要先在 docusaurus.config.js 設定 showLastUpdateTime,詳細資訊可以參考官網,這邊就不多贅述。

放更新日期的 HTML tag 是一個 <time>...<time/> 的結構,它有一個 datetime 的 Attribute,裡面放的就是我要的日期格式。



再來的就只是把它取出來,然後合併到之前整理過的物件裡。

const timeStamp = time.getAttribute("datetime");
docs[i].timeStamp = new Date(timeStamp).getTime();

Step4: import component

最後拿到有日期的物件陣列,再用 sort 去依據日期排序,然後再 import 到 .mdx 檔(記得把 .md 轉成 .mdx 才能引入)。

intro.mdx
import DocList from "@site/src/components/docList.jsx";

<DocList />;

就可以在首頁看到最新更新的文章列表了 🎉



額外補充

不過因為是用 component 引入,所以只要進入到首頁就會 fetch 所有文章的資料,這樣效能並不是很好,想優化效能的可以使用 TanStack Query 來管理 API 請求,有興趣的可以看我完整的程式碼。