当我们使用别人的轮子 (modules) 多了之后就会发现可能别人的轮子可能有些地方不符合自己的项目或者说有些小问题还没修复,这时候我们有几种办法解决,去作者的仓库提 issue(等待作者回复然后修复再更新就需要比较长的时间了),或者自己 fork 项目改掉之后发布到 npmjs.com(后期需要长期维护需要及时合并原来仓库的代码然后更新),每次 npm install 之后手动改一下 node_modules 中的代码(每次都 install 之后都需要改动当然如果需要 fix 的 module 多的话可以用我们今天的主角 Bash 脚本来一键修复啦,不过还是不要忘记每次 install 之后都执行一下脚本哦)

今天我们主要看看第三种解决方案,相比于去提 issue 然后等作者修复之后的更新来说后面两种方案是能很节省时间的(当然啦,如果是一个好 BUG 我还是建议去提交一下 issue 的,不管是不是用后面的方案解决了,为开源事业做出一份自己的贡献嘛),第二种方案嘛,如果对于那种比较热门的轮子来说的话你要更新维护还是需要一定成本的而且还有一个小问题就是不是直接依赖的包那需要维护的依赖链上全部的包的成本就太高了。所以总的来说第三种方案是最轻量的。

其实写一个脚本来处理也十分简单,如下图,假如我安装了一个 demo 的包,在这个 demo 包里的 src/index.js 这个代码中有一行代码有问题

使用 Bash 修复 node_modules 中的依赖包,解析 breeze cli bash npmfix 脚本的使用-天真的小窝

我先在项目根目录创建一个 bash 文件夹,里面包含一个 node_modules_fix 文件夹和一个 npmfix.sh 的 Bash 的脚本文件

使用 Bash 修复 node_modules 中的依赖包,解析 breeze cli bash npmfix 脚本的使用-天真的小窝

将 node_modules/demo/src/index.js 中的代码改正确之后将这个文件复制到 node_modules_fix 文件夹中,然后编辑 npmfix.sh 文件

#!/bin/bash

[ ! -d ./node_modules ] && yarn

echo "修复 node_modules 中的问题..."
/bin/cp -rf ./bash/node_modules_fix/*  ./node_modules/

有多个模块或者多个文件也是先改好之后将它放到 node_modules_fix 文件夹中就好了,只是要注意 node_modules_fix 文件夹中修复好的代码文件路径要和它原来相对 node_modules 文件夹的路径一直。

弄好修复脚本和文件夹之后在每次 npm install 之后在项目根目录下面执行一次 npmfix.sh 脚本就好了

$ bash ./bash/npmfix.sh

解析 breeze cli bash npmfix 脚本的使用

我这里就实战修复一下今天运行 react-native 项目开 debug 时遇到一个 Error: EISDIR: illegal operation on a directory, read 的错误,首先能看到开 debug 时错误输出如下

Error: EISDIR: illegal operation on a directory, read
    at Object.readSync (fs.js:524:3)
    at tryReadSync (fs.js:349:20)
    at Object.readFileSync (fs.js:386:19)
    at UnableToResolveError.buildCodeFrameMessage (/data/app/demo/node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js:347:17)
    at new UnableToResolveError (/data/app/demo/node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js:333:35)
    at ModuleResolver.resolveDependency (/data/app/demo/node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js:211:15)
    at DependencyGraph.resolveDependency (/data/app/demo/node_modules/metro/src/node-haste/DependencyGraph.js:413:43)
    at /data/app/demo/node_modules/metro/src/lib/transformHelpers.js:317:42
    at /data/app/demo/node_modules/metro/src/Server.js:1471:14
    at Generator.next (<anonymous>)

在 GitHub 找到了原因和解决方案,这里看的出来是由于 metro 这个包的一个小问题导致的,我们需要把 node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js 这个文件中一行代码修复一下。

使用 Bash 修复 node_modules 中的依赖包,解析 breeze cli bash npmfix 脚本的使用-天真的小窝

我们先在 node_modules 文件夹中找到这个文件。

使用 Bash 修复 node_modules 中的依赖包,解析 breeze cli bash npmfix 脚本的使用-天真的小窝

我成功找到了它并且修复好它那行代码之后我先将它的相对路径复制一下。

接着我打开我们的 breeze/cli/bash/node_modules_fix 修复文件夹,并且在终端中打开

使用 Bash 修复 node_modules 中的依赖包,解析 breeze cli bash npmfix 脚本的使用-天真的小窝

然后使用 mkdir 创建一个修复要用到的嵌套文件夹目录,这就是我刚刚为啥要复制一下 node_modules 下那个文件的相对路径,我这里直接粘贴过来然后删掉 node_modules 和后面的文件名就能创建一个一样的文件夹嵌套结构了

$ mkdir -p metro/src/node-haste/DependencyGraph/

创建好嵌套的文件夹结构之后我们将刚刚修复好的 js 代码文件复制过来

使用 Bash 修复 node_modules 中的依赖包,解析 breeze cli bash npmfix 脚本的使用-天真的小窝

这样一个简单的 node_modules 小问题就修复好了。因为在 breeze/cli/bash/npmfix.sh 里有直接将文件夹下的全部代码覆盖到 node_modules 的代码所以如果是简单的这些文件覆盖的话基本没问题

#!/bin/bash

echo "修复一些临时npm 兼容问题"

base_path=$PWD

if [ ! -z $1 ]; then
	base_path=$1
fi

# set -x
[ ! -d $base_path/node_modules ] && yarn
/bin/cp -rf $base_path/breeze/cli/bash/node_modules_fix/*  $base_path/node_modules/

当然,我这里还要举例一个不一般的情况,比如说我们修复 package.json 这个我们就不能直接改掉然后放一个 package.json 文件到 node_modules_fix 文件夹下面了,这样的话你会发现运行的时候会报错这个包冲突或者找不到

这是因为 node 是会遍历项目下面全部的 package.json 文件来生成依赖关系的。所以我们可以参考一下 breeze 中 react-native-gifted-chat 包的处理手段,将 package.json 命名为 _package.json 文件

使用 Bash 修复 node_modules 中的依赖包,解析 breeze cli bash npmfix 脚本的使用-天真的小窝

然后在 npmfix.sh 脚本中单独处理一下

#!/bin/bash

……

echo "修复 react-native-gifted-chat ..."
/bin/cp -rf $base_path/node_modules/react-native-gifted-chat/_package.json $base_path/node_modules/react-native-gifted-chat/package.json

好了,今天的划水文到这里也要说再见啦。