This proposal introduces the idea of adding extracted package size information to the output summary for npm install.
NOTE
This is an RFC. It is not a finalized, accepted feature request proposal. I've laid out the general process of implementation, but please don't make a PR implementing it until we've had time to discuss this.
Problem
Right now, there's no built-in way for npm users to figure out the size impact of adding or removing a package from their tree. In the past, it would have been easier because you could just trace the nested tree -- but now, because of flattening and deduplication, it's not trivial to take into account how many new packages would be added by a particular install, and what their total impact would be.
Changes npm install
The npm install output will be changed such that total size information is included, and displayed in different ways depending on output mode:
npm install
The default, human-readable view currently looks like this:
➜ npm i webpack
+ webpack@4.6.0
added 536 packages from 24 contributors in 9.299s
It will be changed to display size information like this:
➜ npm i webpack
+ webpack@4.6.0
added 536 packages (+32MB) from 24 contributors in 9.299s
Or when the net value is negative:
➜ npm rm --dry-run pacote
removed 39 packages (-5MB) in 5.148s
Even when both additions and removals have occurred:
➜ npm i --dry-run pacote@1
+ pacote@1.0.0
added 35 packages, removed 33 packages, updated 1 package and moved 1 package (-3MB) in 5.817s
npm install --json
The JSON format will add two things: size and unpackedSize field to each individual action record, and a sizeDelta field that totals up all the unpackedSize changes, in the toplevel:
➜ npm i ssri --dry-run --json
{
"added": [
{
"action": "add",
"name": "ssri",
"version": "6.0.0",
"path": ".../node_modules/ssri",
"size": 12116,
"unpackedSize": 40772
}
],
"removed": [],
"updated": [],
"moved": [],
"failed": [],
"warnings": [],
"sizeDelta": 40772, // positive or negative, depending on sum
"elapsed": 535
}
npm install --parseable
The --parseable tab-delimited format will remain unchanged by default, to prevent potentially breaking parsers. Instead, the --long/-l option will be supported, which will add two additional columns next to each entry: the tarball size, and the unpackedSize. It's up to users to add the numbers up themselves.
➜ npm i ssri --dry-run --parseable --long
add ssri 6.0.0 node_modules/ssri 12116 40772
Implementation Details
This would need to patch both the npm installer (in lib/install.js and lib/install/actions/extract.js), as well as add an extra field to the finalizeManifest process in pacote (lib/finalize-manifest.js).
npm installer changes
There are two changes to be made to the installer:
On the reporting side, update the three reporters (printInstalledForHuman, printInstalledForParseable, and printInstalledForJSON) in lib/install.js. You should be able to check _size and _unpackedSize in the child.package value, which holds the manifest for each installed package. Note: if any of the packages in the calculation are missing the _unpackedSize value and the current reporter is printInstalledForHuman, this file size summary should be omitted altogether. This case will happen for legacy registries when using npm install --dry-run -- it will otherwise be calculated from actual extracted size.
On the extract side, you will need to check if the child.package._size and child.package._unpackedSize properties exist. If they do not, you should set them based on metadata returned by pacote.extract().
pacote changes
pacote needs to do two things to support this:
-
lib/finalize-manifest.js should be modified to get the compressed and uncompressed tarball size from package manifests, but only if they are available. They should be assigned to _size and _unpackedSize respectively, and are present in the dist.size and dist.unpackedSize properties of the manifest.
-
extract.js and tarball.js should have their functions modified such that they return or emit size and unpackedSize as part of the metadata, where appropriate, after the operation has completed. This should be calculated from the actual data getting extracted (and may require changes to lib/extract-stream.js as well as lib/with-tarball-stream.js.
This proposal introduces the idea of adding extracted package size information to the output summary for
npm install.NOTE
This is an RFC. It is not a finalized, accepted feature request proposal. I've laid out the general process of implementation, but please don't make a PR implementing it until we've had time to discuss this.
Problem
Right now, there's no built-in way for npm users to figure out the size impact of adding or removing a package from their tree. In the past, it would have been easier because you could just trace the nested tree -- but now, because of flattening and deduplication, it's not trivial to take into account how many new packages would be added by a particular install, and what their total impact would be.
Changes
npm installThe
npm installoutput will be changed such that total size information is included, and displayed in different ways depending on output mode:npm installThe default, human-readable view currently looks like this:
It will be changed to display size information like this:
Or when the net value is negative:
Even when both additions and removals have occurred:
npm install --jsonThe JSON format will add two things:
sizeandunpackedSizefield to each individualactionrecord, and asizeDeltafield that totals up all theunpackedSizechanges, in the toplevel:npm install --parseableThe
--parseabletab-delimited format will remain unchanged by default, to prevent potentially breaking parsers. Instead, the--long/-loption will be supported, which will add two additional columns next to each entry: the tarballsize, and theunpackedSize. It's up to users to add the numbers up themselves.Implementation Details
This would need to patch both the npm installer (in
lib/install.jsandlib/install/actions/extract.js), as well as add an extra field to thefinalizeManifestprocess inpacote(lib/finalize-manifest.js).npm installer changes
There are two changes to be made to the installer:
On the reporting side, update the three reporters (
printInstalledForHuman,printInstalledForParseable, andprintInstalledForJSON) inlib/install.js. You should be able to check_sizeand_unpackedSizein thechild.packagevalue, which holds the manifest for each installed package. Note: if any of the packages in the calculation are missing the_unpackedSizevalue and the current reporter isprintInstalledForHuman, this file size summary should be omitted altogether. This case will happen for legacy registries when usingnpm install --dry-run-- it will otherwise be calculated from actual extracted size.On the extract side, you will need to check if the
child.package._sizeandchild.package._unpackedSizeproperties exist. If they do not, you should set them based on metadata returned bypacote.extract().pacotechangespacoteneeds to do two things to support this:lib/finalize-manifest.jsshould be modified to get the compressed and uncompressed tarball size from package manifests, but only if they are available. They should be assigned to_sizeand_unpackedSizerespectively, and are present in thedist.sizeanddist.unpackedSizeproperties of the manifest.extract.jsandtarball.jsshould have their functions modified such that they return or emit size and unpackedSize as part of the metadata, where appropriate, after the operation has completed. This should be calculated from the actual data getting extracted (and may require changes tolib/extract-stream.jsas well aslib/with-tarball-stream.js.