为 Node 模块强制安装 yarn 而不是 npm install?

Posted

技术标签:

【中文标题】为 Node 模块强制安装 yarn 而不是 npm install?【英文标题】:Force yarn install instead of npm install for Node module? 【发布时间】:2017-04-25 20:41:25 【问题描述】:

我想强制使用yarn install 而不是npm install。我想在npm install 中提出错误。 package.json我该怎么办?

【问题讨论】:

您在使用 npm install 时遇到了什么错误 这可能不是他面临的错误,而是希望确保他的整个团队都在使用 yarn。 Yarn 修复了团队工作时 npm 带来的很多问题。 【参考方案1】:

更新:Alexander's answer 是更好的解决方案,并且使用了我在此处描述的相同技术。我将保留我的答案以供后代使用。我回答的初衷是为了表明您可以执行一个适用于所有平台的小型节点脚本。

在您的预安装脚本中,您可以运行一个迷你节点脚本,该脚本应该适用于所有平台,而在 Windows 10 得到广泛采用之前,pgrep(以及其他常见的 *nix 命令和运算符)等内容将无法在 Windows 上运行.

我在 Node v4.7.0 (npm v2.15.11) 和 Node v7.2.1 (npm v3.10.10) 上测试了以下脚本。我认为它适用于介于两者之间的所有内容。它通过检查当前运行进程的环境变量来工作——npm_execpath 是当前运行的“npm”脚本的路径。对于yarn,应该指向/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 的多个主要版本已经存在,但它并没有真正通过 “这个有更好的名字” 测试。

【讨论】:

&& 在 npm 脚本中很好,因为它们是由命令提示符而不是 powershell 执行的。 啊,谢谢。我以为&& 的Windows 等效项是& - 我错了(&; 的Windows 等效项)。我已经更新了我的答案。 引号在 Windows 上很重要,如果您在 -e 参数中使用单引号,则会出错:"preinstall": "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('You must use Yarn to install, not NPM')\"" 这似乎与我们所拥有的相匹配,所以应该可以。我有一台 Mac,我的同事有 Windows,所以我们经常互相破坏。 我不同意你说亚历山大的答案更好。他的不适用于Windows,而您的则可以。他们实际上在做同样的事情,但这是跨平台的。【参考方案2】:

与其他答案一样,我建议使用preinstall script 并检查您的环境。对于在另一个 npm 进程恰好正在运行时不会出现误报的便携式解决方案,使用 node -e 'JS_CODE' 可能是最好的选择。

在该 JS 代码中,您可以使用以下命令检查包管理器的路径:

process.env.npm_execpath

Yarn 的二进制文件是 yarn.js,而 NPM 使用的是 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

【讨论】:

这个答案在 Mac OS 上最适合我。我扩展了 Alexander 的回答,详细解释了所涉及的逻辑以及在***.com/a/49438180/539149 检测纱线/npm 的一般示例 这在 Windows 上不起作用,但对于任何展望未来的人来说,接受的答案都可以。 @Julian我通过将正则表达式更改为仅使用一个斜杠使其在 Windows 10 上运行:!/yarn\.js【参考方案3】:

这里的大多数答案都涉及 hacky 脚本,但有一种内置方法可以实现这一点,我在 Yarn github issue 上发布了该方法。与其他方式不同,这适用于任何和所有 NPM 命令。

你在 package.json 中添加一个像这样的假引擎版本(你可能想要调整纱线和节点条目):

  "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@

【讨论】:

这对我来说效果最好。所选答案(或所选答案中的建议答案)确实阻止了npm,但也阻止了yarn 命令的运行。这看起来最干净,并且易于理解错误消息输出。 注意!!这会在发布包时产生干扰,并使用engine-strict=true 将其重新安装到其他地方(因为package.jsonengines 字段已发布)。相反,我建议不要在 package.json 中使用 engines @Polv 包的消费者不应该有 .nmprc。这意味着engine-strict 对他们来说是错误的。更高版本的 NPM 只会对此发出警告。我【参考方案4】:

在尝试了这些选项后并不太满意,我推荐only-allow。

只需添加:


  "scripts": 
    "preinstall": "npx only-allow yarn"
  

我喜欢它提供了清晰的警告信息,以及如何安装纱线的说明:

感谢Adam Thomas' 回答提供了推荐这个的线程。

【讨论】:

如果用户根本没有安装 npm 会怎样? @Mark 请看github.com/pnpm/only-allow/issues/1#issuecomment-727667757 为了安全起见,我建议任何打算使用此脚本的人使用npx only-allow@1.0.0 yarn【参考方案5】:

您可以使用preinstall 钩子和一些shell 脚本来实现这一点。

示例 package.json:

  "scripts": 
    "preinstall": "pgrep npm && exit 1"
  

【讨论】:

这在 OSX 上对我不起作用,因为它会产生误报。例如,直接在终端中运行 pgrep npm 会返回一个进程 ID,因为我碰巧有一个正在运行的服务器,它是使用 npm 脚本启动的。【参考方案6】:

我刚刚发布了一个包含 CLI 的模块(对 npm preinstall 脚本有用):https://github.com/adjohnson916/use-yarn

另外,我刚刚为 Danger 发布了一个帮助程序来检查 CI 上缺少的 yarn.lock 更改: https://github.com/adjohnson916/danger-yarn-lock

参见此处的讨论:

https://github.com/yarnpkg/yarn/issues/1732 https://github.com/alexanderwallin/use-yarn-instead/issues/1

【讨论】:

【参考方案7】:

如果您想简单地测试软件包是安装在 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": ""

在这个简短的 sn-p 中出现了很多概念:

\\. 部分被转义,因此 \\ 变为 \ 并导致正确转义的 \. 以检测正则表达式中的句点。

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。

1234563因此,如果正则表达式在process.env.npm_execpath 的末尾检测到yarn.js,则返回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 yarnecho npm 部分替换为其他命令。例如,您可以将多个命令放在一个子shell 中,例如(echo yarn)echo $(echo yarn)

就我而言,我需要解决一个问题,即安装了其中一个软件包但在 yarn 下存在错误,因此我必须在成功的情况下运行 npm install --ignore-scripts。请注意,这可能永远不应该在生产环境中完成,但如果您只是需要完成某件事或无法控制以后将使用哪个包管理器,则可以成为救命稻草。

我还没有在 Windows 上尝试过这个,所以如果有人可以在那里测试语法,我会用有效的方法更新我的答案。最好preinstall 脚本在 Windows 和 Mac/Linux shell 下都相同。

【讨论】:

【参考方案8】:

在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 之类的命令。

【讨论】:

以上是关于为 Node 模块强制安装 yarn 而不是 npm install?的主要内容,如果未能解决你的问题,请参考以下文章

Node入门教程第五章:node 模块化(下) npm与yarn详解

[Web 前端] 使用yarn代替npm作为node.js的模块管理器

Yarn install 在安装 node-forge 模块时出错

关于npm和yarn安装node-sass失败并且依旧想使用NPM或者yarn的完美解决方案

linux (centos)安装卸载升级node, npm, yarn

一文简述npm和cnpm和yarn的区别