辛宝Otto

辛宝Otto 的玄酒清谈

北漂前端程序员儿 / 探索新事物 / Web Worker 主播之一/内向话痨
xiaoyuzhou
email

【Technical Perspective Tinkering xLog】A smoother user experience with 4 using unStorage to encapsulate xLogDriver.

image.png

Related

  • [[unjs_unstorage]]

Background

Continuing from the previous three articles, we believe that xlog's ambition should not be limited to the current web-based blog. It should be a better headlessCMS. In order to publish articles more smoothly, we developed the "sync-to-xlog" plugin to make the synchronization process easier.

If we continue to explore, can I use Nuxt to create my own blog with xlog? Following this idea, I realized that the current solution for accessing xlog can be simplified using "unjs/unstorage" and also add some challenges.

A brief introduction to unstorage, it can be understood as a universal plugin that provides a unified interface. By using different driver adapters, it can smooth out the differences in details.

The usage is actually very simple, similar to using 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

Technical Design

It doesn't seem complicated.

First, customize the xLogDriver.

Implement the corresponding APIs:

  • Define getItem('site')
  • Define getKeys() - returns a list
  • Define getItem('slugOrID')
const storage = createStorage({
  driver: xLogStorageDriver({
    token: "", // optional
    charactorID: "", // required
  }),
});

// console.log("list", list);

const list = await storage.getKesy();
console.log("list", list);

Code Implementation

It seems not difficult, I will implement it later. I will update here if there is any progress.

This time we won't use the RESTful API request, we will use the crossbell.js SDK to complete all operations.

I actually wrote it, but it didn't feel right, mainly because the return value of getKeys can only be string[], so I gave up. I'll come back to it after a few major versions.

It seems that implementing only getItems is also possible?

After hesitating for a while, I still implemented it. The source code is open source here: https://github.com/Otto-J/unstorage-xlog-driver

You can use it like this:

/* 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();

Pitfall Experience

Not all APIs need to be implemented

At first, I didn't have a clear understanding of unstorage. I thought all functions needed to be implemented, but later I found that only a few main methods need to be implemented.

What is the appropriate return value for getKeys?

getKeys must return string[]. Through practice, I found that it is better to return ${noteID}.md here, because it can be configured like this in the nuxt-content module, generating virtual files that are similar to local files, making it more consistent.

export default defineNuxtConfig({
  content: {
    sources: {
       driver: path.resolve(
          __dirname,
          "node_modules/unstorage-xlog-driver/dist/index.mjs",
        ),
        characterId: 53709,
        prefix: "/blogs",
    }
  }
})

With this magical sources configuration, remote data can be pulled to the local .nuxt/content-cache/parsed/xLog/blogs directory, and you can see these theoretically virtual files.

I have a good screenshot here, but after thinking about it, I decided not to include it. It's just a bunch of garbled characters and not aesthetically pleasing.

How to design getItem properly

getItem('72.md') only returns the markdown plain text. In this way, I lose some information, such as slug/update_time, etc.

I came up with a solution that suits me well, which is to intercept the plain text, put the information I want to fill in the frontmatter first.

To understand how, please refer to the code here: https://github.com/Otto-J/unstorage-xlog-driver/blob/main/src/index.ts#L124

I first parse the front-matter, merge it with the original markdown, and then return it. This way, the remote data remains unchanged, and I can handle it myself.

The cache that must be added

When I first logged, I was surprised to find that it triggered countless requests, which was very strange. I went to see the implementation of the github-driver and found that I can add my own cache. I maintained an object mapping table to cache the data. Within a certain period of time, I don't need to request the remote data again.

It triggered countless times, like an attack, it's a bit funny and sad.

Using unjs's unbuild template

Originally, I wanted to use tsup to create a pipeline, but then I found that unjs has an unbuild project that provides templates. It comes with vitest/jiti and other things, which is quite convenient to use.

Template address: https://github.com/unjs/template

I also wrote some vitest unit tests.

If I could start over

If I could start over, I wouldn't hesitate so much. I hesitated for two weeks whether to write it or not. I wrote it at first, but then I decided to give up and deleted the code. Although there wasn't much code, once deleted, it's gone. I can only rewrite it, so I still respect my own code. I really don't want to keep it, I can put the code in the blog.

Outlook

So far, we have implemented the unStorage xLogDriver, and no matter what rendering environment I use in the future, I can use this method.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.