RFC: package manifest extensions#889
Conversation
|
@owlstronaut what does the team think about this? This one is essential for isolated mode to work with packages with phantom dependencies. We are already seeing blockers for our migration to isolated mode in Gutenberg. I will be more than happy to draft a PR to the CLI repo. |
owlstronaut
left a comment
There was a problem hiding this comment.
I like the shape of this. A couple comments.
Thank you for the review @owlstronaut. On a side note, I would also like to ask a broader design question before going too far down the declarative path: would the npm team be open to adopting an imperative, root-owned manifest hook API, similar to pnpm's The current RFC intentionally proposes a declarative v1 because it is easier to validate, lock, audit, explain, and keep deterministic under An imperative Would maintainers prefer that this RFC stay focused on declarative |
|
Here is the implementation PR npm/cli#9496 The reason for the above question about imperative API, is that the list in the package.json can get too long. For example, while testing the implementation in Gutenberg, here is what the list looked like 😄
|
4e4daf7 to
463cd08
Compare
|
@manzoorwanijk for a package the size of Gutenberg only having that size of a list, it makes me like the declarative even more. The package.json is ugly, but that's among the worst it'll get and is a lot safer. We can always revisit |
True. We can revisit this later. Some benefits of an imperative API are that you can:
|
|
If this is going to go in package.json, then it probably shouldn't work in packages that don't have private:true, since it'll greatly inflate the size of the packument. |
Good point. Since There is precedent from the native dependency patching work: Would it be acceptable for this RFC to require the same publishing behavior for That would let public packages use |
|
Failing seems better, since it more firmly establishes that it's only for apps. If we want packages to use it, I think it needs to go somewhere other than package.json. |
One concern with failing For example, a public library may have a single root Should this RFC intentionally make that unsupported because |
|
If that's a use case we want to support, then imo we must provide a non-package.json place to store this config. Until that time, that use case is simply not permitted. |
Then in that case, the imperative API seems more compelling. |
|
Since the imperative API needs its own RFC (IMHO), for this RFC, we can simply err in case a non-private package contains |
|
That's definitely the most futureproof approach - even if we decide to simply remove the restriction in the future. Adding features for private packages only is FAR FAR less dangerous than adding any feature for published packages. |
|
Alright, the implementation PR is also updated with the same - npm/cli@8803bd7 |
Summary
Adds an RFC for root-owned
packageExtensions, a declarative v1 package metadata repair mechanism for npm installs.The proposal lets a project add or correct third-party package manifest fields that affect dependency graph construction before Arborist finalizes the ideal tree:
dependenciesoptionalDependenciespeerDependenciespeerDependenciesMetaMotivation
install-strategy=linkedmakes dependency boundaries stricter by avoiding accidental hoisting. That is useful for correctness, but it also exposes packages that import dependencies or type packages they did not declare. Today users often work around those issues by relying on hoisting, adding root dependencies, patching packages after extraction, or maintaining forks. Those options either do not work under linked installs or operate at the wrong phase of installation.RFC 0042: Isolated mode anticipated this exact problem space:
It also described the older workaround:
That workaround is not enough for
install-strategy=linked, because a root dependency does not become visible inside the isolated dependency boundary of the package that actually imports it.This RFC proposes a root-only, deterministic way to record small third-party manifest repairs while upstream packages catch up. It intentionally scopes v1 to declarative metadata repairs rather than arbitrary install-time manifest hooks.
Why declarative v1
An imperative hook model, similar to pnpm's
.pnpmfile.mjs, could solve a broader class of manifest transformation problems. This RFC proposes the declarative subset first because the linked-install migration cases are mostly small dependency metadata repairs, and a declarative model is easier to validate, lock, audit, explain, and remove once upstream packages are fixed.Notable semantics
packageExtensions.nameandversion, not install path.npm civalidates the canonical extension hash, selector conflicts, and minimal lockfile provenance before trusting locked effective metadata.package.jsonis not rewritten.Prior art
The RFC compares this proposal with pnpm
packageExtensions, pnpm.pnpmfile.mjshooks, YarnpackageExtensions,@yarnpkg/extensions, npmoverrides, npm isolated mode, native dependency patching, and install-script policy RFCs.Tests
Not run. This is a docs-only RFC proposal.