跳转到内容
关系图谱

npm-card:npm 包信息卡完全指南

1,608 字 6 分钟

属性 1
series
VaultKit 包指南

@vaultkit/vitepress-plugin-npm-card 提供 ::: npm-card 容器:写包介绍、教程文章时一行嵌入 npm 包信息卡——版本、描述、周下载、解包体积、运行时依赖数、license、TS 类型徽标、keywords 一卡集齐。构建期从 npm registry 抓取元数据渲染为静态卡片,零客户端 JS,全程免认证。

语法与实现同 repo-card 完全同轨:单段 Vite 插件(enforce: 'pre')在 md 编译前改写原文,主参数走 info-string 位、单行即闭合。本文覆盖主参数两种形态、全部 4 个属性、三档尺寸逐档实活演示、全部 4 个插件 options,并讲透它规避几十 MB 完整包文档的取数策略。

为什么需要它

介绍一个 npm 包时,读者最关心的几个数字——最新版本、周下载量、体积、依赖数——散落在 npmjs.com 各处。手工抄进文章,发布当天就开始过时;贴 shields.io 徽章,则是页面运行时的一堆第三方请求。

npm-card 在构建期取数、构建期渲染:数据随每次部署自动刷新,页面加载零额外请求;新发布的包周下载端点还没数据时优雅降级(只是不渲染该字段),不炸构建。

安装

sh
pnpm add -D @vaultkit/vitepress-plugin-npm-card
ts
// .vitepress/config.ts —— 注册在 vite.plugins(非 markdown.config)
import { npmCard } from '@vaultkit/vitepress-plugin-npm-card'
import { defineConfig } from 'vitepress'

export default defineConfig({
  vite: { plugins: [npmCard()] },
})
ts
// .vitepress/theme/index.ts
import '@vaultkit/vitepress-plugin-npm-card/styles/index.css'

使用 @vaultkit/vitepress-theme-vault 主题则开箱即带,容器直接可用。

快速上手

主参数走 info-string 位,单行即闭合、::: 收尾可省:

md
::: npm-card vue

::: npm-card @vue/reactivity {size="sm"}

::: npm-card https://www.npmjs.com/package/vitepress {size="lg"}

实活效果(本页构建期真实抓取渲染):

主参数的两种形态

包名简写

直接写包名,scoped 包原样支持(@scope/name);构建期先过 npm 合法包名正则,非法包名直接抛错:

md
::: npm-card vue

::: npm-card @vue/reactivity

npmjs.com URL

写包主页地址,可带 /v/x.y.z 版本尾巴(自动忽略,恒取 latest):

md
::: npm-card https://www.npmjs.com/package/vitepress

容器属性逐项详解

全部 4 个属性:

属性类型缺省说明
pkgstring包名(等价于 info-string 主参数的简写形态)
urlstringnpmjs.com/package/<name> 地址(等价于主参数 URL 形态)
sizestringmdsm / md / lg
classstring卡片额外类名

pkg / url 属性形态与主参数等价(主参数优先级更高):

md
::: npm-card {pkg="vue" size="sm"}

::: npm-card {url="https://www.npmjs.com/package/vue" class="hero-card"}

未知属性、非法包名、size 超出三档,全部构建期抛错(fail-fast),不渲染残卡。

三档尺寸逐档演示

sm:行内徽章条

npm 徽标 + 包名 + 版本 + 周下载,一行高,正文顺带提及:

md
::: npm-card vue {size="sm"}

md:钉选卡(缺省)

在 sm 基础上加描述、TS 徽标与统计行(周下载、解包体积、运行时依赖数、license),列包清单用:

md
::: npm-card vue {size="md"}

lg:陈列卡

再加大标题、npm i 安装命令行、keywords 徽标行(至多 5 个)与悬停光泽扫过,教程开头、作品页展示用:

md
::: npm-card @vue/reactivity {size="lg"}

插件 Options 全览

npmCard(options?)NpmCardOptions 共 4 项:

名称类型默认值说明
registryBasestring'https://registry.npmjs.org'元数据 registry 基址
downloadsbooleantrue周下载量抓取开关
ttlnumber3_600_000缓存有效期(ms,缺省 1 小时)
cacheDirstringnode_modules/.cache/vitepress-plugin-npm-card缓存目录

registryBase

元数据抓取的 registry 基址,国内 CI 可切 npmmirror 等镜像加速构建:

ts
npmCard({ registryBase: 'https://registry.npmmirror.com' })

downloads

周下载量抓取开关。注意数据恒来自官方 api.npmjs.org,与 registryBase 无关(镜像不提供 downloads API);内网构建可整体关掉:

ts
npmCard({ downloads: false }) // 卡片不再渲染周下载字段

ttl 与 cacheDir

与 repo-card 同款缓存语义:TTL 内直接命中磁盘缓存,过期重抓、失败回退陈缓存。CI 建议持久化缓存目录:

ts
npmCard({ ttl: 24 * 3_600_000, cacheDir: '.cache/npm-card' })

设计机制

取数策略:绝不碰完整包文档

npm registry 的 /{pkg} 端点返回全版本历史文档——大包极其恐怖:vite 的完整文档约 37 MB。给每张卡片拉几十 MB 再丢掉 99.9%,是构建性能的灾难。

npm-card 刻意只打两个小端点:

  • registry.npmjs.org/{pkg}/latest——单版本文档,几 KB,含版本、描述、license、dependencies、types、keywords、dist.unpackedSize 全部所需字段
  • api.npmjs.org/downloads/point/last-week/{pkg}——周下载量,一个数字

两个端点都免认证,也就没有任何 token 配置项——这是它与 repo-card options 表的最大差异。

周下载的优雅降级

新发布的包 downloads 端点可能 404,也可能返回 error 体。npm-card 把两种情况统一降级为 null:卡片不渲染下载字段,构建照常通过,只留一行 warn。元数据错误炸构建(包名写错理应发现),统计数据缺失不炸构建(新包无数据不是作者的错)——两类失败区别对待。

与 repo-card 共享的底盘

Vite 原文改写(enforce: 'pre' + 行首正则 + type-6 HTML block 透传)、ATTR_PATTERN 属性解析、fetchCached 磁盘缓存全部来自 @vaultkit/repo-platform-kit。npm-card 是这个底座「平台无关部分」的最佳示范:它不需要 GitHub/CNB 的平台知识,只消费缓存与属性解析。

改写前会先按 CommonMark 围栏规则切段、只处理围栏外的文本——代码块里顶格演示 ::: npm-card 语法是安全的,这一行为与 repo-card / remote-file 通用。

常见问题

体积字段有时不显示? registry 老版本发布物可能缺 dist.unpackedSize,缺则整个字段不渲染。

TS 徽标的判定标准? latest 版本 manifest 存在 typestypings 字段即亮 TS 徽标;靠 @types/* 补类型的包不亮。

能显示指定版本吗? 不能,恒取 latest——包卡的语义是「这个包现在什么样」,锁版本展示请直接写代码块。

相关链接