“node_modules”文件夹是不是应该包含在 git 存储库中

Posted

技术标签:

【中文标题】“node_modules”文件夹是不是应该包含在 git 存储库中【英文标题】:Should "node_modules" folder be included in the git repository“node_modules”文件夹是否应该包含在 git 存储库中 【发布时间】:2013-08-10 08:00:09 【问题描述】:

我想知道我们是否应该在我们的 repo 中跟踪 node_modules 或者在检查代码时执行 npm install?

【问题讨论】:

相关:Should I check in node_modules to git when creating a node.js app on Heroku? 【参考方案1】:

答案不像Alberto Zaccagni suggests那么简单。如果您开发应用程序(尤其是企业应用程序),在您的 git 存储库中包含 node_modules 是一个可行的选择,您选择哪种替代方案取决于您的项目。

因为他对 node_modules 的争论非常好,所以我将专注于他们的论点。

假设您刚刚完成了企业应用程序,您将不得不支持它 3-5 年。你绝对不想依赖别人的 npm 模块,因为它明天就会消失,你不能再更新你的应用了。

或者您的私有模块无法从 Internet 访问,并且您无法在 Internet 上构建您的应用程序。或者您可能出于某种原因不想依赖最终构建在 npm 服务上。

你可以找到优缺点in this Addy Osmani article(虽然是关于鲍尔的,但情况几乎一样)。最后我将引用 Bower 主页和 Addy 的文章:

“如果您编写的包不是打算供其他人使用(例如,您正在构建一个 Web 应用程序),则应始终将已安装的包检查到源代码管理中。”

【讨论】:

我完全同意这一点。我不希望我们的企业构建系统需要互联网连接才能成功构建,因为它需要下载依赖项,希望仍然存在。谢谢。 @Alberto Zaccagni 我相信你第一次是对的。如果您真的在构建企业应用程序,那么您应该使用企业工具。应该使用 Artifactory 和 npm-artifactory 来防止项目从 Internet 上消失。即使在小型项目中,这也比将同一事物的多个副本签入源代码管理更干净。 在left-pad issue之后,我认为跟踪node_modules绝对不是一个坏主意。 没有人提到的重要方面。如果您的 node_modules 在 VCS 下 - 切换分支只是 git checkout foo。如果 node_modules 不在 VCS 下 - 切换分支是 git checkout foo ; npm install 并且您当前的 NPM 版本需要工作;) 最干净的企业解决方案是托管一个内部的 Intranet 可访问的 npm 存储库,其中包含您使用的所有模块版本,并且不要使用源代码签入 node_modules。您的构建系统将引用您的内部节点存储库。【参考方案2】:

模块详细信息存储在packages.json,这就足够了。无需签到node_modules

人们过去常常将node_modules 存储在版本控制中以锁定模块的依赖关系,但现在不再需要npm shrinkwrap。

这一点的另一个理由,正如@ChrisCM 在评论中所写:

另外值得注意的是,任何涉及本机扩展的模块都无法在架构间工作,需要重新构建。提供不将它们包含在 repo 中的具体理由。

【讨论】:

简单,重点是+1。同样值得注意的是,任何涉及本机扩展的模块都无法在架构间工作,需要重新构建。提供不将它们包含在回购中的具体理由。 并非如此,这是使用可重现的开发环境的理由,例如流浪汉。它应该只需要在一个架构上工作。【参考方案3】:

我建议不要签入 node_modules,因为例如 PhantomJS 和 node-sass 等软件包会为当前系统安装适当的二进制文件。

这意味着如果一个开发者在 Linux 上运行 npm install 并签入 node_modules - 它不适用于另一个在 Windows 上克隆 repo 的开发者。

最好检查 npm install 下载的 tarball 并将 npm-shrinkwrap.json 指向它们。您可以使用 shrinkpack 自动执行此过程。

【讨论】:

但是npm install --global shrinkpack 本身是否不具有延迟的弱点,通过要求其他软件包来安装缩小的软件包?这违背了艾迪的建议。 您能否改写问题@danjah?对不起,我不完全理解你。 根据您的描述,需要依赖 shrinkpack 才能可靠地安装构建依赖项。因此,构建工具的安装本身成为反对将所有构建依赖项提交给版本控制的论点的弱点。 我认为至少根据TFM检查锁定文件就足够了(package-lock.json; yarn.lock):docs.npmjs.com/files/package-lock.json 在使用锁文件时你会得到一个可预测的依赖关系图,并且不会受到不同平台上围绕 PhantomJS 和 node-sass 等讨论的问题的影响。当然,您需要互联网连接,并且注册表要正常运行。【参考方案4】:

这个话题很老了,我明白了。但是由于 npm 生态系统的情况发生了变化,我错过了对此处提供的参数的一些更新。

我总是建议不要将 node_modules 置于版本控制之下。到目前为止,在已接受答案的上下文中列出的这样做的几乎所有好处都已经过时了。

    已发布的包不能再轻易地从 npm 注册表中撤销。因此,您不必担心失去项目之前依赖的依赖项。

    将 package-json.lock 文件放入 VCS 有助于处理频繁更新的依赖项,尽管依赖于相同的 package.json 文件,但可能会导致不同的设置。

因此,如果有离线构建工具,将 node_modules 放入 VCS 可能被认为是唯一符合条件的用例。但是,node_modules 通常会增长得很快。任何更新都会改变很多文件。这正在以不同的方式影响存储库。如果您真的考虑到长期影响,那也可能是一个障碍。

像 svn 这样的集中式 VCS 需要通过网络传输已提交和已签出的文件,这在签出或更新 node_modules 文件夹时会非常缓慢。

当涉及到 git 时,如此大量的附加文件会立即污染存储库。请记住,git 不会跟踪任何文件版本之间的差异,而是会在单个字符发生更改时立即存储文件的任一版本的副本。对任何依赖项的每次更新都会导致另一个大型变更集。由于这会影响备份和远程同步,您的 git 存储库将迅速变大。如果您决定稍后从 git 存储库中删除 node_modules,由于历史原因,它仍然是其中的一部分。如果您已将 git 存储库分发到某个远程服务器(例如用于备份),那么清理它是您将遇到的另一项痛苦且容易出错的任务。

因此,如果您关心高效的流程并希望保持“小”,我宁愿使用单独的工件存储库,例如 Nexos 存储库(或只是一些带有 ZIP 存档的 HTTP 服务器),提供一些以前获取的依赖项集下载。

【讨论】:

【参考方案5】:

不使用源代码控制跟踪 node_modules 是正确的选择,因为某些 NodeJS 模块,如 MongoDB NodeJS 驱动程序,使用 NodeJS C++ 附加组件。这些附加组件是在运行npm install 命令时编译的。因此,当您跟踪node_modules 目录时,您可能会不小心提交特定于操作系统的二进制文件。

【讨论】:

【参考方案6】:

我同意ivoszz 的观点,即有时很有用检查 node_modules 文件夹,但是...


场景 1:

一种情况: 您使用从 npm 中删除的包。 如果您在 node_modules 文件夹中拥有所有模块,那么这对您来说不是问题。 如果你在 package.json 中只有包名,你就不能再得到它了。 如果一个包的使用时间少于 24 小时,您可以轻松地将其从 npm 中删除。 如果它超过 24 小时,那么您需要联系他们。 但是:

如果您联系支持人员,他们会检查删除该版本的软件包是否会破坏任何其他安装。如果是这样,我们不会删除它。

read more

所以发生这种情况的可能性很小,但是有第二种情况......


场景 2:

这种情况的另一种情况: 你开发一个企业版的软件或者一个非常重要的软件,并写在你的 package.json 中:

"dependencies": 
    "studpid-package": "~1.0.1"

你使用那个包的function1(x)方法。

现在 studpid-package 的开发人员将方法 function1(x) 重命名为 function2(x) 并且他们犯了一个错误... 他们将包的版本从1.0.1 更改为1.1.0。 这是一个问题,因为当您下次调用 npm install 时,您将接受版本 1.1.0,因为您使用了波浪号 ("studpid-package": "~1.0.1")。

现在调用function1(x) 可能会导致错误和问题。


但是:

将整个 node_modules 文件夹(通常超过 100 MB)推送到您的存储库会占用您的内存空间。 几 kb(仅 package.json)与数百 MB(package.json 和 node_modules)相比......想想吧。

可以做到/应该考虑一下如果:

软件很重要。

发生故障时会花钱。

您不信任 npm 注册表。 npm 是中心化的,理论上可以关闭。

如果出现以下情况,您不需要在 99.9% 的情况下发布 node_modules 文件夹:

您只为自己开发软件。

您已经编写了一些程序,只是想在 GitHub 上发布结果,因为其他人可能会对它感兴趣。


如果您不希望 node_modules 出现在您的存储库中,只需创建一个 .gitignore 文件并添加行 node_modules

【讨论】:

“发布 node_modules 文件夹”的另一个缺点可能是:在 Windows 和 MacOS 上调用 npm install 可能会在某些包中生成不同的文件(依赖于操作系统的文件)。但我不确定。有人可以验证这是真的吗? “场景 2”:这就是你提交 package-lock.json 的原因。如果将来更新 studpid-package 出现问题,您可以回滚锁定文件以找出适合您的确切版本。【参考方案7】:

我想提供一个中间的选择。

    不要在 git 中添加 node_modules。 使用package-lock.json 文件确定您的依赖版本。 在您的 CI 或发布过程中,当您发布一个版本时,请复制 node_modules 文件夹并将其备份(例如,在云存储中)。

在极少数情况下,您无法访问 NPM(或您使用的其他注册表)或 NPM 中的特定包,您拥有 node_modules 的副本并且可以继续工作,直到您恢复访问权限。

【讨论】:

这个答案说明了最佳实践。尽管package-lock.json 仅出现在更高版本中。也许 NodeJS 的早期实现者当时没有这种方法。【参考方案8】:

还有一点需要考虑:签入node_modules 使得使用dependenciesdevDependencies 之间的区别变得更加困难/不可能。

但另一方面,可以说将经过测试的完全相同的代码推送到生产环境是令人放心的 - 所以包括devDependencies

【讨论】:

“生产经过测试的完全相同的代码”:这就是你拥有 Docker 的目的。或者一个 os 包管理器,比如 rpm。您不会在 test 和 prod 之间重建代码,是吗? devDependencies 帮助构建了最终代码,但在部署、测试和生产中都没有位置。 如果 devDependencies 位于它们自己的 package.json 目录中,比“src”目录高一个目录会有帮助吗?由于从当前目录开始搜索节点模块然后向上移动,因此您仍然应该使用您的 dev 依赖项并分离 dev/src 模块。【参考方案9】:

如果 package.json 中提到了依赖项,则不需要签入 node_modules。任何其他程序员都可以通过执行 npm install 来简单地获得它,并且 npm 足够聪明,可以在您的项目工作目录中创建 node_modules。

【讨论】:

以上是关于“node_modules”文件夹是不是应该包含在 git 存储库中的主要内容,如果未能解决你的问题,请参考以下文章

npm 从父目录安装

当我将项目发布到GitHub时,我应该如何处理Grunt的node_modules目录?

vue - node_modules

我应该缩小 node_modules 还是应该使用为在客户端部署提供的缩小版本?

我应该如何排除电子打包器中的所有 node_modules

Laravel Mix 编译资产后是不是还需要 node_modules 文件夹?