patch-package README

The project's README from github.com/ds300/patch-package. As one markdown file: README.md.

patch-package

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.

# fix a bug in one of your dependencies
vim node_modules/some-package/brokenFile.js

# run patch-package to create a .patch file
npx patch-package some-package

# commit the patch file to share the fix with your team
git add patches/some-package+3.14.15.patch
git commit -m "fix brokenFile.js in some-package"

Patches created by patch-package are automatically and gracefully applied when you use npm(>=5) or yarn.

No more waiting around for pull requests to be merged and published. No more forking repos just to fix that one tiny thing preventing your app from working.

Set-up

In package.json

 "scripts": {
+  "postinstall": "patch-package"
 }

Then

npm

npm i patch-package

You can use --save-dev if you don't need to run npm in production, e.g. if you're making a web frontend.

yarn v1

yarn add patch-package postinstall-postinstall

You can use --dev if you don't need to run yarn in production, e.g. if you're making a web frontend.

To understand why yarn needs the postinstall-postinstall package see: Why use postinstall-postinstall

yarn workspaces

Same as for yarn ☝️ Note that if you want to patch un-hoisted packages you'll need to repeat the setup process for the child package. Also make sure you're in the child package directory when you run patch-package to generate the patch files.

yarn v2+

yarn 2+ have native support for patching dependencies via yarn patch. You do not need to use patch-package on these projects.

pnpm

pnpm has native support for patching dependencies via pnpm patch. You do not need to use patch-package on these projects.

Heroku

For patch-package to work on Heroku applications, you must specify NPM_CONFIG_PRODUCTION=false or YARN_PRODUCTION=false. See this issue for more details.

Docker and CI

CircleCI

Create a hash of your patches before loading/saving your cache. If using a Linux machine, run md5sum patches/* > patches.hash. If running on a macOS machine, use md5 patches/* > patches.hash

- run:
    name: patch-package hash
    command: md5sum patches/* > patches.hash

Then, update your hash key to include a checksum of that file:

- restore_cache:
    key:
      app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash"
      }}

As well as the save_cache

- save_cache:
    key:
      app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash"
      }}
    paths:
      - ./node_modules

Usage

Making patches

First make changes to the files of a particular package in your node_modules folder, then run

yarn patch-package package-name

or use npx (included with npm > 5.2)

npx patch-package package-name

where package-name matches the name of the package you made changes to.

If this is the first time you've used patch-package, it will create a folder called patches in the root dir of your app. Inside will be a file called package-name+0.44.0.patch or something, which is a diff between normal old package-name and your fixed version. Commit this to share the fix with your team.

Options

Nested packages

If you are trying to patch a package at, e.g. node_modules/package/node_modules/another-package you can just put a / between the package names:

npx patch-package package/another-package

It works with scoped packages too

npx patch-package @my/package/@my/other-package

Updating patches

Use exactly the same process as for making patches in the first place, i.e. make more changes, run patch-package, commit the changes to the patch file.

Applying patches

Run patch-package without arguments to apply all patches in your project.

Options

Notes

To apply patches individually, you may use git:

git apply --ignore-whitespace patches/package-name+0.44.2.patch

or patch in unixy environments:

patch -p1 -i patches/package-name+0.44.2.patch

Dev-only patches

If you deploy your package to production (e.g. your package is a server) then any patched devDependencies will not be present when patch-package runs in production. It will happily ignore those patch files if the package to be patched is listed directly in the devDependencies of your package.json. If it's a transitive dependency patch-package can't detect that it is safe to ignore and will throw an error. To fix this, mark patches for transitive dev dependencies as dev-only by renaming from, e.g.

package-name+0.44.0.patch

to

package-name+0.44.0.dev.patch

This will allow those patch files to be safely ignored when NODE_ENV=production.

Creating multiple patches for the same package

💡 This is an advanced feature and is not recommended unless you really, really need it.

Let's say you have a patch for react-native called

If you want to add another patch file to react-native, you can use the --append flag while supplying a name for the patch.

Just make you changes inside node_modules/react-native then run e.g.

npx patch-package react-native --append 'fix-touchable-opacity'

This will create a new patch file while renaming the old patch file so that you now have:

The patches are ordered in a sequence, so that they can build on each other if necessary. Think of these as commits in a git history.

Updating a sequenced patch file

If the patch file is the last one in the sequence, you can just make your changes inside e.g. node_modules/react-native and then run

npx patch-package react-native

This will update the last patch file in the sequence.

If the patch file is not the last one in the sequence you need to use the --rebase feature to un-apply the succeeding patch files first.

Using the example above, let's say you want to update the 001+initial patch but leave the other patch alone. You can run

npx patch-package react-native --rebase patches/react-native+0.72.0+001+initial.patch

This will undo the 002-fix-touchable-opacity patch file. You can then make your changes and run

npx patch-package react-native

to finish the rebase by updating the 001+initial patch file and re-apply the 002-fix-touchable-opacity patch file, leaving you with all patches applied and up-to-date.

Inserting a new patch file in the middle of an existing sequence

Using the above example, let's say you want to insert a new patch file between the 001+initial and 002+fix-touchable-opacity patch files. You can run

npx patch-package react-native --rebase patches/react-native+0.72.0+001+initial.patch

This will undo the 002-fix-touchable-opacity patch file. You can then make any changes you want to insert in a new patch file and run

npx patch-package react-native --append 'fix-console-warnings'

This will create a new patch file while renaming any successive patches to maintain the sequence order, leaving you with

To insert a new patch file at the start of the sequence, you can run

npx patch-package react-native --rebase 0

Which will un-apply all patch files in the sequence. Then follow the process above to create a new patch file numbered 001.

Deleting a sequenced patch file

To delete a sequenced patch file, just delete it, then remove and reinstall your node_modules folder.

If you deleted one of the patch files other than the last one, you don't need to update the sequence numbers in the successive patch file names, but you might want to do so to keep things tidy.

Partially applying a broken patch file

Normally patch application is atomic per patch file. i.e. if a patch file contains an error anywhere then none of the changes in the patch file will be applied and saved to disk.

This can be problematic if you have a patch with many changes and you want to keep some of them and update others.

In this case you can use the --partial option. Patch-package will apply as many of the changes as it can and then leave it to you to fix the rest.

Any errors encountered will be written to a file ./patch-package-errors.log to help you keep track of what needs fixing.

Benefits of patching over forking

When to fork instead

Isn't this dangerous?

Nope. The technique is quite robust. Here are some things to keep in mind though:

Why use postinstall-postinstall with Yarn?

Most times when you do a yarn, yarn add, yarn remove, or yarn install (which is the same as just yarn) Yarn will completely replace the contents of your node_modules with freshly unpackaged modules. patch-package uses the postinstall hook to modify these fresh modules, so that they behave well according to your will.

Yarn only runs the postinstall hook after yarn and yarn add, but not after yarn remove. The postinstall-postinstall package is used to make sure your postinstall hook gets executed even after a yarn remove.

License

MIT

Empowered by Futurice's open source sponsorship program

patch-package (ds300/patch-package)

Searching Database…

这是什么?patch-package 让你可以直接修改 node_modules 中某个包里的文件,并把这些修改保存为一个补丁文件。之后每次 npm 或 yarn 重新安装该包时,这个补丁都会自动重新应用。
它是构建工具之类的东西吗?不是。它是一个小型命令行工具,不是构建工具或打包工具:它为 node_modules 中的包生成并应用差异文件。
怎么修复一个有问题的包?直接编辑 node_modules/package-name 中的文件,然后运行 npx patch-package package-name(或 yarn patch-package)。它会创建一个 patches/ 文件夹,里面有一个 .patch 文件,需要提交到版本库。之后每次安装时,补丁都会通过 postinstall 钩子自动应用。
除了 npm 或 yarn,还需要别的东西吗?只需要 Node >=14 以及 npm>5 或 Yarn v1;如果使用 Yarn v1,还需要添加 postinstall-postinstall 包,这样执行 yarn remove 之后 postinstall 钩子仍然会运行。
patch-package 能用于 Yarn 2+ 或 pnpm 吗?不能。Yarn 2+ 和 pnpm 自带原生的补丁功能(yarn patch、pnpm patch),不需要这个工具。另外要注意,如果 devDependency 的补丁没有改名为 .dev.patch,可能会导致生产环境安装出错;Docker 或 CI 缓存也需要包含 patches 文件夹。
在 Linux、macOS 和 Windows 上使用效果一样吗?只要 Node、npm 或 yarn 能运行的地方,它都能跨平台使用。README 只提到一个小差异:用于 CircleCI 缓存的 md5sum 命令,在 macOS 和 Linux 上略有不同。
为什么要给包打补丁,而不是 fork 它?Fork 通常需要额外的构建步骤,而且你的修复可能会悄悄与原版脱节。而补丁会和你平时的 PR 流程一起审查,与依赖它的代码放在一起;如果底层包的改动破坏了你的修复,它还会直接报错。
能给嵌套或带作用域的依赖打补丁吗?可以。用斜杠分隔包名,例如 npx patch-package package/another-package;带作用域的包则写成 npx patch-package @my/package/@my/other-package。
如果同一个包需要多个独立的补丁,该怎么办?使用 --append 参数,可以创建一系列带编号的补丁文件(类似提交记录);使用 --rebase 则可以安全地更新某个补丁,或把补丁插入到这一系列的中间。
如果想要干净的 node_modules,怎么撤销补丁?运行 patch-package --reverse 可以撤销所有补丁。但如果打过补丁的文件之后有过变动,这个命令会失败,这时只需重新安装 node_modules 即可。
What are similar projects?composer, renovate, pnpm, npm-check-updates, Inquirer.js, rye, pip, tsdx
Creator
ds300
Size
2.3 MB
Stars
11.2K
Age
9y
Commits · 90 Days