【Docusaurus】如何自動顯示 Docusaurus 文章列表
雖然 Docusaurus 有 Sidebar 可以很清楚地找到你要的文章,但我希望可以在首頁看到最新更新的文章列表,不過在 Docusaurus 沒有內建的功能或 API 可以顯示所有的文章,所以需要自己做一個自動爬蟲的 component。
想法概念
在找有沒有官方提供的 API 達到我要的功能時,有看到一個 useDocsSidebar()
的函式可以抓出 sidebar 的清單,決定從這裡下手。再利用裡面提供的各頁面的 url 去抓網頁的 HTML,篩選出我要的資料。
步驟大概是這樣:
- 用
useDocsSidebar()
抓出所有頁面的 url 陣列。 - 用
Promise.all()
同時 fetch 所有的靜態頁面文字檔。 - 使用原生
DOMParser()
轉成 HTML 格式,並抓取資料。 - 最後把 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 才能引入)。
import DocList from "@site/src/components/docList.jsx";
<DocList />;
就可以在首頁看到最新更新的文章列表了 🎉
額外補充
不過因為是用 component 引入,所以只要進入到首頁就會 fetch 所有文章的資料,這樣效能並不是很好,想優化效能的可以使用 TanStack Query 來管理 API 請求,有興趣的可以看我完整的程式碼。