修改 node_modules 里文件的正确姿势
前言
我们在开发的时候经常会遇到这种情况:
- 所依赖的 npm 包有 bug,别人一时半会更新不了
- 不满足自己的需求(比如一些 UI 框架),需要修改某些部分
那么这个时候我们就要去修改 node_modules 里面的源码,直接修改会导致两个问题:
第一,更新问题,重新安装之后,修改的文件会被覆盖
第二,同步问题,node_modules 里的文件一般是不提交到代码库的,那如何让团队其他成员也能同步更新呢?你总不能每次改完之后都手动发给其他人吧。
你可能首先想到的解决办法有这样两个:
- 把别人代码全部复制到自己的 src 目录,修改完之后引入
- 把别人代码下载到本地,修改完之后重新发布为一个包,然后再安装自己发布的这个包
但这两个解决办法都有上述提到的更新问题,当这个依赖包有更新时,没法自动同步更新。而且我们引入依赖包的时候,往往引入的是编译之后的代码,这样会导致每次修改完代码之后,还得自己手动编译,很麻烦,那有没有其他更好的解决办法呢?答案是肯定的。我想到的有这样几个解决办法,我们来逐一分析一下。
说明
以下所有解决方案都以 request 包为例进行演示。
npm link
npm link 相当于建立一个软连接,将我们依赖的包链接到我们修改之后的包,这个在调试本地包的时候经常会用到,下面我们来实际操作一下。
-
fork request 的仓库到自己的仓库,我这里命名为 request-study
-
clone 到本地
-
进入到 request-study 目录,执行
npm link
-
进入到我们的工程目录,执行
npm link request
-
修改包文件里面的代码,这里我们修改的目录是 request-study/lib/auth.js
这样当包里面的文件更新的时候会自动同步到工程项目里面,解决了上述更新的问题。不足的一个地方是当依赖包有更新时,团队其他成员也需要拉取最新的依赖包代码。
webpack alias
webpack alias 的作用是配置别名,比如像这样:
chainWebpack: config => {
config.resolve.alias
.set('@', resolve('./src'))
.set('request/a', resolve('./src/a'))
}
所以我们可以利用 webpack alias 将需要修改的文件代理到我们自己的项目文件中,操作步骤如下:
- 找到别人源码里面的需要修改的文件,复制到 src 目录
- 修改代码,注意里面引用其他的文件路径都需要改成绝对路径
- 找到这个模块被引入的路径(我们需要拦截的路径)
- 配置 webpack alias
我们来实际操作一下。
我们修改的文件如下:
文件被引用的路径为 ./lib/auth (我们要拦截的路径)
将 auth.js 文件复制到 src/assets/auth.js,将 require 路径中引入为当前request包的路径修改为绝对路径,并添加我们的代码
配置 webpack alias (我这里用的是 vue-cli4, 配置文件是 vue.config.js),配置代码为
const path = require('path');
module.exports = {
chainWebpack: config => {
config.resolve.alias
.set('./lib/auth', path.resolve(__dirname, 'src/assets/auth.js'))
}
};
启动我们的项目,控制台打印出我们添加的代码,表明我们的代码添加成功。
当依赖包的代码有更新时,我们也能同步更新,团队其他成员同步修改的代码时也不需要做其它额外的操作。不足的一个地方是当我们修改的依赖包是在配置文件中(比如 vue.config.js)引入时,这个不会生效。
yarn patch
这个需要用到 v2 版本的 yarn,具体步骤如下:
-
全局安装 Yarn 的最新版本:
npm install -g yarn
,这里说明一下,如果你之前安装的是应用程序版本,需要先卸载之后再运行这个命令,不然安装完成之后还是之前的 yarn 版本。 -
进入你的项目目录,运行
yarn set version berry
命令。
-
执行
yarn patch request
命令 -
在如上图所示文件路径中修改代码
-
在你的项目根目录新建一个 patches 文件夹,执行
yarn patch-commit C:\Users\TWITTY~1\AppData\Local\Temp\xfs-f6241b39 > E:\vue-cli4\patches\request+2.88.2.patch
,这样你就能在 patches 文件下看到生成了一个 request+2.88.2.patch 文件,里面保存有你刚才修改代码的 diff 内容。 -
修改package.json 文件如下:
- "request": "^2.88.2" + "request": "patch:request@^2.88.2#./patches/request+2.88.2.patch"
-
重新运行 yarn 和 启动项目,你就能看到依赖包代码修改之后的变化
这种办法解决了上述更新和团队成员同步问题,缺点是操作起来比较繁琐,还得依赖 v2 版本的 yarn。
yarn patch 可能出现的问题:
-
运行
yarn set version berry
时,如果出现类似以下这种错误则可能需要用代理,命令行配置代理方法如下:
windows:
set http_proxy=http://127.0.0.1:1080 set https_proxy=http://127.0.0.1:1080
mac:
export http_proxy=http://127.0.0.1:1080 export https_proxy=http://127.0.0.1:1080
-
运行
yarn patch request
命令时,如果出现以下这种情况,则需要删除 yarn.lock 文件,重新执行yarn install
。具体可以参考我的另一篇文章—记录一次使用 yarn patch 遇到的问题。
-
运行
yarn patch request
命令时,如果出现以下这种情况,说明有多个版本的包共存,你可以选择你具体要修改的那个包版本,比如我想修改的是 request 的2.88.2 版本,就执行yarn patch request@npm:2.88.2
。
patch-package
操作步骤如下:
-
修改package.json 文件如下:
"scripts": { + "postinstall": "patch-package" }
-
安装 patch-package:
npm i patch-package -S
-
在 node_modules 里面修改依赖包的代码
-
每次修改代码之后执行命令
npx patch-package request
最终会在项目根目录生成一个 patches 文件夹,里面保存着修改过的文件记录。
你可能已经看到了,这种解决办法和 yarn patch 很像。是的,patch-package 可以看作是 yarn patch 的简化版,它相当于封装了 yarn patch 繁琐的操作。
总结
我们总结一下四种方法:
npm link 团队其他成员更新时需要同时更新修改依赖包;
webpack alias 不适用配置文件依赖的包;
yarn patch 需要将 yarn 升级到 v2 版本,操作步骤多;
patch-package 可以看做是 yarn patch 的一种替代方案,简化了 yarn patch 的很多操作,是一个比较理想的解决方案。
最后
码字不易,如果觉得对你有点帮助的话,还请动动你可爱的小指,帮忙点个赞;
如果你还有其他解决办法或者问题,也欢迎留言交流。
参考资料: