TLDR:
When you install dependencies in your
application, only your own yarn.lock file is respected. Lockfiles
within your dependencies will be ignored. Reference
Let's get some things cleared first:
--pure-lockfile
is same as normal yarn install except that it won't generate a yarn.lock
file or update one if present.
- Yarn always reads from the
yarn.lock
by default for resolving dependencies while installing unless supplied with --no-lockfile
. So, there is no need to tell it to read from yarn.lock
.
What is yarn.lock
used for?
yarn.lock
is used for resolving what version
should be fetched
given the semver version
of a module in package.json
. It is not used to determine what semver version
should a module be resolved to. That is simply not its use-case.
As mentioned in yarn DOCS: In order to get consistent
installs across machines, Yarn needs more information than the
dependencies you configure in your package json.. Yarn needs to store
exactly which versions of each dependency were installed.
To do this Yarn uses a yarn.lock
file in the root of your project.
So, for resolving semver version
of a dependency, yarn always depends on package.json
. For a given semver version
, yarn checks the yarn.lock
file to see what version
should it fetch. This is what makes yarn Deterministic (Same tecknique is used by npm
which uses npm-shrinkwrap.json
).
Example: Semver Versions like ^1.2.4
can resolve to any version number which is >= 1.2.3 and < 2.0.0
. Without yarn, npm would install 1.2.4
in one machine but 1.9.9
in some other machine, depending on the latest version present at the time of install. This is the problem that yarn solves using yarn.lock
.
The semver version
is determined by the
package.json
file. The yarn.lock
file is only a lookup for which
version and commit hash to install for the given semver version
number.
How does yarn resolve version of a module given its semver version?
Suppose currently our yarn.lock file looks like this:
bluebird@2.9.6:
version "2.9.6"
resolved "https://<...>/bluebird-2.9.6.tgz#1fc3a6b1685267dc121b5ec89b32ce069d81ab7d"
bluebird@^2.9.30:
version "2.11.0"
resolved "https://<...>/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
...
myModule@5.1.0:
version "5.1.0"
resolved "https://<...>/moduleA-5.1.0.tgz#ce97130858add59d616ee80675383b0c127290a0"
dependencies:
bluebird "^1.0.0"
- If package.json has
bluebird: "^2.9.30"
, yarn looks for an entry bluebird@^2.9.30
in the lockfile. It is present and hence is resolved to version=2.11.0
.
- If package.json has
bluebird: "^2.9.0"
, yarn looks for an entry bluebird@^2.9.0
in the lockfile. It is not present. Suppose the latest stable version which satisfies semver criteria is 2.13.0
, then yarn adds an entry for bluebird@^2.9.0
, resolved to 2.13.0
. While resolving version for a given semver version
of bluebird, it does not matter what entry is present for bluebird in moduleA's dependencies in the lockfile.
Semver Version
is not affected by what entries are
present in the dependencies map for a module in yarn.lock
file.
So, if package.json has bluebird: ""
, yarn looks for an entry bluebird@
in the lockfile but is unable to find it. Hence, it resolves bluebird: ""
to the latest version, suppose 3.5.0
. Now, yarn will add an entry for bluebird@
resolved to 3.5.0
.
bluebird@:
version "3.5.0"
resolved "https://<...>/bluebird-3.5.0.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
Form now on whenever yarn encounters {bluebird: ""}
, it will find an entry for bluebird@
in the lockfile and hence will always resolve it to 3.5.0
.
Solution to your problem
To resolve B: ""
to version say 1.0.0
, you need to have an entry for B@
in yarn.lock
resolved to 1.0.0
. Once, yarn.lock
has an entry for B@
, all the successive installs will always fetch version 1.0.0
for B=""
.
Following are the steps you need to take to accomplish the same:
Approach 1 (Recommended)
If you want B to resolve to latest version:
- Add
B:""
in A's package.json
- Run
yarn install
. This will add an entry for B@
resolved to latest version.
- Push
yarn.lock
file.
- Form now on, whoever runs
yarn install
will get the same version.
Approach 2
If you want B to have an older version: (Highly Not Recommended)
- Add
B: 1.0.0
in A's package.json.
- Run
yarn install
. This will add an entry B@1.0.0
in the lockfile.
- Add
B@
alongside B@1.0.0
in yarn.lock. B@, B@1.0.0: ...
- Change B's version to
""
in A's package.json.
- Push
yarn.lock
file.
- Form now on, whoever runs
yarn install
will get the B's version as 1.0.0
.
This approach is highly dangerous as you can break something easily. Your yarn.lock file should always be managed by yarn.
Approach 3 (Recommended)
If you want B to stay at 1.0.0
- Fix B's version to
1.0.0
in A's package.json.
- Run
yarn install
. This will add an entry B@1.0.0
in the lockfile.
- Push yarn.lock file
- Form now on, whoever runs
yarn install
will get the B's version as 1.0.0
.
Edit: Using the yarn.lock file present in the dependencies
If you check this doc:, they have clearly mentioned that yarn will use only the top level yarn.lock file and ignore the lock files present in the dependencies.
There is currently no way of locking down second level dependencies using yarn.lock present in them. I don’t see any need for it. In fact the creators of yarn explain here why that is the case. The reasons being:
- The versions to be installed for second level dependencies can be
captured well by the top-level yarn.lock file, as I have explained
above.
- You would never be able to update the versions of sub-dependencies in your own application when using them directly because they would be locked by other yarn.lock files. You can verify this point by my explanation of how yarn resolves dependencies.
- Yarn would never be able to fold (de-duplicate) dependencies so that compatible version ranges only install a single version.
Also, as in your use-case, if A has a dependency B which works only with version 1.0.0
, A’s package.json should have version mentioned for B as 1.0.0
and not “”. You can always fix your top-level yarn.lock
to add an entry for B@
resolved to 1.0.0
but it is not recommended to manually fix a yarn.lock file as I have mentioned above.
Hope this helped! Please ping me in the comments for any doubts.