├── .gitignore ├── README.md ├── index.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # why-npm-i-so-long 2 | 3 |

illustration of a person asking why npm install take so long?

4 | 5 | Little utility to ease troubleshooting why installing npm dependencies takes too long. 6 | 7 | ## What is "publish size" vs "install size"? 8 | 9 | The "publish size" is the size of the source code published to npm. This number is easy to detect and should be pretty small. 10 | 11 | The "install size" is the size your hard drive will report after running npm install. This includes the package, all of the dependencies, and its dependency's dependencies...and so on. 12 | 13 | ## Use without installing 14 | 15 | ```sh 16 | npx why-npm-i-so-long path/to/package.json 17 | ``` 18 | 19 | ## Installation 20 | 21 | ```sh 22 | npm install --global why-npm-i-so-long 23 | ``` 24 | 25 | ## Usage 26 | 27 | See install size of dependencies 28 | ```sh 29 | why-npm-i-so-long path/to/package.json 30 | ``` 31 | See install size of devDependencies 32 | ```sh 33 | why-npm-i-so-long path/to/package.json --dev 34 | ``` 35 | 36 | ## Acknowledgments 37 | 38 | - [packagephobia](https://github.com/styfle/packagephobia) 39 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('node:fs'); 4 | const path = require('node:path'); 5 | const {styleText} = require('node:util') 6 | const {log} = console; 7 | 8 | function program(...args) { 9 | const isDevIndex = args.indexOf('--dev'); 10 | const isDev = isDevIndex !== -1; 11 | const pathToPkg = isDev ? args[isDevIndex === 0 ? 1 : 0] : args[0]; 12 | const resolvedPath = path.resolve(pathToPkg); 13 | 14 | if (!fs.existsSync(resolvedPath)) return log('File does not exist'); 15 | if (!resolvedPath.endsWith('.json')) 16 | return log('Provided file is not a json file'); 17 | 18 | const pkg = require(resolvedPath); 19 | const {dependencies, devDependencies} = pkg; 20 | 21 | const depsToProcess = isDev ? devDependencies : dependencies; 22 | 23 | if (depsToProcess === undefined) { 24 | return log(`JSON does not have ${isDev ? 'devD' : 'd'}ependencies`); 25 | } 26 | 27 | Promise.all( 28 | Object.entries(depsToProcess).map(([name, version]) => 29 | fetch( 30 | [ 31 | 'https://packagephobia.now.sh/v2/api.json?p=', 32 | name, 33 | '@', 34 | version.replace(/[\^=<>~]/g, ''), 35 | ].join(''), 36 | ).then(res => res.json()) 37 | .catch(() => ({name, install: {bytes: -1}, publish: {bytes: -1}})), 38 | ), 39 | ) 40 | .then(sizes => { 41 | const title = `${pkg.name}'s ${isDev ? 'devD ' : 'd'}ependencies:\n`; 42 | log(styleText('bold', title)); 43 | 44 | return sizes 45 | .sort((a, b) => a.install.bytes - b.install.bytes) 46 | .map(({name, version, install, publish}) => { 47 | if (install.bytes === 0) { 48 | return `${name} - unknown`; 49 | } 50 | if (install.bytes === -1) { 51 | return `${name} - api failed`; 52 | } 53 | return ` 54 | ${styleText('bold', name)} @ ${version} 55 | \tinstall size\t${colorSize(install)} 56 | \tpublish size\t${colorSize(publish)} 57 | `.trim(); 58 | }) 59 | .join('\n\n'); 60 | }) 61 | .then(log); 62 | } 63 | 64 | function colorSize({bytes, pretty}) { 65 | return bytes > 1048576 66 | ? styleText(['bold', 'red'], pretty) 67 | : bytes > 307200 68 | ? styleText('yellow', pretty) 69 | : styleText('green', pretty); 70 | } 71 | 72 | program(...process.argv.slice(2)); 73 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "why-npm-i-so-long", 3 | "version": "2.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "why-npm-i-so-long", 9 | "version": "2.0.0", 10 | "license": "MIT", 11 | "bin": { 12 | "why-npm-i-so-long": "index.js" 13 | }, 14 | "engines": { 15 | "node": ">=20.12" 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "why-npm-i-so-long", 3 | "version": "2.0.0", 4 | "description": "CLI to check dependencies size", 5 | "main": "index.js", 6 | "bin": "./index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "npm", 12 | "cli", 13 | "install", 14 | "size" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/antonk52/why-npm-i-so-long.git" 19 | }, 20 | "bugs": { 21 | "url": "https://github.com/antonk52/why-npm-i-so-long/issues" 22 | }, 23 | "author": "antonk52", 24 | "license": "MIT", 25 | "engines": { 26 | "node": ">=20.12" 27 | } 28 | } 29 | --------------------------------------------------------------------------------