npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue3-ref-kv-cache

v0.1.0

Published

A Vue 3 key-value cache utility with reactive bindings, TTL, persistence, and request deduplication.

Readme

vue3-ref-kv-cache

一个面向 Vue 3 的响应式键值缓存工具库,适合把异步请求结果缓存成可复用的 ref 状态,并支持:

  • 同 key 并发请求去重
  • TTL 过期控制
  • localStorage 持久化
  • use() 组合式调用
  • get() / refresh() / peek() / remove() / clear() / cleanExpired()

这个仓库用于源码开发、测试和本地调试;npm 包发布时只包含构建产物和必要说明文件,不包含 srcdemotests 等开发目录。

安装

npm install vue3-ref-kv-cache vue

要求:

  • Vue 版本:^3.3.0
  • 包格式:同时提供 ESM、CJS 和 TypeScript 类型声明

快速开始

import { createKvCache } from 'vue3-ref-kv-cache';

interface User {
  id: number;
  name: string;
}

const userCache = createKvCache<User, { userId: number }>({
  ttl: 5_000,
  query: async ({ userId }) => {
    const response = await fetch(`/api/users/${userId}`);
    if (!response.ok) {
      throw new Error('获取用户信息失败');
    }

    return response.json();
  },
});

const userState = userCache.use({ userId: 1 });

console.log(userState.loading.value);
console.log(userState.status.value);
console.log(userState.data.value);
console.log(userState.error.value);

在 Vue 组件里可以直接使用:

<script setup lang="ts">
import { createKvCache } from 'vue3-ref-kv-cache';

interface User {
  id: number;
  name: string;
}

const userCache = createKvCache<User, { userId: number }>({
  ttl: 10_000,
  query: async ({ userId }) => {
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
  },
});

const user = userCache.use({ userId: 1 });
</script>

<template>
  <div v-if="user.loading.value">加载中...</div>
  <div v-else-if="user.error.value">请求失败</div>
  <pre v-else>{{ user.data.value }}</pre>
</template>

持久化缓存

const articleCache = createKvCache({
  ttl: 60_000,
  persist: true,
  storageKey: 'article-cache',
  query: async ({ slug }: { slug: string }) => {
    const response = await fetch(`/api/articles/${slug}`);
    if (!response.ok) {
      throw new Error('获取文章失败');
    }

    return response.json();
  },
});

说明:

  • 只有成功请求到的数据会写入 localStorage
  • 持久化内容会在新实例创建时自动恢复
  • 已过期数据会在恢复阶段自动清理
  • 在不支持 localStorage 的环境中会自动降级,不会阻塞库本身运行

自定义缓存 key

默认情况下,库会对参数做稳定序列化,所以这两次调用会命中同一个缓存:

cache.get({ userId: 1, tab: 'profile' });
cache.get({ tab: 'profile', userId: 1 });

如果你的参数里包含不适合序列化的内容,或者你想自己控制 key,可以传入 getKey

const cache = createKvCache({
  getKey: (params: { userId: number }) => `user:${params.userId}`,
  query: async ({ userId }) => {
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
  },
});

建议:

  • 参数尽量使用普通对象、数组、字符串、数字等稳定结构
  • 如果参数里存在循环引用,请务必自己传 getKey

API

createKvCache<TData, TParams>(options)

import type { KvCacheController } from 'vue3-ref-kv-cache';

function createKvCache<TData, TParams>(
  options: CreateKvCacheOptions<TData, TParams>,
): KvCacheController<TData, TParams>;

options

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | query | (params: TParams) => Promise<TData> | 必填 | 实际请求函数 | | ttl | number | 0 | 缓存有效期,单位毫秒;0 表示不过期 | | persist | boolean | false | 是否启用 localStorage 持久化 | | storageKey | string | vue3-ref-kv-cache | 持久化存储 key | | getKey | (params: TParams) => string | 内置稳定序列化 | 自定义缓存 key 生成逻辑 |

返回值

返回一个缓存控制器对象:

  • use(params)
  • get(params)
  • refresh(params)
  • peek(params)
  • remove(params)
  • clear()
  • cleanExpired()

use(params)

立即返回响应式状态,并在有需要时自动触发请求。

const state = cache.use({ id: 1 });

返回结构:

{
  data: Ref<TData | undefined>;
  loading: Ref<boolean>;
  error: Ref<unknown>;
  status: Ref<'idle' | 'loading' | 'success' | 'error'>;
  refresh: () => Promise<TData>;
  remove: () => void;
}

说明:

  • 首次调用时会自动请求
  • 如果同一个 key 已有进行中的请求,会复用该请求
  • 如果缓存仍有效,会直接复用缓存值
  • refresh() 会忽略当前缓存并强制重新请求

get(params)

获取缓存值;如果缓存不存在或已过期,则发起请求并返回结果。

const data = await cache.get({ id: 1 });

适合:

  • 组合式函数外部使用
  • 需要直接拿到 Promise 结果的场景
  • 服务方法、事件处理器、手动预加载场景

refresh(params)

忽略当前缓存,强制重新请求并更新缓存。

await cache.refresh({ id: 1 });

peek(params)

只读取当前缓存快照,不会触发请求。

const snapshot = cache.peek({ id: 1 });

返回结构:

{
  key: string;
  data: TData | undefined;
  error: unknown;
  status: 'idle' | 'loading' | 'success' | 'error';
  loading: boolean;
  expireAt: number;
  updatedAt: number;
  isExpired: boolean;
}

适合:

  • 调试和排查缓存状态
  • 在不希望触发请求时读取当前缓存
  • 做一些额外的 UI 展示或日志记录

remove(params)

删除指定 key 的缓存。

cache.remove({ id: 1 });

clear()

清空当前缓存实例下的所有缓存。

cache.clear();

cleanExpired()

清理当前实例中已经过期的缓存项。

cache.cleanExpired();

缓存行为说明

1. 同 key 并发去重

同一个 key 在请求进行中时,后续 get() / use() / refresh() 会复用当前 Promise,不会重复请求。

2. 过期策略

  • ttl = 0:永不过期
  • ttl > 0:请求成功时记录过期时间,超过后下一次读取会重新请求

3. 错误处理

  • 请求失败后,status 会变为 error
  • 失败不会被当作成功结果缓存
  • 同一个 key 后续再次调用时会重新请求

4. 持久化策略

  • 只持久化成功数据
  • 不持久化 loading 这类运行时状态
  • 已过期或非法数据会在恢复时自动清理

本地调试

仓库内置了一个 Vite 示例页,专门用于调试缓存行为。

启动方式:

pnpm install
pnpm dev

示例页可调试的内容包括:

  • use() / get() / refresh() / peek()
  • TTL 过期行为
  • localStorage 持久化恢复
  • 模拟接口延迟
  • 模拟下一次请求失败
  • remove() / clear() / cleanExpired()

调试页面源码位于仓库中的 demo/App.vue

开发与测试

pnpm build
pnpm test
pnpm typecheck
pnpm pack:check

说明:

  • build:使用 tsup 生成 dist
  • test:运行 vitest
  • typecheck:运行 vue-tsc
  • pack:check:使用 npm pack --dry-run 检查最终发包内容

发布说明

当前发布策略是“仓库里保留源码开发,npm 只发构建结果”。

最终 npm 包只包含:

  • dist
  • README.md
  • LICENSE
  • npm 自动带入的 package.json

不会包含:

  • src
  • demo
  • tests
  • vite.config.ts
  • tsup.config.ts
  • 其他开发配置文件

建议发布前执行:

pnpm build
pnpm test
pnpm typecheck
pnpm pack:check
npm publish

License

MIT