You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
npm WARN lifecycle The node binary used for scripts is /usr/local/bin/node but npm is using /root/node-v8.12.0/out/Release/node itself. Use the `--scripts-prepend-node-path` option to include the path for the node binary npm was executed with.
if(shouldPrependCurrentNodeDirToPATH(opts)){// prefer current node interpreter in child scriptspathArr.push(path.dirname(process.execPath))}
既然了解了这个参数的作用,这次我们执行:
npm1 run build --scripts-prepend-node-path
warning 的确没了,但是出现了一个报错:
Error: The module '/root/preact/node_modules/iltorb/build/bindings/iltorb.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 64. This version of Node.js requires
NODE_MODULE_VERSION 57. Please try re-compiling or re-installing
the module (for instance, using `npm rebuild` or `npm install`).
缘由
同时在系统中安装多个不同版本的 Node.js 跟 npm 听起来像是个伪需求,毕竟当我们需要某个特定版本的 Node.js 时,使用版本工具进行安装、切换都很方便。
不过前些天公司一个运维的小伙伴刚好跟我讨论这个问题,他想在机器上已经安装了一个 Node.js 的情况下,再安装一个不同版本的 Node.js (通过
node2
,npm2
来调用),然后执行npm2 run build
的时候用node2
来编译项目,但是经过他实际测试发现 build 会失败,不清楚问题出在哪里,出于好奇的目的我打算自己试一试。实验
为了不搞乱自己的电脑,我用 docker 启动了一个 ubuntu,在这个干净的 ubuntu 里实验。
从官网下载
v10.16.0
及v8.12.0
两个版本的 Node.js,解压后分别进入各自的目录执行:进行编译。编译完成后分别将各自的 node, npm 可执行文件链接到
/usr/local/bin
目录下:最后得到的结构如下所示:
我们在终端里试一下命令:
可以看到目前系统里存在两个不同的命令
node
跟node1
,分别指向v10.16.0
与v8.12.0
,以及各自搭配的 npm。编译
安装成功后,现在是时候体验一下不同版本的 Node.js, npm 实际使用效果了 。为了简化操作,我们选用 preact 项目来实验
npm run build
。在正式运行 npm 命令之前,我们先查看一下
npm1
这个命令本身的代码,执行vim /usr/local/bin/npm1
可以看到第一行 (shebang) 是:#! /usr/bin/env node
这一行的意思是,找到当前系统中叫 node 的命令来执行此文件。回想一下我们之前的链接操作,
node
是指向v10.16.0
版本的,也就是说我们直接执行npm1 -v
的时候,其实调用的是v10.16.0
版本的 node 来运行npm1
。为了匹配正确的 node 版本,这里我们需要把npm1
的 shebang 改成:#! /usr/local/bin/node1
改完保存并且克隆 preact 的项目后,我们执行
npm1 install
,这一步显示成功。继续执行
npm1 run build
,编译成功。不过有个 warning 引起了我的注意:这里的意思是,如果我们想让运行 run-script 命令时,用的 node 版本与运行当前 npm 的版本一致的话,应该要传递一个
--scripts-prepend-node-path
参数。事实上,通过查看调试 npm 自身的代码可以发现,这个参数会使当前执行 npm 的 node 的可执行文件所在的目录,优先前置到 run-script 开启的子进程的PATH
环境变量中,这样在实际执行 build 命令时,用的版本跟执行 npm1 的版本保持一致。可以看下/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/index.js
中第118
行的代码:既然了解了这个参数的作用,这次我们执行:
warning 的确没了,但是出现了一个报错:
这里提示说项目的依赖包在安装时候使用的 Node.js 版本与执行 build 的时候的版本不一致。我们最开始安装依赖的时候直接执行的是
npm1 run install
,并没有带上--scripts-prepend-node-path
参数,所以实际安装用的版本是v10.16.0
,而不是想要的v8.12.0
。我们重新带上参数安装并 build 试试:可以发现这次成功了,而且用的版本是
npm1
对应的 Node.jsv8.12.0
。(其实还有一种情况就是,当 npm 版本与 Node.js 版本不兼容时,直接运行 npm 也会报错)
结论
可以看到为了让 npm 能识别指定版本的 Node.js,我们需要改动到
npm-cli.js
中的 shebang。另外当多个版本的 Node.js, npm 同时共存时,还需要注意 npm 的配置文件需要隔离多份并且有些配置不能重复,比如用来放置全局依赖包的 prefix 文件夹路径不能相同,否则也会引起一些问题。鉴于这些问题,如果没有特殊需求,并不推荐同时安装多个不同版本的 Node.js,建议还是使用版本管理工具比较好。如果一定要保持现有的 Node.js 存在的情况下,需要使用另一个版本的 Node.js 来做一些事情,建议利用 docker 的 Node.js 镜像来实现,这样既方便又不怕搞乱现有的环境。The text was updated successfully, but these errors were encountered: