pnpm: pnpm patch does not seem to work with workspaces
I am attempting to patch a transitive dependency which is in the dependency tree of multiple workspaces. In this example, the dependency is extract-files@9.0.0
.
From the workspace root, I run pnpm patch extract-files@9.0.0
which gives me the temporary folder link as expected. I open the folder and make the necessary changes. After completing I run pnpm patch-commit <path>
which generates the patch file in the root patches
folder, adds a pnpm.patchedDependencies
property to the root package.json
, and adds a patchedDependencies
section at the top of the pnpm-lock.yaml
file. However, it does not alter any of the references to that dependency elsewhere in the lockfile, and as a result, the versions being used by the workspaces are unchanged.
I revert all changes and then tried making my current working directory one of the workspace folders. I follow the same exact procedure described above and the end result is different. The patches
folder is still added to the root, the root package.json
still has the pnpm.patchedDependencies
property, and the patchedDependencies
section is added to the top of the pnpm-lock.yaml
file. However, this time the lockfile has also been modified to patch the versions of that dependency relative to that workspace. My initial thought here is that the patch needs to be applied one workspace at a time.
I then change my current working directory to another workspace. I repeat the process. This time the temporary folder already shows the patch (this seems expected). I try committing the patch but there is no change. The patch was not applied to that workspace.
Basically what I’m looking to have happen here is to either apply the patch to all workspaces or at least have a procedure where I can patch each workspace one a time. Ideally something like:
pnpm -r patch dependency@version
or pnpm --filter=<workspace> patch dependency@version
It’s definitely possible that I’m doing something wrong here so if there is a procedure that should be taken to make this happen please let me know.
Possibly related issue: #5255
pnpm version:
7.26.3
Code to reproduce the issue:
Expected behavior:
Patches all versions of the dependency
Actual behavior:
Does not patch any versions of the dependency
Additional information:
node -v
prints: v16.16.0- Windows, macOS, or Linux?: Windows
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 1
- Comments: 23 (7 by maintainers)
Commits related to this issue
- fix: patch-commit should auto apply patches in workspaces (#6120) close #6048 — committed to pnpm/pnpm by await-ovo a year ago
@shawnmcknight I think I reproduced the problem and I will try to solve it
@await-ovo I’ve set up a scenario that should be easier to see the problem. Steps:
main
branch does not have the patch applied.pnpm install
to generate the unpatchednode_modules
git checkout apply-patch
. This branch has the patch applied.pnpm install
. The workspaces’node_modules
will not be updated with the patch.git checkout fixed-lockfile
. This branch has hadpnpm install --fix-lockfile
run on it and the lockfile is in a valid state.pnpm install
. The workspaces’node_modules
will now be updated with the patch.The main difference between this flow and what you originally saw is that the
node_modules
will be populated in an unpatched state. Runningpnpm install
on theapply-patch
branch does not properly apply the patch here because the lockfile is not in a proper state. However, once you runpnpm install
on thefixed-lockfile
branch everything will work properly.I debugged through the workflow differences between
pnpm patch-commit
andpnpm install --fix-lockfile
today to try to determine why fixing the lockfile makes the lockfile correct after the patch has been applied but the original patch commit did not.From what I can tell, the primary difference between the two workflows is that
pnpm install
will default recursive operations and filter to all available workspaces by default due to this logic in the main cli. This ensures that when fixing the lockfile all packages are included in the evaluation. However, since thepatch-commit
command is not included in this condition, no packages filters are added, thus only the root package is included in the processing.I tried changing that line from:
to:
in the hopes that this would allow things to work properly.
That change did make it so all packages were included when the patch-commit workflow called the installer. However, this introduced a different problem because the packages’ manifests were read into variables at the time of filtering. Since
patch-commit
later modifies the root package’s manifest to augment thepnpm.patchedDependencies
property, the in-memory root manifest is now out of sync with the on-disk root manifest. When getOptionsFromRootManifest is called, because the in-memory manifest does not havepatchedDependencies
applied within it, the installer will end up doing nothing. In the existing workflow, the root manifest is read in later in installDeps because there haven’t been any projects previously selected so thepatchedDependencies
property is available. So unfortunately my naïve approach to potentially fixing this didn’t pan out.I don’t know enough about the pnpm codebase to determine how this workflow should be fixed. However, from what I can tell, the
patch-commit
process needs to be able to process all packages but also be aware of the patch being applied to the root manifest file. My best guess would be to add logic after the root manifest had had itspnpm.patchedDependencies
property updated to execute similar filtering logic that is applied when runningpnpm install
to build the options forallProjects
,allProjectsGraph
, andselectedProjectsGraph
to supply toinstall
.@zkochan Does this provide any additional insight into the problem? Does my proposed solution to supply project filters to
install
make sense? I am willing to create a PR to fix this, but I’d like to go down a path that make sense.