如何在Windows上使npm项目与Bash shell命令兼容?

8

我最近接手了一个项目,其中有一些NPM脚本是像这样的:

{
    "package": "yarn package-common && mv './dist/APP® TV.wgt' ''./package/$(yarn -s filename)''",
    "package-common": "tizen package -t wgt -s APP -- ./dist && rimraf package && mkdir package",
    "filename": "cross-env-shell echo APP_${npm_package_version}.wgt",
}

这个项目是由一个使用MAC的人编写的。如何将以下部分翻译为可运行的Powershell/cmd命令? 我在任何地方都没有找到相关信息。它运行该命令,并将回显值附加到调用它的字符串中。
''./package/$(yarn -s filename)''

有没有一种方式可以实现跨平台,而不是使用这个软件包?

当前,在PowerShell中运行yarn package时输出的消息为:

'' was unexpected at this time.

顺便提一下:错误信息来自于 cmd.exe,这是 npm 在 Windows 上默认使用的。 - mklement0
如果需要跨平台,我建议将所有内容重写为 node.js 脚本,并使用 execSync(或者如果您想要异步,则使用 exec)来执行必要的命令。然后,您可以通过 npm-script 调用 node.js 脚本,例如 "package": "node somescript.js" - RobC
或者在您的npm脚本中内联评估(即node -e ...)_node.js_脚本。例如:"package": "yarn package-common && node -e \"var sh = require('child_process').execSync; var fn = sh('yarn -s filename', {encoding: 'utf8'}); sh('mv ./dist/APP®TV.wgt ./package/' + fn);\"",这将跨平台运行,但是您脚本中最棘手的部分是路径./dist/APP® TV.wgt中注册符号加空格字符的组合。这是_cmd.exe_的编码噩梦。我建议您将其更改(如果可以)为例如上述npm脚本中的./dist/APP®TV.wgt`。 - RobC
如果要在仅限Windows环境下使用npm默认的_cmd.exe运行,您可能需要考虑将您的package脚本更改为:"package": "yarn package-common && FOR /F %f IN ('yarn -s filename') DO mv ./dist/\"APP®TV.wgt\" ./package/%~f" - 这也将涉及将./dist/APP® TV.wgt路径更改为./dist/APP®TV.wgt,即省略注册符号加空格字符的组合以避免编码问题。 - RobC
2个回答

13
您的基本选择,既可以跨平台,又不需要使用特定于平台的脚本,包括以下内容:
  • 在Windows上也使用Bash

    • 通过WSL在Bash中运行npm脚本,并使用现有的Bash命令,通常包含在package.json文件中,例如在您的情况下。

    • 或者,在安装了Git for Windows之后,配置npm使用bash.exe作为调用命令的shell - 参见此答案 [npm v5.1+]。

  • 在所有平台上安装 PowerShell (Core)(包括Windows),并将命令定义为PowerShell命令(请参阅下文)[npm v5.1+]。

请注意,由于早期版本没有可用于使用特定shell(script-shell)的配置选项,因此需要npm版本5.1或更高版本。运行npm -v获取已安装的版本,并使用npm install -g npm进行更新(如果可能)。


在所有平台上使用PowerShell (Core)与npm [npm v5.1+]:

  • 安装PowerShell Core。

  • 然后将npm配置为使用PowerShell (Core)作为shell(需要npm版本5.1或更高版本):

    • 对于所有您的项目(当前用户)或全局设置(所有用户):

      npm config set script-shell pwsh [--global]
      
    • 针对特定项目(从该项目的根目录):

    • npm config set script-shell pwsh --userconfig ./.npmrc
      
  • 最后,在您项目的package.json文件的scripts键中,将命令定义为PowerShell命令。

例如,在本例中,转换此Bash命令:

yarn package-common && mv './dist/APP® TV.wgt' "./package/$(yarn -s filename)"

注意:我已将''替换为",因为后者更有意义;原始写法中,Bash实际上会丢弃'',并且如果命令包含空格,命令替换$(yarn -s filename)的结果可能会破坏命令。

转化为此PowerShell命令(v7+):

yarn package-common && mi './dist/APP® TV.wgt' "./package/$(yarn -s filename)"

注意:

  • mi是PowerShell的内置别名,对应 Move-Item 命令。

  • 虽然从 PowerShell 中调用脚本很合理,但并非必须的——从 cmd.exe 或批处理文件中调用也可以正常工作。

  • 若要开始使用 PowerShell(Core),请参见 学习 PowerShell;另外,http://hyperpolyglot.org/shell 以简洁、表格形式对比 POSIX类似的 shell(如 Bash)与 cmd.exe及 PowerShell 的语法。


1
在当前项目中,设置配置的“现代”npm语法是npm config set script-shell pwsh --location project。这将创建一个本地的.npmrc文件。 - undefined
谢谢,@ChristianDavén - 我已经相应地更新了答案。 - undefined

0

我要毫不羞耻地推广我的这个解决方案。我遇到了同样的问题,决定写一个小工具来一劳永逸地解决它。结果是一个小型Bash解释器,可以在NodeJS可运行的所有平台上工作,包括Windows。作为一个美好的奖励,它还支持并行运行任务。

简而言之,你可以用bake x代替npm run x,它会正常工作。命令后面指定的所有脚本将并行运行,如果你把@samvv/bake安装为依赖项,你也可以在你的npm脚本中使用它,像这样:

{
  "scripts": {
     "watch:compile-tests": "tsc -w",
     "watch:tests": "ava --watch",
     "test": "ava",
     "lint": "tsc --noEmit",
     "prepare": "npm run lint && webpack --mode production",
     "serve": "webpack serve --mode development",
     "lint-while-testing": "bake lint test"
  }
}

你可以在 这里 找到源代码,使用 npm install -g @samvv/bake 安装该程序包。查看 这篇 Medium 文章 获取更多关于它的信息以及如何使用。

我真心希望这对某些人有所帮助!


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