- 全站标识改为 Verdaccio Mate(登录页/顶部栏/关于页/浏览器标题) - 镜像名改为 verdaccio-mate:latest,README 构建与部署示例同步 - 后端包名 verdaccio-mate-backend - 修复 AppTopbar 模板多余闭合标签(Invalid end tag 导致 build 失败) - 数据卷路径保持不变,避免 NAS 数据丢失
7.5 KiB
Verdaccio Mate · 可视化治理面板(缓存 + 私有包)
对私有 npm Registry(Verdaccio)的缓存目录与私有包可视化治理面板:扫描缓存、来源识别(私有发布 / 上游缓存)、版本预警、清理低版本、拉取存量最新版本、维护 npm Top1000 榜单、README 预览、安装命令一键复制,并通过消息中心推送非实时通知。
项目产生的背景
Verdaccio 是轻量、零配置的 npm 私有仓储,在团队内承担双重角色:
- 离线缓存与内网分发——首次经公网拉取后缓存到本地,内网后续命中即走缓存,装得快且构建稳定;很多 NAS / 内网用户更把它当"包备份池",批量预置热门前端包,构建不受公网波动的私有源。
- 私有发布源——团队内部
@scope包、私有组件直接发布到同一存储目录,与原版界面混杂的代理缓存包共存。
但 Verdaccio 作为一个"仓储",只负责存取、不提供治理能力,长跑后暴露出几类痛点:缓存目录是黑盒(数量/占用/分布不可见)、版本随 npm install 无限膨胀塞满磁盘却无从发现、超量版本只能手工进目录删除(危险易误删)、且只能缓存"用过的包"无法主动预置热门前端依赖。更麻烦的是私有包与缓存包混杂,原版 UI 无法一眼区分来源,也没有 README 预览、安装命令等洞察能力。
本面板即为 Verdaccio 补上缺失的可视化 + 治理 + 主动预置 + 私有包洞察四块能力,并在自研前端里复刻原版界面的读取体验(包来源徽标、README 渲染、搜索联想、安装命令复制、原版用户只读列表),做成开箱即用、可 Docker 一键部署的管理面板。
- 后端:Node.js(Express + better-sqlite3,ESM)
- 前端:Vue 3 + Vite + Element Plus(
frontend/) - 数据:SQLite(
backend/data/),登录鉴权 + 登录限流
功能一览
| 能力 | 说明 |
|---|---|
| 缓存扫描 | 异步扫描 Verdaccio 缓存目录,返回包数/字节,遮罩展示进度 |
| 私有包洞察 | 自动识别私有发布 / 上游代理缓存(_uplinks + verdaccio-db.json 交叉校验),来源筛选 + 包名旁徽标 |
| README 预览 | 详情抽屉渲染 Markdown README(marked + DOMPurify 清洗,双主题样式) |
| 搜索联想 | 输入即时联想(本地前缀 Top 8),点击即搜 |
| 安装命令 | 一键复制 npm install 包@版本(latest 取 dist-tags) |
| 原版用户(只读) | 解析 htpasswd 展示 Verdaccio 用户列表(登录仍走内置账号) |
| 版本预警 | 包版本数超阈值时置顶提示,快照比对去重,变化才推送通知 |
| 清理低版本 | 保留最新 N 版,删除其余,释放空间 |
| 拉取存量最新版 | 对缓存内包一键拉取其最新版本(逐包进度 + 失败明细) |
| Top1000 榜单 | 按 npm Downloads 抓取周榜,与本地缓存比对「未缓存/需更新」,一键拉取 |
| 操作日志 | 扫描/删除/拉取/登录等操作审计(支持按批次 batchId 筛选) |
| 消息中心 | 非实时通知(预警/批量拉取结果/榜单变化/扫描完成),30s 轮询 |
| 定时任务 | 每日 03:00 自动扫描(lazy 懒扫描兜底)、每周一 00:00 抓榜 |
目录结构
backend/ # Node 后端(Express + better-sqlite3)
server.js # 入口:REST API、扫描状态机、鉴权
scanner.js # 缓存目录扫描 + 增量缓存
scan-manager.js # 异步扫描与并发控制
clean.js # 清理低版本 / 删除单版本
sync-latest.js # 一键拉取存量包最新版
npm-toplist.js # Top1000 榜单抓取 / 拉取
db.js # SQLite 存取
notifier.js # 消息通知入口
semver.js # 语义化版本比较
schedules.js # 定时任务(每日扫描/每周抓榜)
test/ # node:test 单元测试
frontend/ # Vue3 + Vite + Element Plus
src/ # 页面、组件、store、api、mock
Dockerfile # 多阶段镜像(前端 dist 本地构建后拷入)
本地开发
Node 要求 >=20.19(推荐 via nvm)。本仓库 better-sqlite3@11 对 Node 24 无预编译二进制,请使用 Node v22(如 22.x 中 ≥22.12)。
# 后端(终端 A)
cd backend
npm install
npm run dev # http://localhost:3000
# 前端(终端 B)
cd frontend
npm install
npm run dev # http://localhost:5173(代理 /api -> 后端)
前端本地代理目标在 frontend/vite.config.js 中配置。
演示模式
未配置 VERDACCIO_STORAGE(或目录无效)时后端以演示模式运行(mock 数据、禁止拉取)。
npm scripts
后端 backend/
| 脚本 | 命令 | 说明 |
|---|---|---|
start |
node server.js |
生产启动 |
dev |
node --watch server.js |
开发热重载 |
test |
node --test |
单元测试(backend/test/) |
lint |
eslint . |
ESLint 静态检查 |
typecheck |
node scripts/typecheck.mjs |
对全部 *.js 做 node --check 语法校验 |
前端 frontend/
| 脚本 | 命令 | 说明 |
|---|---|---|
dev |
vite |
开发服务(5173) |
build |
vite build |
生产构建到 dist/ |
preview |
vite preview |
预览构建产物 |
lint |
eslint . |
ESLint + Vue 规则检查 |
typecheck |
vue-tsc --noEmit |
Vue SFC / TS 类型检查 |
首次运行前端
typecheck前先执行一次build或dev,以生成auto-imports.d.ts与components.d.ts(Element Plus 按需自动注册的类型声明)。
构建 Docker 镜像
cd frontend && npm install && npm run build # 先构建前端 dist
cd .. && docker build --platform linux/amd64 -t verdaccio-mate:latest .
docker save -o verdaccio-mate-amd64.tar verdaccio-mate:latest
镜像基于 node:20-slim,仅含后端运行时依赖 + 前端静态产物,非 root 运行,监听 3000。
部署(示例 docker-compose.yml):
services:
verdaccio-mate:
image: verdaccio-mate:latest
restart: unless-stopped
ports:
- "42338:3000"
volumes:
- /path/to/storage:/storage # Verdaccio 缓存目录
- ./data:/app/data # SQLite 数据
environment:
- VERDACCIO_STORAGE=/storage
- VCM_USERNAME=admin
- VCM_PASSWORD=<强密码>
- DATA_DIR=/app/data
- TZ=Asia/Shanghai
环境变量
| 变量 | 默认 | 说明 |
|---|---|---|
VERDACCIO_STORAGE |
— | Verdaccio 缓存目录(优先于 UI 设置) |
PORT |
3000 |
监听端口 |
DATA_DIR |
backend/data |
SQLite 数据目录 |
VCM_USERNAME |
admin |
面板登录账号 |
VCM_PASSWORD |
666666 |
面板登录密码(生产必须覆盖) |
VCM_DEMO |
— |
1 强制演示模式 |
UV_THREADPOOL_SIZE |
8 |
libuv IO 线程池(目录/文件并发扫描瓶颈) |
说明与约束
- 并发保护:扫描进行中重复
POST /api/scan返回409;扫描期间禁止删除操作,避免破坏进行中扫描的缓存。 - 懒扫描:缓存缺失时首次打开页面触发后台扫描(首次部署遮罩呈现),后续重扫/写操作后改为后台静默 + 消息中心通知。
- 失败冷却:扫描失败后 5 分钟内不自动重试(手动重扫不受限)。
- npm 跨境请求(Search/Downloads/拉包)内置限速、并发控制与 429 指数退避。