我想强制使用yarn install
代替npm install
。我想在npm install
中引发错误。我应该在package.json
做什么?
答案 0 :(得分:15)
更新: Alexander's answer是更好的解决方案。我正在为后人留下我的答案。我的回答的最初要点是表明你可以执行一个应该适用于所有平台的小节点脚本。
在预安装脚本中,您可以运行一个迷你节点脚本,该脚本应该可以在所有平台上运行,而pgrep
(以及其他常见的* nix命令和运算符)之类的东西在Windows 10收到之后将无法在Windows上运行广泛采用。
我在Node v4.7.0(npm v2.15.11)和Node v7.2.1(npm v3.10.10)上测试了以下脚本。我认为它适用于介于两者之间的一切。它的工作原理是检查当前正在运行的进程的环境变量 - npm_execpath
是当前运行的“npm”脚本的路径。对于纱线,它应指向/path/to/yarn/on/your/machine/yarn.js
。
"scripts": {
"preinstall": "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('You must use Yarn to install, not NPM')\""
}
您可以在此处详细了解npm脚本:https://docs.npmjs.com/misc/scripts
就npm_execpath
环境变量而言,虽然没有记录,但我怀疑它会不会改变。它已经出现在npm
的多个主要版本中,它并没有真正传递“这个”测试有一个更好的名称。
答案 1 :(得分:7)
与其他答案一样,我建议使用preinstall
script并检查您的环境。对于一个不会出现误报的便携式解决方案,如果另一个npm进程正好运行,使用node -e 'JS_CODE'
可能是最好的选择。
在该JS代码中,您可以使用以下命令检查包管理器的路径:
process.env.npm_execpath
与NPM使用的yarn.js
相比,Yarn的二进制值为npm-cli.js
。我们可以使用如下所示的正则表达式来检查此字符串是否以yarn.js
结束。
/yarn\.js$/
通过使用这个正则表达式,我们可以确定它不会在文件系统中的某个地方意外匹配。最有可能yarn
不会出现在文件路径中,但您永远不会太确定。
这是一个最小的例子:
{
"name": "test",
"version": "1.0.0",
"scripts": {
"preinstall": "node -e 'if(!/yarn\\.js$/.test(process.env.npm_execpath))throw new Error(\"Use yarn\")'"
}
}
当然,用户仍然可以通过编辑JSON或使用--ignore-scripts
选项来解决此问题:
npm install --ignore-scripts
答案 2 :(得分:3)
这里的大多数答案都涉及骇客脚本,但是有一种内置的方法可以实现此目的,我已将其张贴在computed properties上。与其他方法不同,这适用于所有NPM命令。
您在package.json中添加了一个伪造的引擎版本(您可能想调整一下yarn和node条目):
"engines": {
"npm": "please-use-yarn",
"yarn": ">= 1.17.3",
"node": ">= 12.5.0"
}
然后使用以下命令将.npmrc文件添加到项目根目录:
engine-strict = true
运行NPM会引发错误:
npm ERR! code ENOTSUP
npm ERR! notsup Unsupported engine for root@: wanted: {"npm":"please-use-yarn","yarn":">= 1.17.3","node":">= 12.5.0"} (current: {"node":"12.9.1","npm":"6.10.2"})
npm ERR! notsup Not compatible with your version of node/npm: root@
答案 3 :(得分:3)
尝试了这些选项之后,并不太满意,我建议使用only-allow。
只需添加:
{
"scripts": {
"preinstall": "npx only-allow yarn"
}
}
我喜欢它提供了清晰的警告消息,并说明了如何安装纱线:
请提供用于推荐此主题的线索,以Adam Thomas'的答案为准。
答案 4 :(得分:1)
您可以使用preinstall钩子和一些shell脚本来实现此目的。
示例package.json:
"scripts": {
"preinstall": "pgrep npm && exit 1"
}
答案 5 :(得分:0)
如果您只想测试是否在yarn或npm下安装软件包,我稍微调整了Alexander O'Mara's answer,因为它在OS X上适用于我:
"scripts": {
"preinstall": "if node -e \"process.exitCode=!/yarn\\.js$/.test(process.env.npm_execpath)\" ; then echo yarn ; else echo npm ; fi",
"postinstall": ""
}
在这个简短的片段中发生了很多概念:
\\.
部分已转义,因此\\
变为\
并导致正确转义\.
以检测正则表达式中的句号。
process.exitCode=
可用于设置进程的退出代码,并且由于Node.js的异步性质而比调用process.exit(N)
更安全。
在Alexander's example中,throw new Error(\"Use yarn\")
导致节点以代码1退出,并将堆栈跟踪打印到stderr
。您可以尝试在控制台上运行这些内容以查看其工作原理:node -e 'throw new Error("Oops")'
和node -e 'throw new Error("Oops")' 2> /dev/null
(将stderr
流定向到/dev/null
)。然后,您可以使用echo $?
验证退出代码为1(打印最后一个退出代码)。
shell的if XXXX ; then YYYY ; else ZZZZ ; fi
条件逻辑检查XXXX
的退出代码并转到then
的情况为0(任何其他值转到else
的情况)。因此,如果正则表达式在yarn.js
的末尾检测到process.env.npm_execpath
,则返回true。这必须被否定,以便节点进程以代码0退出并满足if
。
您还可以console.log()
正则表达式结果并比较shell中的输出(这只是更详细一点)。以下是如何执行此操作的一些示例:https://unix.stackexchange.com/a/52801和https://superuser.com/a/688902
您可以将true ;
或false ;
附加到任何shell语句以手动设置退出代码。例如,您可以尝试true ; echo $?
或false ; echo $?
。
如果您不需要,也可以完全取消else echo npm ;
部分。
完成所有这些操作后,您可以将echo yarn
和echo npm
部分替换为其他命令。例如,您可以将多个命令放在子shell中,如(echo yarn)
或echo $(echo yarn)
。
在我的情况下,我需要解决其中一个软件包安装但在纱线下有bug的问题,因此我必须在成功案例中运行npm install --ignore-scripts
。请注意,这可能永远不会在生产中完成,但如果您只是需要完成某些工作,或者无法控制将在何时使用哪个包管理器,那么这可能是一个救生员。
我没有在Windows上试过这个,所以如果有人可以在那里测试语法,我会用可行的方法更新我的答案。如果preinstall
脚本在Windows和Mac / Linux shell下都相同,那将是最好的。
答案 6 :(得分:0)
在 Reddit 上找到了替代解决方案。我将此添加到我的 .zshenv
文件末尾:
NPM_PATH=$(which npm)
npm () {
if [ -e yarn.lock ]
then
echo "Please use yarn with this project"
else
$NPM_PATH "$@"
fi
}
它现在阻止我在 Mac 上的任何纱线项目上心不在焉地运行 npm i
之类的命令。