What is the proper way to "patch" a node_modules module?
Asked Answered
C

2

10

Say I have a Node.js app, lets call it patched-app. This app is a simple app that uses prompt-sync to ask for user input and then does something with it.

So we create a folder patched-app and initialize it with npm init. We then run npm i prompt-sync and create a new file called index.js where my code would be. To make things a little bit more interesting, I will also create a git repository here and this is the result:

+---patched-app
|   |   .gitattributes
|   |   .gitattributes
|   |   .gitignore
|   |   index.js
|   |   package-lock.json
|   |   package.json
|   |   
|   +---node_modules
|   |   |   .package-lock.json
|   |   |   
|   |   +---ansi-regex
|   |   |       index.js
|   |   |       license
|   |   |       package.json
|   |   |       readme.md
|   |   |       
|   |   +---prompt-sync
|   |   |       index.js
|   |   |       LICENSE
|   |   |       package.json
|   |   |       README.md
|   |   |       test.js
|   |   |       
|   |   \---strip-ansi
|   |           index.d.ts
|   |           index.js
|   |           license
|   |           package.json
|   |           readme.md
|   \---.git
|      <<git stuff>>

Now the issue here is that I don't like something with this prompt-sync package and so I want to edit node_modules/prompt-sync/index.js and change it to my liking. I don't necessarily want to create a whole new module such as prompt-sync-swiffy (or do I?), as my changes are small enough so I don't have to download any new packages for prompt-sync, so I'm good with the existing dependencies of ansi-regex and strip-ansi.

I could just open up node_modules/prompt-sync/index.js, edit it and be done - and that's what I have pretty much been doing thus far because I don't know any better. I have recognized at least three major issues with this though:

  • I cannot update prompt-sync anymore or I might lose the changes I made (losing !== just breaking my patched changes)
  • I cannot basically run any package commands, such as npm audit fix etc, as those might also overwrite my changes
  • This doesn't work at all, if I want to have my project in a git repository, because I will obviously add node_modules to .gitignore and if anyone were to pull my repository and run npm install, it would install prompt-sync without my changes

I also don't necessarily want to fork prompt-sync and / or create a new "official" NPM package. What I want is a method that allows me or anyone else to run npm install normally, while somehow keeping my patches to modules local e.g. have a module_patches folder which isn't ignored by the repository.

It is OK if a newer version of prompt-sync breaks my patch. That would be on me to update the patch or use a locked in version of prompt-sync.

So what are my options?

Conquest answered 30/6, 2022 at 18:41 Comment(1)
Hey just patch it and keep a copyTantra
R
19

A nice way to patch NPM packages is using patch-package. It will automatically create patch files of your changes and apply them in postinstall hook.

Romanticism answered 1/7, 2022 at 8:5 Comment(2)
Well that's funny, this is exactly 100% what I was looking for! It makes separate .patch-files, auto-applies them, works with git-repositories and I can target exact packages and even package version with this. Excellent work, thanks for finding this for me!Conquest
why haven't I found this 2 years earlier?Snowy
I
6

Patch a "node_modules" (Node.js) module

Patch-package lets app authors instantly make and keep fixes to npm dependencies. It's a vital band-aid for those of us living on the bleeding edge.

Process

Fix a bug in one of your dependencies

MODEL

nano "node_modules/<PACKAGE_NAME>/some_file.js"

Run patch-package to create a "*.patch" (in "patches" folder) file

MODEL

npx patch-package "<PACKAGE_NAME>"

Required settings/resources in your "package.json"

For patches to be applied during installation, these settings/resources are necessary in your "package.json".

  [...]
  "dependencies": {
    [...]
    "patch-package": "X.X.X",
    "postinstall-postinstall": "X.X.X",
    [...]
  },
  [...]
  "scripts": {
    [...]
    "postinstall": "patch-package"
  },
  [...]

Ref(s):

Thanks! 😘

Integrated answered 29/10, 2023 at 20:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.