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

Bra*_*ing 6 npm snowpack

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

“问题”是,当我安装一个包时,我必须首先运行npm install --save my-package,然后我必须用npx snowpack. 在积雪文档提到,我可以包括prepare脚本,将snowpack一切都运行后npm install,但这并不适用于单个包,只是一个普通的npm install在我所有的依赖关系package.json。据我所知,npm 文档中提到的所有 npm 钩子都是这种情况。

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

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

这是不够的运行snowpack后,只需运行npm install,你会被钩住得到postinstallrelease。此外,我想确保在我的项目上工作的开发人员可以npm install --save newdep像往常一样使用然后snowpack运行。我不想要求开发人员使用自定义命名脚本。

Rob*_*obC 9

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

生命周期钩子/脚本postinstall仅在运行通用npm install命令时调用,而不是npm install --save <pkg_name>在项目开发阶段有人运行时调用。


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

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

  • 在您的项目上工作的开发人员在运行复合命令时必须将他们的 shell 设置为Bashnpm install --save
  • 处理您的项目的开发人员需要自定义他们的 Bash启动文件,即~/.bashrc并且可能是~/.bash_profile.
  • 项目目录,即您希望自定义逻辑对其生效的项目目录,必须包含一个自定义.bashrc文件。

猛击解决方案:

以下三个步骤是配置您的项目和操作系统所必需的,以便在开发人员运行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=$1
        shift
        for el in "$@"; do [[ "$el" == "$word" ]] && return 0; done
      }
    
      log_warn_message() {
        local cmd_name=$1 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
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

  2. ~/.bashrc文件:

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

    PROMPT_COMMAND='if [[ "$bashrc" != "$PWD" && "$PWD" != "$HOME" && -e .bashrc ]]; then bashrc="$PWD"; . .bashrc; fi'
    
    Run Code Online (Sandbox Code Playgroud)

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

  3. ~/.bash_profile文件:

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

    if [ -f ~/.bashrc ]; then . ~/.bashrc; fi
    
    Run Code Online (Sandbox Code Playgroud)

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


附加信息。

设置/配置助手:

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

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

    echo $'\n'"PROMPT_COMMAND='if [[ \"\$bashrc\" != \"\$PWD\" && \"\$PWD\" != \"\$HOME\" && -e .bashrc ]]; then bashrc=\"\$PWD\"; . .bashrc; fi'" >> ~/.bashrc
    
    Run Code Online (Sandbox Code Playgroud)

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

  2. 对于第三步,运行以下命令以附加~/.bash_profile加载~/.bashrc文件所需的代码行:

    echo $'\n'"if [ -f ~/.bashrc ]; then . ~/.bashrc; fi" >> ~/.bash_profile
    
    Run Code Online (Sandbox Code Playgroud)

我的 shell 是否配置为 Bash?

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

echo $0
Run Code Online (Sandbox Code Playgroud)

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

如何将我的 shell 配置为 Bash?

如果echo $0不打印,-bash则您需要更改外壳。要将其更改为 Bash 运行:

chsh -s /bin/bash
Run Code Online (Sandbox Code Playgroud)

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


解释

  1. 项目特定.bashrc文件:

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

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

      echo $0
      
      Run Code Online (Sandbox Code Playgroud)

      本质上读取$* 特殊参数以检查传递给npm函数的参数是否以任一开头;install ,或者它的速记等价物i ,以及是否--save也通过了选项/参数。

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

      chsh -s /bin/bash
      
      Run Code Online (Sandbox Code Playgroud)

      或这个(或其他一些变体):

      if [[ $* == "install "* || $* == "i "* ]] && array_includes --save "$@"; then
        ...
      fi
      
      Run Code Online (Sandbox Code Playgroud)
    • if满足语句中指定的条件时,即它们是true,我们在其主体中执行以下任务:

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

        # Example showing `--save` option at the end
        npm install <pkg_name> --save
        
        Run Code Online (Sandbox Code Playgroud)
      2. npx通过读取的部分检查命令是否全局存在:

        # Example showing `--save` option in the middle
        npm i --save <pkg_name>
        
        Run Code Online (Sandbox Code Playgroud)

        如果该npx命令不可用(全局),我们会警告用户该npx snowpack命令无法运行,并return在退出状态为1.

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

      3. 如果该npx命令全局存在,则我们运行伪“postinstall”命令,即

        command npm "$@"
        
        Run Code Online (Sandbox Code Playgroud)
    • if语句中指定的条件不满足时,即它们是false,用户实际上是在运行任何其他不满足的 npm 命令npm install --save <pkg_name>。因此,在else分支中,我们按原样运行命令:

      command -v npx >/dev/null 2>&1 || {
        log_warn_message npx
        return 1
      }
      
      Run Code Online (Sandbox Code Playgroud)
  2. ~/.bashrc 文件:

    《Bash 参考手册》5.2 Bash Variables小节中,该变量描述如下:PROMPT_COMMAND

    PROMPT_COMMAND

    如果设置,该值将被解释为在打印每个主要提示 ( $PS1)之前执行的命令。

    所以,这行代码(又来了):

    command npx snowpack
    
    Run Code Online (Sandbox Code Playgroud)

    加载“项目特定” .bashrc(如果存在),这反过来又会npmnpm函数覆盖命令。这实质上提供了一种覆盖npm install --save特定项目的复合命令的机制。

    这个答案@Cyrus作进一步的解释。

  • 这个答案花费了很多时间和精力,但这显然太过分了。我不质疑你答案的合法性,它会产生OP所追求的效果。想想那些继续他的项目但没有参与的人。此外,这并不支持跨平台,但它看起来确实是一个很好的概念证明,再次证明一切皆有可能。 (3认同)

Bra*_*ing 2

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