patch-package uses patches with filenames like @scope+pkg+1.2.3.patch and content containing node_modules/ prefixes.
pnpm uses patches with filenames like @scope__pkg@1.2.3.patch and content without node_modules/ prefixes.
Features
Core Flow
- Scans for patch files (default
./patchesdirectory) when processing config files - Normalizes the path, then performs conversion: content rewrite + filename rewrite
- Aggregates results into
patchedDependenciesentries, writes them back to config - Runs
pnpm installautomatically via workflow step to apply the patches
Content Conversion
- Detection: converts only if patch content includes node_modules diff headers (
diff --git a/node_modules/...,-- a/node_modules/...,+++ b/node_modules/...) - Prefix calculation: derives a removal pattern from the patch filename by taking all
+separated parts except the last (version), joining with/, and prefixing with node_modules - Rewrite: globally removes that prefix from the patch content to meet pnpm's expected format
Filename Conversion
- Input naming (patch-package):
<name parts joined by '+'>+<version>.patch - Output naming (pnpm):
<name parts joined by '__'>@<version>.patch - Example:
@scope+pkg+1.2.3.patch→@scope__pkg@1.2.3.patch
Batch vs Single-File Processing
- Directory mode: enumerates all
.patchfiles, then converts each (content + filename) - Single-file mode: validates existence,
.patchextension, presence of+in name, and ensures the target converted file doesn't already exist; then converts - If a patch doesn't need conversion (no node_modules headers), it's skipped
Configuration Updates
Patched Dependencies
For each converted file:
- Key: filename without
.patch, replace__back to/, e.g.<name>/<sub>/...@<version> - Value:
<patchesDir>/<convertedFileName>wherepatchesDiris the directory name containing the patches (e.g.,patches) - Merges these into existing
patchedDependencies, overwriting duplicate keys
Config Files
- Prefers pnpm-workspace.yaml: reads top-level
patchedDependencies, merges new entries, and writes back - Fallback to package.json: updates
pnpm.patchedDependenciesin place if workspace file is absent - Merge strategy: additive with overwrite, preserving unrelated fields
Examples
Before (patch-package)
File: patches/@react-spring+core+9.4.5.patch
diff
After (pnpm)
File: patches/@react-spring__core@9.4.5.patch
diff
Configuration in pnpm-workspace.yaml:
yaml
Error Handling
- Directory mode: errors on non-existent path or non-directory
- Single-file mode: blocks if the converted target file already exists (to avoid overwrite)
- Requires filenames containing
+and ending with.patch; otherwise errors - Normalizes Windows path separators to
/where relevant (regex and key generation)