Have you checked for existing feature requests?
Summary
ppm relies on npm to do a lot of grunt work. But since ppm bundles its own Node, it also must bundle its own npm.
For reasons that I’m sure are complex and better left to @DeeDeeG to explain (or decide not to explain to avoid exhaustion), we maintain our own fork of the npm-cli repository. Of the commits that exist in that repo, I can identify ten that are definitely unique to our fork, and they suggest that the reasons to maintain an ongoing fork of npm-cli include
- bumping
node-gyp occasionally, and
- bumping
libnpm, libcipm, and npm-lifecycle (three dependencies of npm-cli that are themselves deprecated in favor of packages I'll mention below).
This is not the world’s most onerous chore, but there’s only one of @DeeDeeG, and I’d love to use their talents as politely as possible.
Can we outright eliminate dependence on npm? Let’s think it through.
How do we use NPM?
These are the places in the codebase I can identify where we explicitly shell out to npm:
ci.js shells out to npm ci
clean.js shells out to npm prune
config.js shells out to npm config
dedupe.js shells out to npm dedupe
install.js shells out to npm install
publish.js shells out to npm version
rebuild.js shells out to npm rebuild
There are other places where we use npm more like a library — require('npm'), then call methods on it — but these mainly involve reading configuration. Using npm in this manner is also deprecated and is worth replacing if we can.
So we can group these into tasks and then figure out other ways to accomplish the same tasks:
Dependency installation/cleanup
ci.js and install.js use npm for managing node_modules and reconciling it with package.json. We can use arborist for this; see #159.
arborist can also probably do the stuff done by npm prune, and I imagine by npm dedupe as well.
Reading NPM configuration
config.js delegates to npm for reading from and writing to configuration, since ppm has a need for many of the configuration keys that npm does, and wants to manage them the same way.
We could instead manage this with @npmcli/config.
Building/rebuilding modules
ppm famously needs to compile packages with native module dependencies, so that’s why it shells out to npm rebuild. But npm itself mainly delegates this task to node-gyp, so we could do the same.
That said: build scripts don’t actually have to use node-gyp. So what we really want here is the ability to run arbitrary package scripts, including build and rebuild — hence we also want the @npmcli/run-script package.
Creating tags and commits
Publishing a Pulsar package is quite different from publishing an NPM package, so publish.js doesn’t actually call npm publish. But it does leverage npm version to handle the chore of bumping a version number and generating a Git commit and tag.
This doesn’t have a direct analog in library form. But the version incrementing is simple enough as to be achievable via the semver library, and the Git-related tasks are straightforward as well. We could just shell out to git for those, since we require it for package publishing anyway.
What benefits does this feature provide?
Atom never seemed to have their own fork of npm — so why did we have to fork it? The original PR says it was to allow us to bump node-gyp to 9.4.
I don't have enough context to know why forking was necessary to achieve that goal. But I do know that ppm also depends directly on node-gyp, so it would make things simpler if we didn't have to bump it in two different places.
Any alternatives?
Not realistically. The options are the status quo (ad-hoc usage of npm for all its management tasks) and the more modern approach of relying on single-purpose libraries that offer more hygienic access to the same functionality.
Other examples:
No response
Have you checked for existing feature requests?
Summary
ppmrelies onnpmto do a lot of grunt work. But sinceppmbundles its own Node, it also must bundle its ownnpm.For reasons that I’m sure are complex and better left to @DeeDeeG to explain (or decide not to explain to avoid exhaustion), we maintain our own fork of the
npm-clirepository. Of the commits that exist in that repo, I can identify ten that are definitely unique to our fork, and they suggest that the reasons to maintain an ongoing fork ofnpm-cliincludenode-gypoccasionally, andlibnpm,libcipm, andnpm-lifecycle(three dependencies ofnpm-clithat are themselves deprecated in favor of packages I'll mention below).This is not the world’s most onerous chore, but there’s only one of @DeeDeeG, and I’d love to use their talents as politely as possible.
Can we outright eliminate dependence on
npm? Let’s think it through.How do we use NPM?
These are the places in the codebase I can identify where we explicitly shell out to
npm:ci.jsshells out tonpm ciclean.jsshells out tonpm pruneconfig.jsshells out tonpm configdedupe.jsshells out tonpm dedupeinstall.jsshells out tonpm installpublish.jsshells out tonpm versionrebuild.jsshells out tonpm rebuildThere are other places where we use
npmmore like a library —require('npm'), then call methods on it — but these mainly involve reading configuration. Usingnpmin this manner is also deprecated and is worth replacing if we can.So we can group these into tasks and then figure out other ways to accomplish the same tasks:
Dependency installation/cleanup
ci.jsandinstall.jsusenpmfor managingnode_modulesand reconciling it withpackage.json. We can usearboristfor this; see #159.arboristcan also probably do the stuff done bynpm prune, and I imagine bynpm dedupeas well.Reading NPM configuration
config.jsdelegates tonpmfor reading from and writing to configuration, sinceppmhas a need for many of the configuration keys thatnpmdoes, and wants to manage them the same way.We could instead manage this with
@npmcli/config.Building/rebuilding modules
ppmfamously needs to compile packages with native module dependencies, so that’s why it shells out tonpm rebuild. Butnpmitself mainly delegates this task tonode-gyp, so we could do the same.That said: build scripts don’t actually have to use
node-gyp. So what we really want here is the ability to run arbitrary package scripts, includingbuildandrebuild— hence we also want the@npmcli/run-scriptpackage.Creating tags and commits
Publishing a Pulsar package is quite different from publishing an NPM package, so
publish.jsdoesn’t actually callnpm publish. But it does leveragenpm versionto handle the chore of bumping a version number and generating a Git commit and tag.This doesn’t have a direct analog in library form. But the version incrementing is simple enough as to be achievable via the
semverlibrary, and the Git-related tasks are straightforward as well. We could just shell out togitfor those, since we require it for package publishing anyway.What benefits does this feature provide?
Atom never seemed to have their own fork of
npm— so why did we have to fork it? The original PR says it was to allow us to bumpnode-gypto9.4.I don't have enough context to know why forking was necessary to achieve that goal. But I do know that
ppmalso depends directly onnode-gyp, so it would make things simpler if we didn't have to bump it in two different places.Any alternatives?
Not realistically. The options are the status quo (ad-hoc usage of
npmfor all its management tasks) and the more modern approach of relying on single-purpose libraries that offer more hygienic access to the same functionality.Other examples:
No response