npm install 如果 package.json 被修改

Posted

技术标签:

【中文标题】npm install 如果 package.json 被修改【英文标题】:npm install if package.json was modified 【发布时间】:2019-02-27 05:19:42 【问题描述】:

TL;DR:如果您的 package.json 已被修改,有没有办法让 npm install 在运行任何 npm 脚本之前自动运行?

问题场景

您拉取或签出更新了package.json 的分支。你运行npm run my-scriptmy-script 依赖于新添加到 package.json 的包。 my-script 失败。你想知道为什么。在翻转你的桌子之前,你运行npm install 只是为了确定。 my-script 运行成功。你不需要一张新桌子。

我知道像gradle 这样的构建/任务运行工具会在运行任务之前确保您的依赖项是最新的。我一直是npm 不这样做的(次要)痛点。我偶然发现了两个我不太喜欢的解决方案。

非理想解决方案:make

您可以使用 make 并通过以下技巧利用其集成的依赖跟踪,而不是依赖 package.json 中的 npm 脚本来运行命令:

# Smart install: Only executes if package.json's
# modification date is later than node_module's

node_modules: package.json
    npm install
    @rm -f node_modules/.modified
    @touch -m node_modules/.modified

install: node_modules 

来源:https://mattandre.ws/2016/05/make-for-hipsters/

问题是你知道必须依赖 make 来运行脚本,而失去了 npm 脚本的某些优势,例如方便地引用其他脚本和并行运行脚本 (npm-run-all)。如果他们不知道make 或在运行它时遇到问题(Windows),与其他人一起工作也会更加困难。它是 node/npm 生态系统之外的一个过时工具,而且对于这种智能安装优势而言成本太高。

非理想解决方案:Git 挂钩

另一种方法是添加post-merge git hook。

问题是这个解决方案是存储库本地的,不能轻易共享。 npm install 只会在 git 合并时自动运行。当您以任何其他方式更改package.json 时,您仍然必须记住运行npm install。诚然,这在实践中只是一个小问题。尽管如此,当您想要运行脚本时,完全不必考虑运行 npm install 会很好。

来源:https://davidwalsh.name/git-hook-npm-install-package-json-modified

理想的解决方案

我想以类似于以下方式定义我的package.json


  "scripts": 
    "pre-run": "npm-smart-install",
    "my-script": "…"
  ,
  "dependencies": 
    "npm-smart-install": "1.0.0"
  

npm-smart-install 是一个我希望存在的假设 npm 包。 pre-run 是一个假设的 npm-scripts 生命周期钩子。当我运行npm run my-script 并且package.json 自上次运行任何脚本以来已被修改时,请在运行my-script 之前运行npm install

重复一遍:如果您的 package.json 已在不依赖 npm 生态系统之外的工具的情况下被修改,有没有办法让 npm install 在运行任何 npm 脚本之前自动运行?

【问题讨论】:

您自己的假设包可能并不难实现。您可以在第一次安装时生成package.json 的哈希摘要,然后在后续安装中使用它来检查文件是否更改。 This 看起来有类似的功能。 另外,为什么不在任何脚本之前运行npm install?如果一切都存在正确的版本,那么它不会做任何事情。 这会延迟每个脚本的运行。 这听起来像是NPM's tink 希望解决的问题(尽管那是几年之后的事了)。 我的包裹快用完了。试图弄清楚我如何像在理想的解决方案场景中那样执行它。 【参考方案1】:

和其他答案一样,但我认为更简单,因为它是 package.json 中的一行 shell 脚本:


    "scripts": 
        "install-if-needed": "[ package.json -nt node_modules ] && npm install && touch node_modules",
        "my-script": "npm run install-if-needed && ..."
    

或者,基本等价:


    "scripts": 
        "install-if-needed": "[ package.json -nt node_modules ] && npm install && touch node_modules",
        "premy-script": "npm run install-if-needed",
        "my-script": "..."
    

对于每个需要它的脚本,您必须内联 npm run install-if-needed 或拥有一个 pre... 脚本——我不知道有什么其他方法可以让它在多个其他脚本之前运行。

解释:install-if-needed 检查package.jsonnode_modules 的修改时间。如果node_modules 更新,它什么也不做;否则它运行npm install。最后的touch node_modules 是必要的,因为npm install 本身可能会更改 package.json 的修改时间(例如,如果它正在更正 package.json 中的空白)。

【讨论】:

node_modules 的最后修改时间不会像 npm/yarn lockfile 的哈希一样可靠:/【参考方案2】:

您可以创建一个自定义脚本来运行您的智能安装。

smart-install.sh 文件

#!/usr/bin/env bash

changedFiles="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"

checkForChangedFiles() 
    echo "$changedFiles" | grep --quiet "$1" && eval "$2"


packageJsonHasChanged() 
  echo "Changes to package.json detected, installing updates"
  npm i


checkForChangedFiles package.json packageJsonHasChanged

然后,如果您有哈士奇犬,您可以将其添加到结帐后挂钩或您喜欢的任何挂钩中。如果你没有 husky,你也可以直接将它添加到本质上做同样事情的脚本中。

.huskyrc 文件


  "hooks": 
    "post-checkout": "npm run smart-install"
  

package.json 文件

"scripts": 
  ...
  "smart-install": "bash ./bin/smart-install.sh",

无论哪种方式,最好创建一个 npm 脚本来运行 smart-install

【讨论】:

类似yarnhook:github.com/frontsideair/yarnhook【参考方案3】:

好的,我已经完成了包裹。 Here 是。您可以完全按照您在理想场景中指定的方式使用它。只需 npm install install-changed 并将其添加到自定义脚本中,例如您的示例中的 pre-run。它应该弄清楚它是否需要npm install,如果需要就这样做。

 
  "scripts": 
    "pre-run": "install-changed",
    "my-script": "…"
  ,

您也可以通过编程方式执行此操作,但我认为您不需要它。

let installChanged = require('install-changed')

let isModified = installChanged.watchPackage() 

上面的函数做同样的事情,此外它还返回一个布尔值,你可能会发现它很有用。

【讨论】:

干得好!我只是希望 npm 有一个集成的“预运行”钩子。就像现在一样,我必须写"my-script": "npm run prerun && …""premy-script": "install-changed", "my-script": "…" 而不是packagehash.txt,它应该使用git历史记录中package.json的当前版本 install-changed 有一个 fork,叫做package-changed,它基本上是一样的,但更灵活,允许你在 package.json deps/devDeps 变化时运行任何命令。然后我分叉了这个分支并将其命名为lockfile-changed,因为它只是创建了yarn.lock 内容的哈希值。这都是关于纱线的。我建议使用package-changed,除非你真的希望它基于 yarn.lock+use yarn。如果你使用我的包,它可能有错误。我还没有完全测试过。

以上是关于npm install 如果 package.json 被修改的主要内容,如果未能解决你的问题,请参考以下文章

npm install 如果 package.json 被修改

[Vue] npm install 如果安装node-sass失败,可以用如下方法解决

[Vue] npm install 如果安装node-sass失败,可以用如下方法解决

npm install -g 和npm install --save-dev的关系

npm install 后缀

几种npm install 的区别