Windows的NPM包'bin'脚本

47

Cucumber.js提供了一个命令行“二进制”文件,它是一个包含shebang指令的简单的.js文件:

#!/usr/bin/env node
var Cucumber = require('../lib/cucumber');
// ...

package.json 文件中通过设置 "bin" 配置键来指定二进制文件:

{ "name" : "cucumber"
, "description" : "The official JavaScript implementation of Cucumber."
// ...
, "bin": { "cucumber.js": "./bin/cucumber.js" }
// ...

在 POSIX 系统上,这一切都运行良好。有人报告说,在 Windows 上运行 Cucumber.js 时出现了问题

基本上,.js 文件似乎是通过 Windows 的 JScript 解释器(而不是 Node.js)执行的,并且由于 shebang 指令而抛出语法错误。

我的问题是:设置适用于 UNIX 和 Windows 系统的“二进制”脚本的推荐方法是什么?

谢谢。

3个回答

70

Windows忽略shebang行#!/usr/bin/env node,并根据.js文件关联执行它。在调用脚本时明确使用node。

node hello.js

附注:Pedantry(严谨主义):shebangs(解释器指示)不在POSIX标准中,但它们受到大多数*nix系统的支持。


如果您将项目打包为Npm,请在package.json中使用“bin”字段。然后在Windows上,Npm会安装与脚本一起使用的.cmd包装器,以便用户可以从命令行执行它。

hello

为了让npm正确地创建shim,脚本必须有shebang行#!/usr/bin/env node


6
问题出在二进制脚本名称以“.js”为后缀。NPM根据“bin”配置指令创建了一个unix友好的cucumber.js和一个针对Windows友好的cucumber.js.cmd二进制文件。由于Windows处理文件“扩展名”的方式,当输入node_modules\.bin\cucumber.js时,它会将“.js”文件通过JScript运行,而不是.cmd文件。感谢这个苛刻的附言 ;) - jbpros
1
我遇到了完全相同的问题。我正在尝试找到一种解决方案,不需要我告诉Windows用户键入不同的命令。预先处理npm生成的.cmd文件的JavaScript文件在Windows Script Host中执行;我希望有一种方法可以利用它来代理到基于Node的CLI:http://stackoverflow.com/questions/24113091/equivalent-of-unix-exec-in-jscript-windows-script-host - ELLIOTTCABLE
如何让它在Node.js中执行而不是Microsoft JScript?即使将其更改为node ./index.js也无法使其工作。更正:重新执行npm link似乎可以解决问题。 - Joel Harkes
我和你一样遇到了同样的问题,错误信息为 ENOENT: no such file or directory, chmod 'C:\Users\<user>\AppData\Roaming\npm\node_modules\<module>\node .\index.js'。在 package.json 文件中,有如下代码:"bin": { "<module>": "node ./index.js"} 你是怎么解决这个问题的? - YoyoS
1
好的,我已经添加了#!/usr/bin/env node,即使是在Windows上也可以工作。 - YoyoS
@YoyoS 是的,那对我也起作用了,谢谢! - Daniel Rodríguez Meza

5

"bin"应该改为"cucumber",npm会创建一个指向"node %SCRIPTNAME%"的文件,名字是"cucumber"或者"cucumber.cmd"。前者适用于posix环境,后者适用于Windows环境...如果你希望"js"作为可执行文件名的一部分...你应该使用连字符... "cucumber-js"。在你的情况下,.js文件会在.js.cmd之前运行,导致WScript解释器将其视为JScript文件而不是Node脚本。

我建议查看coffee-script的package.json文件,这是一个很好的例子。

{
  "name":         "coffee-script",
  "description":  "Unfancy JavaScript",
  "keywords":     ["javascript", "language", "coffeescript", "compiler"],
  "author":       "Jeremy Ashkenas",
  "version":      "1.4.0",
  "licenses":     [{
    "type":       "MIT",
    "url":        "https://raw.github.com/jashkenas/coffee-script/master/LICENSE"
  }],
  "engines":      {
    "node":       ">=0.4.0"
  },
  "directories" : {
    "lib" : "./lib/coffee-script"
  },
  "main" : "./lib/coffee-script/coffee-script",
  "bin":          {
    "coffee":     "./bin/coffee",
    "cake":       "./bin/cake"
  },
  "scripts": {
    "test": "node ./bin/cake test"
  },
  "homepage":     "http://coffeescript.org",
  "bugs":         "https://github.com/jashkenas/coffee-script/issues",
  "repository":   {
    "type": "git",
    "url": "git://github.com/jashkenas/coffee-script.git"
  },
  "devDependencies": {
    "uglify-js":  ">=1.0.0",
    "jison":      ">=0.2.0"
  }
}

0

我成功地想出了解决类似问题的方法。

我最初的计划是只有一个大的 .js 文件,用于 API 和 CLI(原因是因为当时我不知道如何在两个文件之间共享变量)。当一切都构建好后,我尝试将 #!/usr/bin/env node shebang 添加到我的文件中。然而,这并没有阻止 Windows 脚本主机报错。

最终,我想出了一个“变量桥”的想法,允许使用 getVarsetVar 读取和设置变量。这使我不得不从 API 代码中提取 CLI 代码,并添加一些导入到变量桥中。

在 CLI 文件中,我添加了 shebang,并修改了项目的 package.json

{
    ...
    "main": "./bin/api.js",
    "bin": {
        "validator": "./bin/cli.js"
    }
    ...
}

这里有几个小笔记,我认为如果 Windows Script Host 仍然出现错误可能会有所帮助(我都应用了它们,所以不确定哪一个起了作用):

  • 只使用 LF 行尾似乎有所帮助。

  • 似乎 ./bin 是编译后文件的首选目录。我曾尝试过 ./dist,但没有成功。

  • 在 shebang 后面加上一行空行可能是必要的:

    // cli.js
    
    #!/usr/bin/env node
    
    // code...
    
  • package.json 中使用相同的名称作为 mainbin 对我来说似乎是个问题。


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