javascript - 在没有 "npm run x"条目的情况下实现 "scripts"行为?

标签 javascript node.js npm command-line-interface

在已安装的“上下文”中运行 Node 命令 node_modules ,您可以在 scripts 中输入领域package.json .例如:

...
  "scripts": {
    "test": "mocha --recursive test/**/*.js --compilers js:babel-register"
  }
...

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

有没有办法在不创建脚本条目的情况下实现完全相同的行为?例如,一次性的“脚本”?

我正在想象类似以下的内容,相当于 npm run test :
npm cmd mocha --recursive test/**/*.js --compilers js:babel-register

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

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

最佳答案

注意:此答案解决了 OP 的特定用例:在给定项目的上下文中调用依赖包的 CLI;这与使 CLI 全局可用无关 - 请参阅底部的讨论。

tl;博士:

在类 Unix 平台上 , 前置 npm run env --到您的命令 ;例如。:

npm run env -- mocha --recursive test/**/*.js --compilers js:babel-register

不仅允许仅通过名称调用依赖 CLI,而且完全复制了 npm 的环境。套幕后使用 npm testnpm run-script <script-defined-in-package.json> .

遗憾的是,这种方法不适用于 Windows。

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

有两个(不相互排斥)使 npm 项目的依赖项的 CLI 可从 shell 中仅通过名称调用的方法 :
  • (a) 使用 您将命令传递给 的每次调用帮助程序命令.
  • (b) 运行 (临时)修改您的环境的每 session 一次命令 .

  • Frxstrem's helpful answer在类 Unix 平台上为 (a) 提供了一个不完整的解决方案;但是,这可能就足够了,具体取决于您的特定需求。
    它是不完整的,因为它只是将包含(符号链接(symbolic link))依赖 CLI 的目录添加到 $PATH 中。 ,而不执行调用 npm test 时发生的所有其他环境修改或 npm run-script <script-defined-in-package.json .

    Unix 便利性和 Windows 解决方案

    请注意 以下所有解决方案均基于 npm run env ,确保设置所有必要的环境变量,就像在项目的 package.json 中预定义的运行脚本时一样。文件与 npm testnpm run-script <script> .
    这些环境修改包括:
  • 前置 $(npm prefix -g)/node_modules/npm/bin/node-gyp-bin和项目目录的 ./node_modules/.bin子目录,这是指向依赖项的 CLI 的符号链接(symbolic link)所在的位置,(临时)到 $PATH环境变量。
  • 定义无数 npm_*反射(reflect)项目设置的环境变量,例如 npm_package_version以及 npm/node环境。


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

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

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

    (a) 每次调用的助手:

    定义

    alias nx='npm run-script env --'
    

    允许您通过添加 nx 来临时调用您的命令;例如。:

    nx mocha --recursive test/**/*.js --compilers js:babel-register
    

    (b) 每 session 一次配置命令:

    alias npmenv='npm run env -- $SHELL'
    

    运行 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
    

    视窗解决方案:

    (a) 和 (b) :请注意,Windows(与类 Unix 平台上的类 POSIX shell 不同)不(直接)支持传递范围仅限于单个命令的环境变量,因此下面的命令,即使传递了要执行的特定命令(案例(a )),也总是修改 session 的环境(情况(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
        }
      } 
    }
    

    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.
    %*
    

    用法 (cmd.exe 和 PowerShell):

    对于用例 (b),简单地调用为 npmenv没有论据;之后,您可以仅通过名称 ( mocha ... ) 调用依赖 CLI。

    对于用例 (a),添加 npmenv听你的命令;例如。:

     npmenv mocha --recursive test/**/*.js --compilers js:babel-register
    

    警告:如前所述,第一次调用 npmenv - 无论有无参数 - 总是修改 %PATH%/$env:PATH session 剩余时间的变量。

    如果您在同一 session 中切换到不同的项目,请确保运行 npmenv (至少一次),但请注意,这将附加目录添加到 %PATH% ,因此如果它不是当前项目的已安装依赖项,您仍然可能会意外地运行先前项目的可执行文件。

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

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

    OP 的问题是关于在给定项目的上下文中临时调用已安装的依赖包的 CLI,仅通过可执行名称 - 就像 npm允许你在命令中添加 scripts关键在 package.json文件。

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

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

    特别是,如果给定的 CLI 已经作为依赖项安装,那么全局安装它(可能是不同的版本)不仅是多余的,而且会混淆何时执行哪个版本。

    关于javascript - 在没有 "npm run x"条目的情况下实现 "scripts"行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39990788/

    相关文章:

    javascript - Cursor.forEach 不是 Node.js 函数

    node.js - 将node_modules或bower_components复制到Web应用程序中的static/public目录

    node.js - 安装sqlite3时node-pre-gyp出错

    javascript - 如何使用 $.ajax{} 使用 ajax 更新 html

    javascript - Electron 中内容周围的黑色边框

    javascript - "the remote procedure call failed"- 仅限 IE

    node.js - Node js中的单元测试/模拟谷歌数据存储

    npm install 因多层本地依赖项而失败

    javascript - 使用 `npm install font-awesome` 时出错

    Javascript 正则表达式模式匹配