内部链接
- [[技术折腾 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,后续无论我是使用何种渲染环境,都可以使用这个方法。