修改 node_modules 里文件的正确姿势

2,548 阅读6分钟

前言

我们在开发的时候经常会遇到这种情况:

  1. 所依赖的 npm 包有 bug,别人一时半会更新不了

  2. 不满足自己的需求(比如一些 UI 框架),需要修改某些部分

那么这个时候我们就要去修改 node_modules 里面的源码,直接修改会导致两个问题:

第一,更新问题,重新安装之后,修改的文件会被覆盖

第二,同步问题,node_modules 里的文件一般是不提交到代码库的,那如何让团队其他成员也能同步更新呢?你总不能每次改完之后都手动发给其他人吧。

你可能首先想到的解决办法有这样两个:

  1. 把别人代码全部复制到自己的 src 目录,修改完之后引入

  2. 把别人代码下载到本地,修改完之后重新发布为一个包,然后再安装自己发布的这个包

但这两个解决办法都有上述提到的更新问题,当这个依赖包有更新时,没法自动同步更新。而且我们引入依赖包的时候,往往引入的是编译之后的代码,这样会导致每次修改完代码之后,还得自己手动编译,很麻烦,那有没有其他更好的解决办法呢?答案是肯定的。我想到的有这样几个解决办法,我们来逐一分析一下。

说明

以下所有解决方案都以 request 包为例进行演示。

npm link

npm link 相当于建立一个软连接,将我们依赖的包链接到我们修改之后的包,这个在调试本地包的时候经常会用到,下面我们来实际操作一下。

  1. fork request 的仓库到自己的仓库,我这里命名为 request-study

  2. clone 到本地

  3. 进入到 request-study 目录,执行 npm link

  4. 进入到我们的工程目录,执行 npm link request

  5. 修改包文件里面的代码,这里我们修改的目录是 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 将需要修改的文件代理到我们自己的项目文件中,操作步骤如下:

  1. 找到别人源码里面的需要修改的文件,复制到 src 目录

  2. 修改代码,注意里面引用其他的文件路径都需要改成绝对路径

  3. 找到这个模块被引入的路径(我们需要拦截的路径

  4. 配置 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,具体步骤如下:

  1. 全局安装 Yarn 的最新版本:npm install -g yarn ,这里说明一下,如果你之前安装的是应用程序版本,需要先卸载之后再运行这个命令,不然安装完成之后还是之前的 yarn 版本。

  2. 进入你的项目目录,运行 yarn set version berry 命令。

  3. 执行 yarn patch request 命令

  4. 在如上图所示文件路径中修改代码

  5. 在你的项目根目录新建一个 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 内容。

  6. 修改package.json 文件如下:

    - "request": "^2.88.2"
    + "request": "patch:request@^2.88.2#./patches/request+2.88.2.patch"
    
  7. 重新运行 yarn 和 启动项目,你就能看到依赖包代码修改之后的变化

这种办法解决了上述更新和团队成员同步问题,缺点是操作起来比较繁琐,还得依赖 v2 版本的 yarn。

yarn patch 可能出现的问题:

  1. 运行 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
    
  2. 运行 yarn patch request 命令时,如果出现以下这种情况,则需要删除 yarn.lock 文件,重新执行 yarn install

    具体可以参考我的另一篇文章—记录一次使用 yarn patch 遇到的问题

  3. 运行 yarn patch request 命令时,如果出现以下这种情况,说明有多个版本的包共存,你可以选择你具体要修改的那个包版本,比如我想修改的是 request 的2.88.2 版本,就执行 yarn patch request@npm:2.88.2

patch-package

操作步骤如下:

  1. 修改package.json 文件如下:

    "scripts": {
    + "postinstall": "patch-package"
    }
    
  2. 安装 patch-package: npm i patch-package -S

  3. 在 node_modules 里面修改依赖包的代码

  4. 每次修改代码之后执行命令 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 的很多操作,是一个比较理想的解决方案。

最后

码字不易,如果觉得对你有点帮助的话,还请动动你可爱的小指,帮忙点个赞;

如果你还有其他解决办法或者问题,也欢迎留言交流。

参考资料:

juejin.cn/post/684490…

yarnpkg.com