Skip to content

Instantly share code, notes, and snippets.

@cdaringe
Created April 13, 2022 18:28
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cdaringe/66c7cd5f95f74766f9eb1e699fdd7399 to your computer and use it in GitHub Desktop.
Save cdaringe/66c7cd5f95f74766f9eb1e699fdd7399 to your computer and use it in GitHub Desktop.
pnpm-patch-package.js
/**
* @description
* Support patch-package in pnpm projects.
*
* `pnpm` can be tricky to use with patch-package. To minimize friction creating patches,
* this script helps automate patching by using npm and a temp workspace to generate
* patch files.
*
* @usage
* 0. ensure the dependencies of interest are top level dependencies/devDependencies (no patching transitive deps)
* 1. pnpm install, then make edits to your dependencies in your node_modules
* 2. edit the below `relativePatchedFilenames`
* 3. run `node <this-script>`
* 4. preview the emitted patch
* 5. use the emitted command to copy the patch into the project
*/
const relativePatchedFilenames = ["node_modules/foo/index.js"];
const path = require("path");
const srcProjectDirname = process.cwd();
const readLocalPkgJson = () => require(path.resolve(srcProjectDirname, "package.json"));
const patchPackageVersion = readLocalPkgJson().devDependencies["patch-package"];
const cp = require("child_process");
const log = (str) => console.log(`[pnpm-pp]`, str);
const cmd = (args, opts) => {
log(args);
cp.execSync(args, { ...opts, stdio: "inherit" });
};
const tempAppDirname = "/tmp/app"; // or os.tmpDir(), whatever
const cmdInPatchApp = (args, opts) => cmd(args, { ...opts, cwd: tempAppDirname });
const pkgUp = (filename) => {
const pkgJsonDirname = path.dirname(filename);
if (pkgJsonDirname === "/") throw new Error(`pkg not found for file`);
const pkgJsonFilename = path.resolve(pkgJsonDirname, "package.json");
try {
const pkgJson = require(pkgJsonFilename);
return pkgJson.name;
} catch {
return pkgUp(pkgJsonDirname);
}
};
const pkgsToPatch = [
...new Set(relativePatchedFilenames.map((relative) => path.resolve(srcProjectDirname, relative)).map(pkgUp)).values(),
];
cmd(`mkdir -p ${tempAppDirname}`);
[
`git init`,
`echo node_modules > .gitignore`,
`npm init -y`,
`rm -rf patches`,
`npm install -DE patch-package@${patchPackageVersion} ${pkgsToPatch.join(" ")}`,
...relativePatchedFilenames.map(
(relative) => `cp "${path.resolve(srcProjectDirname, relative)}" "${path.resolve(tempAppDirname, relative)}"`
),
...pkgsToPatch.map((pkg) => `npx patch-package ${pkg}`),
`ls -al patches`,
].forEach((cmd) => cmdInPatchApp(cmd));
console.log(`\n\nTo accept:\n\tcp ${tempAppDirname}/patches/* "${srcProjectDirname}/patches"`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment