Files
deepseek-harness/scripts/attribute-chunk-bytes.mjs

102 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Attribute a built chunk's minified bytes to source npm packages / workspace dirs via its
// sourcemap (zero-dependency VLQ decoder). The dist-audit companion of the shell chunk-layout
// decision (.agents/notes/implemented/architecture/2026-08-06-web-shell-dist-chunk-layout.md):
// verifies vendor/index membership after changing VENDOR_PACKAGES or bumping render deps.
// Usage: node scripts/attribute-chunk-bytes.mjs <chunk.js> [--top N]
import { readFileSync } from 'node:fs'
const chunkPath = process.argv[2]
const topN = Number(process.argv[process.argv.indexOf('--top') + 1] || 40)
const code = readFileSync(chunkPath, 'utf8')
const map = JSON.parse(readFileSync(chunkPath + '.map', 'utf8'))
const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
const charToInt = new Map([...B64].map((c, i) => [c, i]))
// Decode one VLQ-encoded segment list line by line.
const lines = code.split('\n')
const bySource = new Float64Array(map.sources.length)
let unmapped = 0
let srcIdx = 0, srcLine = 0, srcCol = 0, nameIdx = 0
const mappingLines = map.mappings.split(';')
for (let li = 0; li < mappingLines.length; li++) {
const lineLen = li < lines.length ? lines[li].length + 1 : 0
const segsRaw = mappingLines[li]
if (segsRaw === '') { unmapped += lineLen; continue }
let genCol = 0
const segs = []
for (const segStr of segsRaw.split(',')) {
const fields = []
let shift = 0, value = 0
for (const ch of segStr) {
const digit = charToInt.get(ch)
value += (digit & 31) << shift
if (digit & 32) { shift += 5 } else {
fields.push((value & 1) ? -(value >>> 1) : (value >>> 1))
shift = 0; value = 0
}
}
genCol += fields[0]
if (fields.length > 1) {
srcIdx += fields[1]; srcLine += fields[2]; srcCol += fields[3]
if (fields.length > 4) nameIdx += fields[4]
segs.push([genCol, srcIdx])
} else {
segs.push([genCol, -1])
}
}
if (segs[0][0] > 0) unmapped += segs[0][0]
for (let i = 0; i < segs.length; i++) {
const end = i + 1 < segs.length ? segs[i + 1][0] : lineLen
const span = Math.max(0, end - segs[i][0])
if (segs[i][1] >= 0) bySource[segs[i][1]] += span
else unmapped += span
}
}
// Aggregate source path -> package bucket.
function bucketOf(src) {
if (src.startsWith('') || src.includes('vite/')) return '(vite virtual/helpers)'
const nm = [...src.matchAll(/node_modules\/(@[^/]+\/[^/]+|[^@./][^/]*)\//g)]
if (nm.length > 0) return nm[nm.length - 1][1]
let m = src.match(/packages\/([^/]+\/[^/]+)\//)
if (m) return 'ws:packages/' + m[1]
m = src.match(/vendor\/([^/]+)\//)
if (m) return 'ws:vendor/' + m[1]
m = src.match(/apps\/web\//)
if (m) return 'ws:apps/web'
return src
}
const byBucket = new Map()
for (let i = 0; i < map.sources.length; i++) {
if (bySource[i] === 0) continue
const b = bucketOf(map.sources[i])
byBucket.set(b, (byBucket.get(b) || 0) + bySource[i])
}
byBucket.set('(unmapped: interop glue/helpers)', unmapped)
const total = code.length
const rows = [...byBucket.entries()].sort((a, b) => b[1] - a[1])
const kb = n => (n / 1024).toFixed(1).padStart(8)
const pc = n => ((n / total) * 100).toFixed(1).padStart(5)
console.log(`chunk: ${chunkPath} total ${(total / 1024).toFixed(1)} kB (minified, pre-gzip)`)
console.log(`${'kB'.padStart(8)} ${'%'.padStart(5)} package`)
let shown = 0, acc = 0
for (const [name, bytes] of rows) {
if (shown++ < topN) console.log(`${kb(bytes)} ${pc(bytes)} ${name}`)
acc += bytes
}
if (rows.length > topN) console.log(` ... ${rows.length - topN} more buckets`)
console.log(`accounted: ${(acc / 1024).toFixed(1)} kB of ${(total / 1024).toFixed(1)} kB`)
// Group summary: npm vendor vs workspace.
let vendor = 0, ws = 0, other = 0
for (const [name, bytes] of rows) {
if (name.startsWith('ws:')) ws += bytes
else if (name.startsWith('(')) other += bytes
else vendor += bytes
}
console.log(`\nGROUPS npm-vendor ${(vendor / 1024).toFixed(1)} kB | workspace ${(ws / 1024).toFixed(1)} kB | glue ${(other / 1024).toFixed(1)} kB`)