IMPLEMENTED in npm/cli#3.
This proposal introduces a new package alias system that allows installation of
packages with names other than the ones in package.json
, as well as a new
dependency type that allows referencing registry-hosted packages when using this
system. In short, this feature implements the corresponding feature in
Yarn and is
intended to be mostly compatible with their implementation.
This was previously proposed back in 2012 and definitively shot down, again, and again.
This was a fairly reasonable response back then, when npm was expected to be for node modules themselves -- nesting largely prevents the need for this kind of aliasing. While it can be somewhat inconvenient, it's still possible, and it doesn't seem to have stopped the ecosystem from growing as fast as it did. The simplicity of the npm model has been pretty good to us this whole time.
Enter 2018, and we've started working on npm asset
. After many conversations
about it (with @isaacs nonetheless!) the CLI team finally decided to go ahead
with this feature. Having the Yarn implementation around was a good reference
when deciding how to actually do this and totally helped make a case for it!
This will occur on two levels: one, a new spec type, alias
will be added, to
represent the npm:<pkg>
part. The bigger change, though, will be allowing npm
to install any package under a different name, regardless of package type, and
use the specific name provided when it adds it to node_modules
. That is, npm install foo@github:zkat/bar
will always install into a directory called foo
,
as will npm install foo@npm:bar
and npm i foo@../bar
.
Furthermore, package IDs (used when comparing packages), will take aliases into account. For a package to be considered equivalent by npm, it must match BOTH the package name and version AS WELL AS the physical directory name it was installed under. This will take care of blocking aliases from injecting transitive dependencies.
Pretty much since the dawn of npm's time, there's been the question of "how do I install a package under this separate name?" -- be it for using git forks as replacements, or forked npm packages as replacements. This question is older than npm scopes themselves, so we've had some developments since the choice was originally made.
There is no good, easy way to do this. You can, of course, craft special packages that re-export everything under a different name and install those, but that seems less than ideal in a lot of situations.
The main use-cases for something like this seem to be:
- installing multiple versions of a same-name package side-by-side (
npm i jquery3@npm:jquery@3 jquery2@npm:jquery@2
-> installsnode_modules/jquery(2|3)
- installing a registry-published fork under the name of the original package (
npm i npm@npm:@zkat/npm
) - shorter, more convenient import names for packages that are otherwise longer than desired (
npm i npa@npm:npm-package-arg
)
This RFC should solve all three of those problems.
There are other, related problems that this RFC will NOT address:
- replacing packages in transitive dependencies that have different names (
npm i underscore@npm:lodash
will only make it sorequire('underscore')
in your own project loadslodash
instead. Your dependencies will receive their own (nested) version of the actualunderscore
package). This may be covered in the future by an explicit resolutions mechanism, and may be facilitated by this RFC, but is still not part of it. - circumventing package naming restrictions (
npm i UpdateNotifier@npm:update-notifier
is invalid because CamelCased names are invalid. npm will continue to refuse installing anything in your filesystem that violates these expectations, because they can cause serious filesystem conflicts and other breakage) - others?
I'm working on an implementation of this over in a branch right now, and it's a lot, and I don't know how to write all that down right now.
The only prior art I'm aware of is Yarn's aliasing feature, which, as far as I can tell, is entirely undocumented. I can't really tell what the gotchas are with their own specifics.