npm中bundledDependencies相对于普通依赖的优势

105

npm 允许我们指定 bundleDependencies,但这样做有什么好处呢?我猜如果我们想要确保即使引用的模块被删除,也能获得正确的版本,或者捆绑会带来速度上的优势?

有人知道 bundledDependencies 相对于普通依赖项的优势吗?


17
如果这个拼写是“bundleDependencies”,那也是可以的。文档写得非常好! - Colonel Panic
11
然而,仅仅改为“也受到尊敬”这样的修饰词会使人感到悲伤。如果我身处困境,需要一位武士或骑士前来帮助,我肯定希望他配备相应的武器和盔甲,并且是一个有荣誉感的人。 - Jon Coombs
3
“我猜想,即使我们所引用的模块被删除了,如果我们想要确保获取正确的版本,这个想法突然变得非常重要。”这个想法现在变得非常重要:http://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm - joews
1
另请参见https://dev59.com/72gu5IYBdhLWcg3wQE4D。 - Anon
6个回答

119

对于快速阅读者:此问答涉及package.json的bundledDependencies字段,而非package

bundledDependencies的作用

“bundledDependencies”正如其名。这些依赖应该在您的项目内部。因此,其功能与普通依赖基本相同。运行npm pack时,它们也将被打包。

何时使用它们

通常情况下,正常的依赖项是从npm注册表中安装的。 因此,当:

  • 您想要重用来自npm注册表之外或已修改的第三方库
  • 您想要将自己的项目重用为模块
  • 您想要分发一些文件与您的模块

这样,您就不必创建(和维护)自己的npm存储库,但仍能获得与npm软件包相同的好处。

何时使用捆绑的依赖关系

在开发过程中,我认为主要的重点不是防止意外更新。我们有更好的工具来做到这一点,即代码仓库(git、mercurial、svn...)或现在的锁定文件。

要固定您的软件包版本,您可以使用:

  • 选项1:使用新版NPM 5,它随node 8一起发布。它使用一个package-lock.json文件(请参见node blog和node 8发布说明)

  • 选项2:使用yarn而不是npm。 它是Facebook的软件包管理器,比npm更快,并使用yarn.lock文件。否则,它使用相同的package.json

这类似于其他包管理器(如Bundler或Cargo)中的锁定文件。它类似于npm的npm-shrinkwrap.json,但不会丢失信息,并且可以创建可重现的结果。

npm 实际上是从其他地方复制了这个功能,其中包括 yarn

  • 选项3: 这曾经是先前推荐的方法,但我不再推荐使用。其想法是大多数情况下使用 npm shrinkwrap,有时将整个内容(包括 node_module 文件夹)放入代码库中。或者可能使用 shrinkpack。当时的最佳实践在 node.js 博客joyent developer 网站上进行了讨论。

另请参阅

这可能有些超出问题的范围,但我想提一下我所知道的最后一种依赖关系类型:peer dependencies。还请参阅此相关SO问题和可能关于bundledDependenciesyarn文档。


6
“包括node_module文件夹” - 这是一件相当奇怪的事情,它会在你的代码库中添加生成的代码...特别是当你使用本地模块时... - Oleksandr
@Olexandr 在这个和冒着包破坏你应用的风险之间,我想选择是很容易的。请注意,您可以将其放在单独的分支中(例如使用git)。同意,这远非理想的解决方案。 - nha
4
基于像phantomjs这样的软件包,我建议不要提交node_modules文件夹,因为它会在当前系统上安装相应的二进制文件。这意味着,如果一个开发人员在Linux上运行npm install并检入node_modules文件夹,那么在Windows上克隆代码库的另一位开发人员将无法使用它。最好是提交npm install下载的tarball,并在npm-shrinkwrap.json中指向它们。您可以使用“npm install -g shrinkpack”工具自动完成此过程。 - Jamie Mason
1
谢谢@nha,你也可以使用shrinkpack来保护自己,因为注册表tarballs将在你的项目存储库中。 - Jamie Mason
1
@fold_left 是的,确实,谢谢你指出这一点(以及制作shrinkpack)。我只是在说,如果npm注册表像不可变数据存储一样运行,所有这些都可以避免。 - nha
显示剩余2条评论

50

目前Node面临的最大问题之一是它变化非常快。这意味着生产系统可能非常脆弱,npm update可能很容易破坏它们。

使用bundledDependencies可以解决这个问题,确保无论其他内容如何更改,您始终会提供正确的依赖项,正如您正确猜测的那样。

您还可以使用它来捆绑您自己的私有包,并将它们与安装一起交付。


1
它是如何始终提供正确的依赖项的?这是否意味着npm update不会影响bundledDependencies中的任何依赖项? - Kevin Ghadyani
2
是的,正确的。请注意,捆绑的依赖项可能在任何根本上都不是“正确”的。它们只是捆绑者认为是正确的东西。 - Julian Knight
7
也许是因为你在看一个已经有五年半历史的答案!Node.JS 在这段时间内的发展是惊人的。也许你可以留下一些有用的评论? - Julian Knight

25

另一个好处是,您可以将内部依赖项(应用程序组件)放在那里,然后仅需像独立模块一样在应用程序中要求它们,而不会使您的 lib/ 混乱,并将它们发布到 npm。

如果/当它们成熟到可以作为单独模块存在的程度时,您可以轻松地将它们放在 npm 上,而无需修改代码。


5
我很惊讶这里还没有看到这个,但是在仔细选择的情况下,bundledDependencies 可以用来生成可分发的包,它可以在未配置 npm 的系统上运行。 如果您有一个未联网/不在互联网上的系统,这将非常有帮助:将您的软件包放在闪存驱动器(或其他设备)上,并解压 tar 文件,然后运行 npm runnode index.js 就能开箱即用了。
也许有更好的方法来打包您的应用程序以便"离线"运行,但如果有,我还没有找到。

1
假设您正在使用pnpm来管理一个monorepo,并且您有一个utils文件夹。要访问此文件夹,您可以选择以下其中一种方法(最后一种选项使用bundledDependencies):
  • 使用相对导入,可能会显得丑陋、混乱,破坏封装性,并且如果您在不更新导入的情况下更改文件夹位置,甚至可能会出错。
  • 作为一个更好的选择,如果您使用TypeScript,您可以将utils文件夹的路径别名为任何您想要的名称,比如"utils"。结果是每个子包只需要引用该别名,如果您以后更改了utils文件夹的位置,只需在tsconfig.json中更改路径即可。但是,如果在一个也使用"paths"的子包定义另一个tsconfig.json(别名选项),这种方法将无效。
  • 您可以使用bundledDependencies来维护一个私有和本地的utils包,用户将无法从npm下载,但您仍然可以在公共包中使用它们。这样,您还可以通过名称引用它,而不是相对路径。
当然,解决方案可能并不总是使用,每个问题都有自己的特定要求,但我发现对于那些在monorepos中经常出现的特定用例非常有用。

0
从操作上来看,我认为bundledDependencies是一个模块的私有模块存储,而dependencies则更公开,在您的模块及其依赖项(和子依赖项)之间解析。您的模块可能依赖于旧版本的react,但某个依赖项需要最新版本。您的包/安装将导致您的固定版本在node_modules/$yourmodule/node_modules/react中,而您的依赖项将在node_modules/react(或node_modules/$dependency/node_modules/react如果他们愿意的话)中获取他们的版本。
一个注意事项:我最近遇到了一个依赖项,它没有正确配置其对react的依赖关系,并且在bundledDependencies中使用react会导致该依赖模块在运行时失败。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接