【开源项目】更新一波去年的开源项目,加个小功能点,顺便补充playwright测试样例

787 阅读5分钟

我正在参加「掘金·启航计划」

前情提要

在去年九月份的时候,赋闲在家,为了更好地把自己推销出去,就整了个开源项目——proxy-web-storage,在掘金发过介绍文章——【开源项目】看了vue的源码,我用proxy实现了更强大的storage,也上过阮老师的周刊推荐,目前收获了200+stars。在此,也是感谢阮老师的推荐和各位老哥的支持,也欢迎各位尝试使用和提出建议。

stokado

ok,再次介绍一下 proxy-web-storage,以及此次更新内容。

首先,proxy-web-storage 改名为 stokado(/stəˈkɑːdoʊ/),以下正式用 stokado 称呼。stokadostorage 的世界语(一种国际辅助语言)。世界语的理念跟我开源 stokado 的想法是一致的,成为 web storage 的辅助,帮助前端朋友们更好地更方便地去管理 web storage

1. 语法糖

从之前的名字 proxy-web-storage 可以看出,这个项目主要是借助 proxy ,拦截了对 localStoragesessionStorage 的访问,实现各种类型数据的序列化和反序列化。支持的类型有常见的基本类型,包括 bigint 类型、number 类型的几个特殊值—— NaNInfinity-Infinity,还支持Array 类型, Date 类型,RegExp 类型,Function 类型,Set 类型,Map 类型。嗯,不支持 symbol

import { local, session } from 'stokado'

// Date
local.test = new Date('2000-01-01T00:00:00.000Z')
local.test.getTime() === 946684800000 // true

// RegExp
local.test = /d(b+)d/g
local.test.test('cdbbdbsbz') // true

// function
local.test = function () {
  return 'hello stokado!'
}
local.test() === 'hello stokado!' // true

实现的方式主要是把数据的类型和序列化后的值存进真正的 storage 里,后续的功能也是基于这个数据类型进行开发,类型如下:

interface TargetObject {
  type: string
  value: string | object
  options?: StorageOptions
}

详细也可以看下之前的文章或者点进github查看测试样例了解更多用法,顺便再点个 star 嘿嘿,来都来了。

2. 监听订阅

这个就没啥好说的,熟悉 vue 的同学应该都会手搓一套简单的发布订阅模式吧。不然也可以看看 mitttiny-emitter 等开源库的实现方式,基本上大同小异。

onoff,以及 once 三个方法,分别是订阅,取消订阅和只触发一次订阅。

import { local } from 'stokado'

local.on('test', (newVal, oldVal) => {
  console.log('test', newVal, oldVal)
})
local.on('test.a', (newVal, oldVal) => {
  console.log('test.a', newVal, oldVal)
})

local.test = {}
// test {} undefined

local.test.a = 1
// test.a 1 undefined

从上面的例子也可以看到,stokado 对于 ObjectArray 类型的数据,支持二级监听。obj.a for Object and list[0] for Array, 还有 list.length 的监听。没有对三级以上的数据进行监听处理,如果后续有同学需要这方面的功能,再看看要不要整上吧。或者你有兴趣的话,也欢迎你加入,一起搞事情。

3. 设置过期

stokado 提供了 setExpiresgetExpiresremoveExpires 三个方法对指定项设置过期时间,获取它的过期时间和移除它的过期设置。

需要注意的是,当传入的时间值小于当前时间,则直接删除指定项。

import { local } from 'stokado'

local.test = 'hello stokado'
local.setExpires('test', Date.now() + 10000)

// within 10's
local.test // 'hello stokado'

// after 10's
local.test // undefined

上面的例子有一个很不友好的地方,设置一个过期时间需要先存储值。我原来构想的是,对已经存在的值进行操作,但如果是新值呢?

这也是此次更新内容之一,setItem 支持 options 配置。

local.setItem('test', 'hello stokado', { expires: Date.now() + 10000 })

4. 一次性取值

这就是标题所说的新增功能点,痛点来自于有时候用 localStorage 作为页面之间跳转的数据传输,在跳转取值后,要把存储值移除掉,如此的重复操作,当然是写进 stokado 省事啦。

只有 setDisposable 一个方法,就是设置指定项只能获取一次值。

import { local } from 'stokado'

local.setItem('test', 'hello stokado', { disposable: true })
// local.test = 'hello stokado'
// local.setDisposable('test')

local.test // 'hello stokado'
local.test // undefined

setExpires 一样,setItem 也支持配置,用 disposable 字段。

playwright测试

其实之前是用 jest 写了几个测试样例,主要是语法糖方面,其他功能点没写,是因为 localStorage 在不同页面修改存储,会触发 storageEvent 事件,而 jest 没办法模拟这个事件。所以,如果想对所有功能点加上测试样例的话,就要借助 headless browser。比较有名的工具有 playwrightpuppeteer,前者是微软出品,后者是谷歌。从标题可以知道,我选了 playwright。原因如下:

// playwright
test('basic test', async ({ context }) => {
  const page1 = await context.newPage();
  const page2 = await context.newPage();

  await page1.goto('https://juejin.cn/');
  await page2.goto('https://juejin.cn/');

  await page2.evaluate(() => {
    window.addEventListener('storage', (ev) => {
      console.log(ev.newValue, ev.oldValue); // hello world! null
    })
  });

  await page1.evaluate(() => {
    window.localStorage.setItem('test', 'hello world!');
  });
});
// puppeteer
(async () => {
  const browser = await puppeteer.launch();

  const page1 = await browser.newPage();
  const page2 = await browser.newPage();

  await page1.goto('https://juejin.cn/');
  await page2.goto('https://juejin.cn/');

  await page2.evaluate(() => {
    window.addEventListener('storage', (ev) => {
      console.log(ev.newValue, ev.oldValue); // hello world! undefined
    })
  });

  await page1.evaluate(() => {
    window.localStorage.setItem('test', 'hello world!');
  });

  await browser.close();
})();

其实两者的用法差不多,区别在于它们各自触发 storageEvent 时的 oldValue 不相同,playwrightnullpuppeteer 则是 undefined,而浏览器的表现为 null。并且 playwright 集成了test相关的断言等函数,还支持Chromium,Firefox,WebKit等不同内核(虽然我只用了Chromium)。

结语

对这次 1.1.0 更新做个总结:

  1. 正式更名为 stokadonpm也同步更新了。
  2. setItem 支持 options 配置,目前支持字段有 expiresdisposable
  3. 新增功能点:一次性取值。
  4. 增加 playwright 测试样例,补充监听订阅、设置过期、一次性取值等功能以及 localStoragesessionStorage 混合使用的相关测试。

其实还想再讲一下关于做开源的感想,但是瞅着这时间快年中总结了,到时候再一起抒发心中所思所想。

最后,感谢各位小伙伴看完,如果有操作 storage 的需求,不妨试试 stokado。不试也没关系,点个 star 再走呗。