运行 npm 安装单个包后的脚本(如安装后)?

Run a script (like postinstall) after npm installing a single package?

我开始玩 Snowpack。它采用与 Webpack 不同的方法,在安装后立即捆绑单个包。

"issue" 是,当我安装一个包时,我必须先 运行 npm install --save my-package 然后我必须用 npx snowpack 手动打包它。 Snowpack docs mention that I can include a prepare script that would snowpack everything after running npm install but that doesn't apply to individual packages, just on a generic npm install of all dependencies in my package.json. As far as I can tell, this is the case for all npm hooks mentioned in the npm docs.

有什么方法可以在我安装单个软件包时自动 运行 脚本?我能想到的唯一方法是覆盖安装脚本并向其中添加一些内容。 GitHub 或其他地方有这样的例子吗?

更新: 为了澄清起见,我想 运行 npx snowpack 每次安装带有 --save 的新软件包时,但最好不带 --save-dev 或不带 --save。这对于任何包都不会有所不同。这将特定于某个 repo/project,在我的系统上不是全局的。

仅仅 运行 宁 npm install 之后 运行 snowpack 是不够的,就像挂钩到 postinstallrelease.此外,我想确保从事我的项目的开发人员可以像往常一样使用 npm install --save newdep,然后 snowpack 将 运行。我不想要求开发人员使用自定义 named 脚本。

我认为最好的办法是创建一个执行所需操作的新脚本。您的 package.json 中的以下内容:

{
  "scripts": {
    "snowpack-install" : "npm install --save && npx snowpack"
  }
}

更正

您实际上可以在 package.json 中使用 postinstall option。安装后将 运行 "AFTER the package is installed"。这看起来像下面这样:

{
  "scripts": {
    "postinstall" : "npx snowpack"
  }
}

简短回答:很遗憾,npm 不提供任何内置功能来满足您的要求。

生命周期 hooks/scripts 例如 postinstall are invoked only when running the generic npm install 命令,而不是在项目开发阶段有人 运行s npm install --save <pkg_name> 时。


解决方法: 考虑通过实质上覆盖 shell 级别的 npm 命令来自定义 npm install --save 复合命令的逻辑。

尽管是 Bash 解决方案,但以下解决方案描述了如何为特定项目实现此自定义逻辑。但是,此解决方案取决于以下条件:

  • 当 运行 使用 npm install --save 复合命令时,从事您项目的开发人员必须将 shell 设置为 Bash
  • 从事您的项目的开发人员将需要自定义他们的 Bash startup files,即 ~/.bashrc 并且可能 ~/.bash_profile
  • 项目目录,即您希望自定义逻辑生效的项目目录,必须包含自定义 .bashrc 文件。

Bash 解法:

以下三个步骤是配置您的项目和操作系统所必需的,因此当开发人员 运行s npm install --save <pkg_name>(或其变体)npx snowpack 命令随后被调用。

注意:第二点和第三点(下方)是开发人员需要执行(一次)以自定义其 Bash 启动文件的任务。

  1. 项目具体.bashrc文件:

    首先在项目目录的根目录中创建以下“项目特定” .bashrc文件,即将其保存在项目所在的同一级别package.json 文件所在:

    /some/path/to/my-project/.bashrc

    npm() {
    
      local name_badge="\x1b[37;40mpostinstall\x1b[0m"
    
      array_includes() {
        local word=
        shift
        for el in "$@"; do [[ "$el" == "$word" ]] && return 0; done
      }
    
      log_warn_message() {
        local cmd_name= warn_badge warn_mssg
        warn_badge="\x1b[30;43mWARN!\x1b[0m"
        warn_mssg="${cmd_name} command not found. Cannot run npx snowpack."
        echo -e "\n${name_badge} ${warn_badge} ${warn_mssg}" >&2
      }
    
      log_run_message() {
        echo -e "\n${name_badge} Running pseudo postinstall hook."
      }
    
    
      if [[ $* == "install "* || $* == "i "* ]] && array_includes --save "$@"; then
    
        # 1. Run the given `npm install --save ...` command.
        command npm "$@"
    
        # 2. Check whether the `npx` command exists globally.
        command -v npx >/dev/null 2>&1 || {
          log_warn_message npx
          return 1
        }
    
        log_run_message
    
        # 3. Run the pseudo "postinstall" command.
        command npx snowpack
    
      else
        # Run all other `npm` commands as per normal.
        command npm "$@"
      fi
    }
    

    注意: 要更好地理解此文件的作用,请参阅下面的 “说明” 部分。

  2. ~/.bashrc文件:

    要使自定义逻辑,即上述.bashrc文件中的npm函数生效,需要配置Bash读取上述"特定项目 .bashrc 文件。要配置它,请将以下代码行添加到 ~/.bashrc:

    PROMPT_COMMAND='if [[ "$bashrc" != "$PWD" && "$PWD" != "$HOME" && -e .bashrc ]]; then bashrc="$PWD"; . .bashrc; fi'
    

    注意:为了更好地理解这行代码的作用,请参阅“说明”部分下面.

  3. ~/.bash_profile 文件:

    通常您的 ~/.bash_profile 包含以下代码行来加载 ~/.bashrc 文件(或它的一些变体):

    if [ -f ~/.bashrc ]; then . ~/.bashrc; fi
    

    如果不存在,则必须将其添加到 ~/.bash_profile


附加信息。

Setup/Configuration 帮手:

考虑您的开发人员使用以下两个命令来帮助配置他们的 Bash 启动文件,按照上述第二步和第三步。

  1. 对于第二步,运行以下命令:

    echo $'\n'"PROMPT_COMMAND='if [[ \"$bashrc\" != \"$PWD\" && \"$PWD\" != \"$HOME\" && -e .bashrc ]]; then bashrc=\"$PWD\"; . .bashrc; fi'" >> ~/.bashrc
    

    这会将 PROMPT_COMMAND=... 行代码添加到现有的 ~/.bashrc 文件中,或者创建一个新文件(如果尚不存在):

  2. 对于第三步,运行 下面的命令在 ~/.bash_profile 中附加必要的代码行以加载 ~/.bashrc 文件:

    echo $'\n'"if [ -f ~/.bashrc ]; then . ~/.bashrc; fi" >> ~/.bash_profile
    

我的shell配置成Bash了吗?

要检查 shell 是否配置为 Bash 您可以创建一个新会话,即创建一个新终端 window 和 运行:

echo [=15=]

如果它打印 -bash 那么它正在使用 Bash.

如何将 shell 配置为 Bash?

如果 echo [=54=] 不打印 -bash,那么您需要更改 shell。将其更改为 Bash 运行:

chsh -s /bin/bash

注意:您需要创建一个新会话才能使此更改生效。


说明

  1. 项目具体.bashrc文件:

    .bashrc 文件包含一个名为 npmshell function。此函数的主体包含覆盖默认 npm install|i --save 命令所需的逻辑。

    • if语句中指定的条件,即读到的部分;

      if [[ $* == "install "* || $* == "i "* ]] && array_includes --save "$@"; then
        ...
      fi
      

      本质上是读取 $* special parameter 以检查传递给 npm 函数的参数是否以其中之一开头; install ,或者是 shorthand 等价的 i ,以及 --save option/argument 是否也通过了。

      为了检查 --save 参数是否存在,我们将 $@ 特殊参数传递给 array_includes 函数。我们以不同方式处理此参数,因为 --save 选项在复合命令中的位置可能不同。例如,用户可以通过 运行ning this;

      安装一个包
      # Example showing `--save` option at the end
      npm install <pkg_name> --save
      

      或这个(或其他变体):

      # Example showing `--save` option in the middle
      npm i --save <pkg_name>
      
    • 当满足 if 语句中指定的条件时,即它们是 true,我们在其主体中执行以下任务:

      1. 运行 给定的 npm install --save ... 命令原样通过以下行:

        command npm "$@"
        
      2. 检查npx命令是否全局存在通过读取的部分:

        command -v npx >/dev/null 2>&1 || {
          log_warn_message npx
          return 1
        }
        

        如果 npx 命令不可用(全局),我们警告用户 npx snowpack 命令不能 运行,并且 return 尽早从函数中使用1.

        的退出状态

        注意:我在这个检查中的逻辑假定您将在全局安装 npx。但是,如果您在项目中本地安装 npm,则需要更改此逻辑。也许通过检查 ./node_modules/.bin/npx 是否存在来代替。或者,您可能确信 npx 命令将始终存在,因此断定此检查是不必要的。

      3. 如果 npx 命令全局存在,那么我们 运行 伪“安装后”命令,即

        command npx snowpack
        
    • if 语句中指定的条件不满足时,即它们是 false,用户本质上是 运行ning 任何其他 npm 命令那不是 npm install --save <pkg_name>。因此,在 else 分支中,我们 运行 按原样执行命令:

      command npm "$@"
      
  2. ~/.bashrc 文件:

    Bash参考手册5.2 Bash Variables部分PROMPT_COMMAND变量描述如下:

    PROMPT_COMMAND

    If set, the value is interpreted as a command to execute before the printing of each primary prompt ($PS1).

    因此,这行代码(再次出现):

    PROMPT_COMMAND='if [[ "$bashrc" != "$PWD" && "$PWD" != "$HOME" && -e .bashrc ]]; then bashrc="$PWD"; . .bashrc; fi'
    

    加载“项目特定”.bashrc(如果存在的话),它又用 npm 函数覆盖 npm 命令。这本质上是为特定项目提供覆盖 npm install --save 复合命令的机制。

    请参阅 @Cyrusthis answer 以获得进一步的解释。

使用较新版本的 Snowpack (>=2),您可以 运行 snowpack dev 并且它会监视您的 npm_modules 文件夹以寻找要构建的新模块。