Patching packages in Yarn berry
--
At one point, patching a package in Yarn was as simple as yarn patch <package-name>
and following the prompts. Now, it’s riddled with unintuitive bugs. Let’s walk through it.
Patching the package
To prepare the package for patching, run yarn patch <package-name>
. The command output should specify a temporary directory for you to edit. Make the desired changes to the package in that directory, then follow the subsequent command in the output: yarn patch-commit -s <directory>
.
Verifying the results
Once you’ve executed the patch-commit
command, you should now have a .yarn/patches
directory with a file corresponding to your target package name and version.
Additionally, your root package.json
file should now contain a resolutions
property with a <package-name>@<version>
key and patch:<package-name>@npm:<version>::__archiveUrl=<url>#.yarn/patches/<package-name>-npm-<version>-<hash>.patch
value.
This used to be everything you needed to do to patch a package, but you may notice that absolutely no changes occur after yarn install
ing the new patch.
Fixing the range
Unintuitively, Yarn expects the range provided in package.json
's resolutions
key to match the range specified by dependencies
. Typically, this is as simple as changing <package-name>@<range>
to <package-name>@^<range>
, but if the mere ^
does not resolve your issue, you may need to investigate what ranges are used to reference your target package by executing yarn why <package-name>
.
Per the aforementioned GitHub issue, this should be the only change you need to make, but unfortunately this behavior has regressed at some stage in Yarn berry’s development cycle. When you yarn install
now, you will run into this cryptic error:
Error: Patch locators must explicitly define their source
Defining your source
I had the unfortunate pleasure of deep-diving the Yarn berry source code to resolve this. Yarn uses a particularly complex regular expression to parse the value seen in the package.json
’s resolutions
value. At some point, the Yarn team made a breaking change to this parser, but did not change their patch command to match it.
The yarn patch-commit
command created a value of patch:<package-name>@npm:<version>::<search>#<path>
. The new…