在没有"脚本"条目的情况下实现"npm run x"行为?

Jon*_*nah 13 javascript command-line-interface node.js npm

要在已安装的"上下文"中运行节点命令node_modules,可以在scripts字段中输入package.json.例如:

...
  "scripts": {
    "test": "mocha --recursive test/**/*.js --compilers js:babel-register"
  }
...
Run Code Online (Sandbox Code Playgroud)

然后我可以输入npm run test我的项目根目录,然后运行mocha测试(通过调用安装的mocha二进制文件node_modules/mocha/bin).

有没有办法实现完全相同的行为,但没有创建脚本条目?例如,对于一次性"脚本"?

我想象的东西如下,相当于npm run test:

npm cmd mocha --recursive test/**/*.js --compilers js:babel-register
Run Code Online (Sandbox Code Playgroud)

有没有办法实现这个目标?

注意:我应该澄清我正在寻找真正的等价.也就是说,我的命令应该能够访问其他脚本命令等.我知道你总是可以使用node和node_modules中二进制文件的路径调用二进制文件,但这不是一个合适的解决方案.

mkl*_*nt0 15

注意:这个答案解决了OP的特定用例:在给定项目的上下文中调用依赖包的CLI ; 它不是关于使全球可用的 CLI - 请参阅底部讨论.

TL;博士:

类Unix的平台上,在你的命令前面npm run env -- ; 例如:

npm run env -- mocha --recursive test/**/*.js --compilers js:babel-register
Run Code Online (Sandbox Code Playgroud)

不仅可以通过名称调用依赖CLI,还可以完全复制npm使用npm test或后台设置的环境npm run-script <script-defined-in-package.json>.

遗憾的是,这种方法在Windows上不起作用.

对于Windows解决方案,请继续阅读便利别名(包括每会话一次的环境配置命令)和背景信息.


有两种(不是相互排斥的)方法使npm项目的依赖项的CLI可以通过shell中的名称来调用:

  • (a)使用您将命令传递给的per-invocation helper命令.
  • (b)运行每会话一次的命令(暂时)修改您的环境.

Frxstrem的有用答案为(a)类Unix平台提供了不完整的解决方案; 但是,根据您的具体需求,它可能就足够了.
它是不完整的,因为它仅仅是预先考虑包含(符号连接)依赖的CLI到该目录$PATH,而不执行,当你调用发生的所有其他环境中修改npm testnpm run-script <script-defined-in-package.json.


Unix方便和Windows解决方案

请注意,下面的所有解决方案都基于npm run env,它确保设置所有必需的环境变量,就像在项目package.json文件中使用npm test或预定义运行脚本时一样npm run-script <script>.
这些环境修改包括:

  • 前置$(npm prefix -g)/node_modules/npm/bin/node-gyp-bin和项目目录的./node_modules/.bin子目录,即依赖项CLI的符号链接(临时)到$PATH环境变量的位置.
  • 定义众多npm_*的环境变量,反映该项目的设置,如npm_package_version还有npm/ node环境.

类Unix平台的便捷解决方案:

下面的两个解决方案都是基于别名,在(a)的情况下是使用脚本的更轻量级的替代方案,并且在(b)的情况下是允许修改当前shell环境的先决条件(尽管也可以使用shell函数).

为方便起见,请将这些别名添加到shell配置文件/初始化文件中.

(a)每次调用助手:

定义

alias nx='npm run-script env --'
Run Code Online (Sandbox Code Playgroud)

允许你简单地通过前置来调用你的命令nx; 例如:

nx mocha --recursive test/**/*.js --compilers js:babel-register
Run Code Online (Sandbox Code Playgroud)

(b)每会话一次配置命令:

alias npmenv='npm run env -- $SHELL'
Run Code Online (Sandbox Code Playgroud)

运行npmenv以使用npm环境集进入子shell,允许在该子shell中直接(仅按名称)调用依赖CLI.
换句话说,使用如下:

cd ~/some-npm-project
npmenv # after this, you can run dependent CLIs by name alone; e.g., `mocha ...`
# ... run your project-specific commands
exit  # exit the child shell before you switch to a different project
Run Code Online (Sandbox Code Playgroud)

Windows解决方案:

(a)(b):请注意,Windows(与类Unix平台上的类似POSIX的shell)不会(直接)支持仅作用于单个命令的传递环境变量,所以下面的命令,即使传递给特定的命令执行命令(case(a)),总是也修改会话的环境(case(b)).

PowerShell(也适用于Unix版本):

将以下函数添加到$PROFILE(特定于用户的配置文件脚本):

function npmenv($commandIfAny) {
  npm run env -- |
    ? { $_ -and $_ -notmatch '^>' -and $_ -match '^[a-z_][a-z0-9_]+=' } | 
      % { $name, $val = $_ -split '='; set-item -path "env:$name" -value $val }
  if ($?) {
    if ($commandIfAny) {
      & $commandIfAny $Args
    }
  } 
}
Run Code Online (Sandbox Code Playgroud)

cmd.exe (常规命令提示符,经常错误地称为"DOS提示符"):

创建一个名为的批处理文件npmenv.cmd,将其放在您的文件夹中%PATH%,并按如下方式定义:

@echo off
:: Set all environment variables that `npm run env` reports.
for /f "delims==; tokens=1,*" %%i in ('npm run env ^| findstr /v "^>"') do set "%%i=%%j"
:: Invoke a specified command, if any.
%*
Run Code Online (Sandbox Code Playgroud)

用法(兼具cmd.exe和PowerShell):

对于用例(b),简单地调用npmenv 不带参数 ; 之后,您可以通过名称(mocha ...)调用依赖CLI .

对于用例(a),npmenv请在命令前加上; 例如:

 npmenv mocha --recursive test/**/*.js --compilers js:babel-register
Run Code Online (Sandbox Code Playgroud)

警告:如上所述,第一次调用npmenv- 无论是否带有参数 - 总是会修改会话剩余部分的%PATH%/ $env:PATHvariable.

如果你在同一个会话中切换到另一个项目,请确保再次运行npmenv(至少一次),但请注意,这会预先添加其他目录%PATH%,因此如果不是,您仍然可能会意外地运行以前项目的可执行文件现在项目的已安装依赖项.

从PowerShell中,您实际上可以将这两个解决方案结合起来,以获得不同的(a)和(b)功能:将*.cmd上面的文件定义为一个独特的命令(使用不同的名称,例如nx.cmd),您只使用参数(a),并重新定义PowerShell函数作为无参数环境修改的补充(b).
这是有效的,因为PowerShell总是*.cmd进程中运行文件,这些文件不会影响当前的PowerShell会话环境.


关于问题范围和答案的说明:

OP的问题是关于在特定项目 ad-hoc 的上下文中调用已安装的依赖包的CLI ,仅仅是可执行名称 - 就像npm允许您在添加到文件中的scripts键的package.json命令中一样.

问题在于使CLI 全局可用(通过安装它们npm install -g).

实际上,如果要创建模块化,自包含的包,请不要依赖全局安装的包.相反,将所有依赖包作为项目的一部分:使用npm install --save(用于运行时依赖性)和npm install --save-dev(仅用于开发时依赖性) - 请参阅https://docs.npmjs.com/cli/install

特别地,如果一个给定的CLI已安装作为依赖性,安装它全局以及(可能在不同版本)不仅是多余的,但要求在其版本是在被执行时的混乱.

  • 旁白:我通常会将两个前面的注释移到一个附录中,这样它们就可以让人们不在了 - 但是你的代表很高,因此知道这里的事情是如何运作的.我个人认为,投票建议和评论根本不属于职位,如果你能把它删除,那将是理想的; 它对大多数读者来说是没有用的,他们不记得从不介意投票,但实际上也没有任何"错误"投票这样的事情.好的帖子将在长期内获得赞成. (2认同)