Chris W. Chris W. - 1 year ago 99
Node.js Question

How do I override nested dependencies with `yarn`?

If my package has these dependencies

{ "name": "my-package",
"dependencies": { "foobar":"~1.0.3", "baz":"2.0.9" }


And the
foobar
package has these dependencies

{ "name": "foobar",
"dependencies": { "baz":"^2.0.0" }


and the most recently released version of
baz
is
2.1.0
, the first run of
yarn
will install in
foobar/node_modules
.

How do I force yarn to use the package for
foobar
?

My understanding is that this would be possible using
npm shrinkwrap
(a la this question).




The summary of my question probably is: Yarn creates repeatable, deterministic installations, but how do I customize that installation?

Answer Source

If you do in fact have a sub-dependency that is overly restrictive in what versions it will accept, you can override them using yarn. It sounds like the original question wasn't exactly correct, but the original question was in fact the one I wanted answered, and I found an answer, so here it is for posterity:

I'm using the socket.io library, and it has component-emitter as a dependency. But it has a pair of versions that it requires. This is what the yarn.lock file looked like before I changed anything:

[email protected]:
  version "1.1.2"
  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3"

[email protected]:
  version "1.2.0"
  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.0.tgz#ccd113a86388d06482d03de3fc7df98526ba8efe"

So it was including two copies of the component emitter in my client code. I looked, and there didn't appear to be any breaking changes between 1.1.2 and 1.2.0 (or 1.2.1, which was current). I first tried just changing the yarn.lock file:

[email protected], [email protected]^1.2.1, [email protected]:
  version "1.2.1"
  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"

This worked, but the file has warnings about it being autogenerated, meaning that every single update or new package I add will stomp on this change. A bit of searching found the yarn --flat option, which will force yarn to choose no more than one of each package in the entire project. That seems like overkill to me, since I'm sure there are actual cases of incompatibility between older and newer packages. I just wanted to eliminate a redundant package from my client code, to make the download smaller; I still want the development packages to all work correctly.

But in the docs to yarn --flat I found a reference to a "resolutions" block that can go in package.json:

"resolutions": {
  "package-a": "2.0.0",
  "package-b": "5.0.0",
  "package-c": "1.5.2"
}

So I tried putting "component-emitter" : "1.2.1" in a new "resolutions" block in my package.json, and it in fact flattened component-emitter to 1.2.1 for all places that required it, and now I have only one copy in my client code.

EDIT: It appears that you need to do both: Modify yarn.lock and add the resolutions section. This time I was overriding a typescript dependency in the package typescript-json-schema, which was had a dependency on ~2.0.10, but I needed support for TypeScript 2.1 features...seems to work fine with the new override in place.

Note that adding a resolutions section for TypeScript didn't flatten all references to TypeScript: There's another package that depends on TypeScript 1.8.x, and it's still included at that version. So you can mix-and-match repository flattening this way. And my original component-emitter override has survived many yarn updates and package adds, so it seems to all work.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download