/** * @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 ` * 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"`);