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

@gitlon/version

v0.1.4

Published

Vite 构建版本插件:生成 version.json、注入版本信息并提供客户端缓存刷新能力

Readme

@gitlon/version

Vite 构建版本插件。开发态提供版本接口,构建态输出 version.json,并可把同一份版本信息注入 HTML 和 Vite define

安装

pnpm add -D @gitlon/version

要求 Node.js >= 18、Vite >= 5。

Vite

import { defineConfig } from 'vite'
import buildVersionPlugin from '@gitlon/version'

export default defineConfig({
  plugins: [buildVersionPlugin()],
})

默认行为:

  • 开发态通过 /version.json 返回版本信息;
  • 构建态生成 dist/version.json
  • 构建态生成 dist/refresh.html 刷新页,开发态同路径响应;
  • 向 HTML 注入 window["__VERSION__"]window.refreshCache()window.checkVersion()
  • 通过 Vite define 注入 __VERSION__
  • 读取项目最近的 package.json,写入 pkgNamepkgVersion
  • 开发态 time0
  • 构建态 timeAsia/Shanghai 时区的 YYYYMMDDHHmmss
{
  "pkgName": "your-app",
  "pkgVersion": "1.0.0",
  "time": "20260917153045",
  "env": "production"
}

VitePress

必须复用同一个插件实例:

import { defineConfig } from 'vitepress'
import buildVersionPlugin from '@gitlon/version'

const buildVersion = buildVersionPlugin()

export default defineConfig({
  vite: {
    plugins: [buildVersion],
  },
  transformHtml: buildVersion.transformHtml,
})

Nuxt

Nuxt HTML 不经过 Vite transformIndexHtml,需把 headScript() 接入 render:html

import buildVersionPlugin from '@gitlon/version'

const buildVersion = buildVersionPlugin()

export default defineNuxtConfig({
  vite: {
    plugins: [buildVersion],
  },
  hooks: {
    'render:html'(html) {
      html.head.push(buildVersion.headScript())
    },
  },
})

插件自动识别 Nuxt 构建资产目录。默认静态文件路径通常为 /_nuxt/version.json

配置

interface BuildVersionContext {
  command: 'serve' | 'build'
  mode: string
}

interface BuildVersionPluginOptions {
  filename?: string
  globalName?: string
  defineName?: string | false
  injectToHtml?: boolean
  refreshHtml?: boolean | string
  refreshKey?: string
  checkKey?: string
  timeZone?: string
  version?: string | number | ((context: BuildVersionContext) => string | number)
  data?: Record<string, any>
  log?: (content: any) => string
  payload?: (json: any) => any
}

filename

版本文件路径,默认 version.json。自动跟随 Vite base

buildVersionPlugin({ filename: 'meta/version.json' })

globalName

HTML 注入的 window 属性名,默认 __VERSION__

buildVersionPlugin({ globalName: '__APP_VERSION__' })

defineName

Vite 编译期常量名,默认 __VERSION__。传 false 关闭:

buildVersionPlugin({ defineName: false })

injectToHtml

是否注入 HTML,默认 true。关闭后仍提供和生成版本 JSON。

refreshHtml

独立刷新页的文件名,默认 refresh.html。传 false 不生成,同时不注入 refreshKey 方法:

buildVersionPlugin({ refreshHtml: 'clear.html' })
buildVersionPlugin({ refreshHtml: false })

refreshKey

跳转到刷新页的全局方法名,默认 refreshCache,注入为 window.refreshCache()

buildVersionPlugin({ refreshKey: 'goRefresh' })

checkKey

检查是否有新版本的全局方法名,默认 checkVersion,注入为 window.checkVersion()

buildVersionPlugin({ checkKey: 'getVersionStatus' })

该方法的注入只受 injectToHtml 控制,refreshHtml: false 不影响它。

timeZone

默认版本时间所用时区,默认 Asia/Shanghai

version

固定版本值或版本生成函数:

buildVersionPlugin({
  version: ({ command, mode }) => (command === 'serve' ? 0 : `${mode}-20260917`),
})

data

追加字段。覆盖顺序为 data、项目包信息、time/envpayload

buildVersionPlugin({
  data: {
    appName: 'admin',
    commitSha: 'abc1234',
  },
})

payload

最终改写 payload:

buildVersionPlugin({
  payload: (json) => ({
    version: json.time,
    environment: json.env,
  }),
})

log

自定义构建完成日志:

buildVersionPlugin({
  log: (payload) => `build version: ${payload.time}`,
})

读取版本

运行时:

console.log(window.__VERSION__)

编译期:

console.log(__VERSION__)

远程检查:

const latest = await fetch('/version.json', { cache: 'no-store' }).then((response) =>
  response.json(),
)

if (latest.time !== window.__VERSION__?.time) {
  window.location.reload()
}

或直接调用注入的全局方法,一次拿到本地与线上信息:

const { local, server, update } = await window.checkVersion()

console.log(local) // 注入的 __VERSION__
console.log(server) // 线上 version.json
if (update) window.refreshCache()

返回结构为 { local, server, update }updateserver.time !== local.time 判定。请求失败或响应非 2xx 时不抛错,返回 server: nullupdate: false。请求走 no-store 并在 URL 上附加时间戳参数二次防缓存,URL 已按 Vite base 计算。

刷新项目缓存

import { clearUrlCache } from '@gitlon/version/client'

await clearUrlCache({
  urls: ['/vue-app/', '/vue-app/index.html'],
  redirectUrl: '/vue-app/',
  time: 5,
  onBeforeRedirect: async () => {
    await reportUpdate()
  },
})

time 单位为秒,默认 5。调用时显示全屏倒计时;依次使用无缓存请求、reload 请求和隐藏 iframe 刷新各 URL,完成或超时后携带随机参数跳转。

onBeforeRedirect 在跳转前调用并被 await,适合收尾工作(存状态、埋点、清理登录态)。回调抛错或刷新超时都不影响跳转。

无参数时处理当前页面路径及其 index.html

await clearUrlCache()

hash 路由会保留,随机参数写在 # 前。该方法仅支持同源 URL;浏览器无法直接删除全部 HTTP 缓存,此方法只尽可能刷新目标项目缓存。

刷新页

插件在 dist 中生成 refresh.html,作为不依赖应用构建产物的稳定入口:

/refresh.html?url=/vue-app/    → 清理 /vue-app/ 缓存后跳转到 /vue-app/

流程为:显示 loading → 对 url 及其 index.html 变体依次发送无缓存请求并加载隐藏 iframe → 完成或 5 秒超时后跳转到 urlurl 支持相对路径,相对 refresh.html 所在位置解析;跳转不附加随机参数。

不带 url 参数时跳转到当前目录的 index.html

/refresh.html        → /index.html
/app/refresh.html    → /app/index.html

业务代码触发刷新(同事在任意位置调用):

window.refreshCache()

等价于 location.replace('<刷新页路径>?_=' + Date.now() + '&url=' + encodeURIComponent(location.href)),携带当前完整 URL 并透传 hash,刷新页请求本身也带时间戳防缓存;用 replace 而非 href=,刷新页不会进入历史栈,避免用户后退时被反复弹回。路径已按 Vite base 计算。

该页脚本由插件内联生成,不 import 任何带 hash 的构建产物,所以旧版本页面也能通过它清理缓存后进入新版本。dev server 同样响应该路径。

类型导出

主入口导出:

  • buildVersionPlugin
  • BuildVersionContext
  • BuildVersionPayload
  • BuildVersionPluginOptions
  • BuildVersionPlugin

客户端入口导出:

  • clearUrlCache
  • ClearUrlCacheOptions