23

我想强制使用yarn install而不是npm install. 我想在npm install. 我应该做什么package.json

4

8 回答 8

30

更新: 亚历山大的答案是更好的解决方案,并使用我在这里描述的相同技术。我将保留我的答案以供后代使用。我回答的初衷是表明您可以执行一个可以在所有平台上运行的小节点脚本。

pgrep在您的预安装脚本中,您可以运行一个可以在所有平台上运行的迷你节点脚本,而在 Windows 10 得到广泛采用之前,诸如(以及其他常见的 *nix 命令和运算符)之类的东西将无法在 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,但它并没有真正通过“这个有更好的名字”测试。

于 2016-12-13T02:15:48.683 回答
16

与其他答案一样,我建议使用preinstall脚本并检查您的环境。对于一个在另一个 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
于 2016-12-20T00:58:48.217 回答
12

这里的大多数答案都涉及 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@
于 2020-05-20T10:39:51.900 回答
10

在尝试了这些选项并且不是很满意之后,我推荐only-allow

只需添加:

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

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

仅允许错误输出的屏幕截图

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

于 2020-06-03T15:03:03.290 回答
2

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

示例包.json:

  "scripts": {
    "preinstall": "pgrep npm && exit 1"
  }
于 2016-12-13T02:02:27.097 回答
2

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

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

另请参阅此处的讨论:

于 2017-05-07T22:52:47.720 回答
2

如果您想简单地测试软件包是否安装在 yarn 或 npm 下,我稍微调整了Alexander O'Mara 的答案,因为它在 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=process.exit(N)由于 Node.js 的异步特性,可用于设置进程的退出代码并且比调用更安全。

  • Alexander 的示例中,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)。然后您可以验证退出代码是否为 1 echo $?(打印最后一个退出代码)。

  • shell 的if XXXX ; then YYYY ; else ZZZZ ; fi条件逻辑检查 0 的退出代码XXXX并转到thencase (任何其他值都转到elsecase)。因此,如果正则表达式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 yarnandecho npm部分替换为其他命令。例如,您可以将多个命令放在一个子shell 中,例如(echo yarn)or echo $(echo yarn)

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

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

于 2018-03-22T20:47:55.390 回答
0

在Reddit上找到了替代解决方案。我将此添加到.zshenv文件的末尾:

NPM_PATH=$(which npm)
npm () {
  if [ -e yarn.lock ]
  then
    echo "Please use yarn with this project"
  else
    $NPM_PATH "$@"
  fi
}

它现在阻止我像npm i在我的 Mac 上的任何纱线项目上那样心不在焉地运行命令。

于 2021-01-21T16:09:23.557 回答