patch-package 实现原理:如何保存恢复 node_modules 下的代码改动?

网站建设3年前发布
44 0 0

有时候我们需要修改 node_modules 下的一些代码,但是 node_modules 不会提交到 git 仓库,改动保存不下来,怎么办呢?,这时候可以用 patch-package 这个工具。,比如我对 node_modules 下的 acorn 代码做了一些修改:,加了一个 a.js 的文件:,202303060050237165642063ed1a0808198829008ee4c9be1e1f916,在项目目录下执行 npx patch-package acorn 之后,就会生成这样一个目录:,2023030600502352f780a49d8ced879664961494aa3bd6678c8f370,在 patches 目录下的 xx.patch 文件里记录着对这个包的改动。,这个 patches 目录是可以提交到 git 仓库的,然后再次把项目拉下来的时候,执行下 npx patch-package 就会应用这次改动。,可以把它配到 postintsll 里,每次安装完依赖自动跑。,20230306005255d3c0cb2520291798d66642ea0ef0f8e76b560d153,这样能保证每次拉取下来的代码都包含了对 node_modules 的改动。,如何使用我们学会了,那它是怎么实现的呢?,探究它的实现原理要分为两各方面,一个是 patches 文件怎么生成的,一个是 patches 文件怎么被应用的。,patches 文件怎么生成的,看 patches 文件的内容就能看出来这是 git 的 diff:,2023030609521575c51d337e6069e72ce507a366235a16713e24437,确实,patch-package 就是依赖 git diff 实现的 patches 文件生成。,首先 patch-package 会创建一个临时目录:,2023030600570087fd8d0270b165baea06948e6a00f57c8b28b2540,然后在这个目录写入一个 package.json 文件,dependencies 就是命令行参数指定的包名:,20230306005701a826b2e534e99b49478479a95b125e195974cc105,我们去这个目录看一下:,2023030600525707bd3458888166dffef9126f16f10f1eaa28c1389,确实,是有这样一个 package.json 的。,然后它会在这个目录下执行 yarn install 或者 npm install(patch-package 现在不支持 pnpm):,2023030600570146d841b96824ec74036396d15f43df644e0b04408,20230306005026b73b9772418b5b8b38b656b24c9aecf57535c7862,之后就进行 git 的 init、add、commit,生成一个基础的 commit。,20230306005026e42c73848124c1ec7c582301d4a2cf9e7eab97939,然后把现在 node_modules 目录下的这个被修改过的包复制过去:,2023030600502719f5e334038699f030b161de93f2a30718ca95915,之后再 git add,然后执行 git diff,就能拿到改动的 diff:,20230306005028686e17e2684671c08f670026addaa480241fc5560,这不就是 patches 文件的内容么:,20230306005028d2f0edc3481f9fc7329273c7c370d543e1cc6a147,然后写到 patches 目录即可,20230306005259e9514c158a7c852d26d558e708ada6d8510242951,patches 文件的生成还是挺简单的,就是在临时目录下创建了一个基础 commit,然后把新的内容复制过去,通过 git diff 生成的 patches 内容。,那应用 patches 的内容是怎么实现的呢?,patches 如何被应用的?,我又对 acorn 目录下的文件做了些修改,生成的 patches 文件是包含了增删改的:,20230306005702c4bbc9a248c0620e001540f76118021b34083f559,20230306005031e29a3440767c6cd0bfd3304fab2d2a9be71562988,20230306005301e1d40be442d27ea24e60495f164205ebdf1b6b101,patches 文件里记录了对哪几行做了新增,哪几行做了删除,哪几行做了修改。,如果人工应用这个 patches 文件的话,不就是找到对应文件的对应行数,做反向的操作就可以了么?,没错,patch-package 也是这样实现的,不过是自动进行的:,它读取 patches 文件之后会进行 parse:,20230306005032f321506167239a670c7776cf83f4b18155a9db960,这个 parse 的实现就是对每一行的字符串做判断,进行不同的处理:,2023030600503345dcac307ed9efabd47553971cdb637afddc78585,最终能得到一个包含 diff 信息的对象,包含了对什么文件的哪些行做了什么修改:,2023030600530262d8aa7836b8fcd74279446e6f901c54d8bdb9939,之后对不同的类型做不同的操作就可以了:,20230306005035947c3b737396cbe0bfe45285a6a28169687eb9327,这样就把 patches 文件里的改动应用到了 node_modules 下的包里。,当我们需要对 node_modules 下的代码做改动的时候,可以通过 patch-package xxx 生成 patches 文件,它可以被提交到 git 仓库,然后再拉下来的代码就可以通过 patch-package 来应用改动。,实现原理要分为两部分来看:,patches 文件的生成是在临时目录生成 package.json,下载依赖,生成一个 commit,然后把改动的代码复制过去,两者做 gif diff,就可以生成 patches 文件。,patches 文件的应用则是 patch-package 自己实现了它的 parse,拿到对什么文件的哪些行做什么修改的信息,之后根据不同做类型做不同的文件操作就可以了。,整体看下来,这个小工具的原理还是挺清晰的,不过 parse patch 文件那部分还是有些麻烦的,当你需要解析 git diff 信息的时候,也可以参考下它的实现。

© 版权声明

相关文章