內部連結
- [[技術折騰 xLog 1 可行性探索]]
- [[技術折騰 xLog 2 深入理解 xlog 的鑑權]]
- [[技術折騰 xLog 3 實現一個 obsidian 插件]]
- [[技術折騰 xLog 4 使用 unStorage 封裝 xLogDriver]]
- [[速通 - xLog 背後的 CrossBell SDK]]
- [[從官方 XLOG Obsidian 插件中能學到什麼]]
- [[開發 Obsidian Sync To Xlog 插件之 處理 obsidian 的圖片]]
- [[速通 - CrossBell 的開源作品]]
- [[速通 Obsidian Docs - 侧重插件開發]]
關聯
- [[unjs_unstorage]]
背景#
承接前三篇內容,前三篇我們認為 xlog 的雄心應該不滿足目前的網頁版 blog,應該是更好的 headlessCMS ,為了更流暢地發表文章,我們開發了 sync-to-xlog
插件,讓同步過程更輕鬆。
如果繼續展望,要拓展 xlog 的展示場景,我能不能用 nuxt 製作一個自己的 blog?順著這個思路,我意識到,目前獲取 xlog 的方案還可以更簡單,順便給自己增加一點難度,試試 unjs/unstorage
簡單介紹 unstorage ,可以理解一個通用插件,提供統一的接口,使用不同的 driver 適配器,就能磨平細節差異。
用法其實特別簡單,一看就會,和 localstorage 用法一樣
import { createStorage } from "unstorage";
const storage = createStorage(/* opts */);
await storage.getItem("foo:bar");
await storage.hasItem()
// getItem getItems
// getItemRaw
// setItem setItems setItemRaw
// getMeta setMeta removeMeta
// getKeys
技術設計#
看著不複雜。
首先自定義 xLogDriver
。
實現對應 api
- 定義 getItem ('site')
- 定義 getKeys () - 返回 list
- 定義 getItem (‘slugOrID')
const storage = createStorage({
driver: xLogStorageDriver({
token: "", // 可選
charactorID: "", // 必選
}),
});
// console.log("list", list);
const list = await storage.getKesy();
console.log("list", list);
代碼實現#
似乎不難,後面實現。有進展我會更新到這裡。
這一次我們不使用 restful api 請求了,使用 crossbell.js
SDK 來完成所有操作。
實際寫了寫,不舒服,主要是在 getKeys
的返回值只能是 string[]
,放棄了。等到幾個大版本再回來看吧。
好像只實現 getItems 也可以?
猶豫了一陣,還是實現了 源碼開源在這裡 https://github.com/Otto-J/unstorage-xlog-driver
你可以這樣使用
/* eslint-disable unicorn/prefer-top-level-await */
import { createStorage } from "unstorage";
import { xLogStorageDriver } from "unstorage-xlog-driver";
const OTTO_ID = 53_709;
async function main() {
const storage = createStorage({
driver: xLogStorageDriver({
characterId: OTTO_ID,
ttl: 60 * 60,
}),
});
// const keys = await storage.getKeys();
// console.log(keys);
const info = await storage.getItem("72.md");
// const info = await storage.getMeta("72.md");
console.log(info);
}
main();
踩坑經驗#
不需要全部實現 api#
一開始我對 unstorage
認識不清,我以為所有的功能都要實現,後來只需要實現幾個主要的方法就行。
getKeys 返回什麼合適?#
getKeys
返回的必須是 string[]
,通過實踐發現,這裡返回 ${noteID}.md
比較好,因為 nuxt-content 模塊裡可以這樣配置,生成虛擬文件,加上 md 和本地文件差不多,更一致。
export default defineNuxtConfig({
content: {
sources: {
driver: path.resolve(
__dirname,
"node_modules/unstorage-xlog-driver/dist/index.mjs",
),
characterId: 53709,
prefix: "/blogs",
}
}
})
有了這個神奇的 sources 配置,可以把遠程的數據拉取到本地 ls .nuxt/content-cache/parsed/xLog/blogs
既可以看到這些理論上的虛擬文件了。
這裡有一張截圖比較好,想了想還是不放了,都是亂碼不美觀。
getItem 怎麼設計比較好#
getItem('72.md')
返回的只有 markdown 純文本。這樣我就丟失了一些信息,比如 slug/update_time 等等。
我想了個比較適合我的方案,那就是攔截純文本,先把想填補的信息放入 frontmatter 裡。
怎麼理解,請看代碼 https://github.com/Otto-J/unstorage-xlog-driver/blob/main/src/index.ts#L124
我先解析 front-matter,和原始 markdown 進行合併再返回。這樣遠程數據不動,自己處理就好。
必須要加的緩存#
我當初打了 log,特別驚訝地發現觸發了無數次請求,特別奇怪,我去看了 github-driver 的實現,才知道可以自己加緩存。自己維護一個 object 映射表,緩存有效內讀取緩存,這樣一段時間內就不用重新請求遠程數據了。
觸發了無數次,有點像攻擊,扶額哭笑。
使用 unjs 的 unbuild 模板#
本來我是想用 tsup 搞一個流水線,後來發現 unjs 有個 unbuild 項目提供了模板。自帶 vitest/jiti 等東西,用起來挺順手的。
模板地址 https://github.com/unjs/template
咱也寫了一把 vitest 單元測試。
如果能重來#
如果能重來,寫的就不會這麼猶豫了,猶豫了兩周要不要寫。本來寫了,後來覺得放棄好了,就把代碼刪除了,雖然沒多少東西,但是刪除了就沒了,只能重新寫,所以還是尊重自己的代碼。真不想留著,把代碼放博客裡也行。
展望#
至此,我們實現了 unstorage 的 xLogDriver,後續無論我是使用何種渲染環境,都可以使用這個方法。