Node.js中的node_modules/.bin/package.cmd文件

5

我是新手,正在学习Node.js。我试图构建一个NPM模块,但对于在本地/ node_modules / .bin文件夹中存在的带有软件包名称的cmd文件感到困惑。

我安装了多个依赖包,并发现cmd文件是不同的。

jade.cmd

@IF EXIST "%~dp0\node.exe" (
  "%~dp0\node.exe"  "%~dp0\..\jade\bin\jade" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node  "%~dp0\..\jade\bin\jade" %*
)

mocha-casperjs.cmd

@IF EXIST "%~dp0\/bin/sh.exe" (
  "%~dp0\/bin/sh.exe"  "%~dp0\..\mocha-casperjs\bin\mocha-casperjs" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  /bin/sh  "%~dp0\..\mocha-casperjs\bin\mocha-casperjs" %*
)

我的问题是,如果这是由NPM自动生成的,为什么npm会为两个不同的包创建2个不同的文件。这是用户创建并告诉NPM的吗?
2个回答

6

简述:

在Windows上,npm 根据脚本文件中指定的 shebang 行所使用的shell/解释器来创建包装批处理文件(*.cmd)。


你所看到的是npm对于Windows操作系统的Unixshebang机制的模拟。如果一个可执行的纯文本文件(脚本)的第一行以字符#!开头,那么它告诉操作系统应该将脚本传递给哪个解释器/ shell来执行(有关更多信息,请参见我的this answer)。
由于Windows不支持shebang行,npm创建了一个wrapper*.cmd(批处理)文件,显式地调用“binary”文件(在package.json文件的bin键中指定的脚本文件),并使用脚本文件的shebang行中指定的任何可执行文件。
换句话说:npm解析脚本的shebang行,以确定要调用哪个shell/解释器,并相应地创建包装批处理脚本。 如果我们查看jade包中的./bin/jade.js,我们会看到#!/usr/bin/env node作为shebang行,这就是为什么jade.cmd包装文件调用node.exe的原因。
这是典型情况:一个用JavaScript编写的脚本必须由Node.js引擎执行
然而,也可以指定任何其他shell/解释器,但只有在Windows上也可用给定的shell/解释器时才有意义;对于node来说,这是一个确定的事实,但正如mocha-casper.js包中的mocha-casper.cmd的内容所示,使用Unix默认shell/bin/sh没有意义(./bin/mocha-casperjs文件包含shebang行#!/bin/sh)。
制作人选择自行开发Windows集成,通过重新实现Unix shell脚本为cmd.exe的mocha-casperjs.bat(也是批处理文件) - 然而,由于npm不知道这一点,因此该批处理文件没有放置在PATH(全局)/无法仅通过名称发现(在项目上下文中调用CLIs)。
更普遍地说,为了让脚本在Windows上也能工作,使用带有绝对的POSIX风格路径的shebang行是没有意义的,除非目标shell/解释器通过/usr/bin/env的间接调用进行指定,这会向npm发出信号,让它在PATH中查找它(请参见我的答案this answer以获取更多信息)。另外,包装批处理文件也会在它们自己的目录中查找可执行文件,但这很少有帮助,因为即使您将它们明确添加为package.json的bin键中的条目,npm也不会将它们复制到那里。
另外一件事:最近版本的npm还为Unix环境(特别是Cygwin和Windows上的Bash)创建无扩展名的包装脚本。

创建自己的包时,如果要将 CLI(“二进制文件”)作为 npm 包的一部分直接执行脚本并像命令行实用程序一样运行,以在 Windows 上正常工作,您必须采取以下措施:

  • 为你的脚本添加shebang行 - 即使你只打算在Windows上运行它们。

  • 将shebang行定义为#!/usr/bin/env <interpreter-executable-filename-without-extension>; 通常情况下,如果你的脚本是用JavaScript编写的,并且必须使用node执行,则使用:
    #!/usr/bin/env node

  • 在你的package.json文件的bin键中,定义脚本键不带扩展名,因为当包装器批处理文件创建时(在Unix上,会创建一个名为该键的符号链接),.cmd会直接附加到键名后面;例如: "bin": { "foo": "./bin/fooj.js" }

  • 注意:如果在package.jsonbin键指向的脚本具有扩展名.js,但没有shebang行,则包装器脚本将直接调用.js文件,这将默认使用WSH(具体来说,使用其JavaScript引擎JScript)而不是Node.js来执行,这不会按预期工作 - 参见this question以了解你将看到的症状。


1
你可以告诉npm将与您的软件包一起提供的可执行文件从 ./node_modules/.bin 目录(本地安装时)或全局访问(当模块全局安装时)。您应该将 bin 字段放入 package.json 并指定脚本的相对路径。例如,jade package.json包含以下代码:
"bin": {
  "jade": "./bin/jade.js"
}

安装jade包时,npm会生成一个包装脚本(jade.cmd),使得该脚本(./bin/jade.js)可以访问。该包装脚本的内容取决于当前操作系统、shell以及您希望访问的脚本类型。Jade使用.js脚本,npm为您的操作系统生成jade.cmd,它将启动节点并将脚本名称作为参数传递。但是mocha-casperjs使用shell脚本,因此生成的mocha-casperjs.cmd的内容不同——它启动sh.exe而不是node。
您可以在这里阅读有关package.json的bin字段的信息:https://docs.npmjs.com/files/package.json#bin

package.json 中的 bin 属性告诉 npm 包可执行文件的位置。但是当你安装一个包时,npm 会将其安装在 node_modules/jade(jade 只是一个例子)中,并在 node_modules/.bin/jade.cmd 中添加一个 cmd 文件,该文件指向 node_modules/jade/bin/jade。 - prabhat
@prabhat,是的,你说得对。我写了关于生成cmd文件的内容,npm将其放置在node_modules/.bin目录中。您无法手动更改此cmd文件的内容,它是自动生成的。这回答了您的问题吗,还是我没有理解您的意思? - Victor
如果npm生成它,为什么两个包的不同如此之大,这是我的问题。我在谷歌上找不到任何资料,所以我来这里问了。 - prabhat
1
@prabhat,我已经写过了。这是因为jade package.json在bin选项中指定了JavaScript文件(通过node.exe运行),而mocha-casperjs指定了通过sh.exe命令解释器运行的shell脚本。因此,npm为jade生成一个脚本(启动node),为mocha-casperjs生成另一个脚本(启动sh.exe)。如果mocha-casperjs作者在bin选项中指定了js文件,npm将生成与为jade生成的完全相同的cmd文件(当然,除了文件名)。 - Victor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接