辛宝的玄酒清谈!
1173 words
6 minutes
技术折腾 xLog 4 用 unStorage 封装 xLogDriver
2023-10-20

技术折腾 xLog 4 用 unStorage 封装 xLogDriver

内部链接

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

技术折腾 xLog 4 用 unStorage 封装 xLogDriver
https://ijust.cc/posts/play-xlog-write-a-xlog-unstorage-driver/
Author
辛宝 Otto
Published at
2023-10-20