fix: 扫描缓存与真实大小计算,解决页面加载慢与数据虚增

- scanner: 大小改为统计实际 .tgz 文件(兼容 {version}.tgz 与 {pkg}-{version}.tgz 命名),
  不再用 unpackedSize 兜底虚增数倍
- server: 扫描结果内存缓存(首次懒扫描,后续请求秒回),新增 POST /api/scan 手动重扫,
  /api/packages 返回 scannedAt 时间戳,clean/删版本后自动失效缓存
- 前端: 概览页新增「重新扫描」按钮 + 「基于 xxx 扫描」时间展示;Top30 在真实环境
  (无访问统计)降级为「缓存占用 Top 30」按大小排序
- compose: 数据卷改 named volume,修复非 root 容器 SQLITE_CANTOPEN
This commit is contained in:
陈银军
2026-09-19 17:57:58 +08:00
parent 72722ab6bf
commit f84f21574f
8 changed files with 147 additions and 41 deletions
+26 -9
View File
@@ -118,19 +118,36 @@ export function scanStorage(storageDir) {
const timeObj = meta.time || {}
const distTags = meta['dist-tags'] || {}
// 物理 .tgz 文件:先列目录建立文件名 → 大小索引
// (Verdaccio 各版本命名不同:{version}.tgz 或 {pkgname}-{version}.tgz,不猜、直接扫)
const tgzSizes = new Map()
let tgzTotal = 0
try {
for (const f of fs.readdirSync(pkgDir)) {
if (!f.endsWith('.tgz')) continue
const size = fs.statSync(path.join(pkgDir, f)).size
tgzTotal += size
tgzSizes.set(f.slice(0, -4), size)
}
} catch {}
const versionsDetail = []
let totalBytes = 0
// 总大小以实际 .tgz 文件为准;unpackedSize 是解压后大小,会数倍虚增,仅作无物理文件时的兜底
const totalBytes = tgzTotal
for (const [v, info] of Object.entries(versionsObj)) {
// tgz 物理文件:Verdaccio 约定 {pkgDir}/{version}.tgz
const tgz = path.join(pkgDir, `${v}.tgz`)
let size = 0
try {
size = fs.statSync(tgz).size
} catch {
// 无物理文件:用元数据 dist.tarball 大小兜底(无则 0)
let size = tgzSizes.get(v)
if (typeof size !== 'number') {
// 兼容 {pkgname}-{version}.tgz 命名:用元数据 dist.tarball 的文件名精确匹配
const tb = info && info.dist && info.dist.tarball
const bn = tb ? String(tb).split('/').pop() : ''
if (bn.endsWith('.tgz')) {
const hit = tgzSizes.get(bn.slice(0, -4))
if (typeof hit === 'number') size = hit
}
}
if (typeof size !== 'number') {
size = (info && info.dist && typeof info.dist.unpackedSize === 'number') ? info.dist.unpackedSize : 0
}
totalBytes += size
versionsDetail.push({
version: parseVersion(v),
size: fmtMb(size),