UNPKG

npm-install-size

Version:

Check the install size of any NPM package before installing it.

66 lines (63 loc) 2.47 kB
import fetch from 'node-fetch'; import { retry, parsePkgArg } from './fetch.js'; import { getDirStats, cleanup } from './analyze.js'; import tar from 'tar'; import fs from 'fs/promises'; import os from 'os'; import path from 'path'; async function fetchPackageMeta(pkgArg) { const { name, version } = parsePkgArg(pkgArg); const encoded = encodeURIComponent(name); const url = `https://registry.npmjs.org/${encoded}`; const res = await retry(() => fetch(url)); if (!res.ok) throw new Error(`Package not found`); const data = await res.json(); let ver = version || data['dist-tags']?.latest; if (!ver || !data.versions[ver]) throw new Error(`Version not found`); return { meta: data, version: ver, tarball: data.versions[ver].dist.tarball, dependencies: data.versions[ver].dependencies || {} }; } async function getPackageSizeFromTarball(tarballUrl) { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), `npm-install-size-tree-`)); try { const res = await retry(() => fetch(tarballUrl)); if (!res.ok) throw new Error(`Failed to download tarball`); await fs.mkdir(tempDir, { recursive: true }); await new Promise((resolve, reject) => { const extractStream = tar.x({ cwd: tempDir, strip: 1 }); res.body.pipe(extractStream); res.body.on('error', reject); extractStream.on('finish', resolve); extractStream.on('error', reject); }); const stats = await getDirStats(tempDir); return stats.total; } finally { await cleanup(tempDir); } } export async function getDependencyTreeSize(pkgArg, options = {}, seen = new Set()) { const { name, version } = parsePkgArg(pkgArg); const key = version ? `${name}@${version}` : name; if (seen.has(key)) { return { totalSize: 0, tree: { name: key, size: 0, dependencies: {} } }; } seen.add(key); const { tarball, version: resolvedVersion, dependencies } = await fetchPackageMeta(pkgArg); const size = await getPackageSizeFromTarball(tarball); let depTree = {}; let depTotal = 0; for (const dep in dependencies) { const depSpec = `${dep}@${dependencies[dep]}`; const { totalSize: depSize, tree: depSubtree } = await getDependencyTreeSize(depSpec, options, seen); depTree[depSpec] = depSubtree; depTotal += depSize; } return { totalSize: size + depTotal, tree: { name: key, size, dependencies: depTree } }; }