“vendoring”是什么?

113

"vendoring"是什么?你如何定义这个术语?

在不考虑具体实现的情况下,它在不同的编程语言中是否有相同的含义?


2
我发现它被用于Python、PHP和Ruby领域,但它并不是一个非常知名的概念。这就是为什么我会问这个问题的原因 :-) - Niels Bom
2
我对这个概念的不完全理解也与我没有看到它被广泛使用有关。 - Niels Bom
5个回答

91

基于这个答案

针对Go语言,定义如下:这里

Vendor是指制作你的项目使用的第三方包的副本。通常将这些副本放置在每个项目内并保存在项目存储库中。

该答案的上下文是关于Go语言的,但概念仍然适用。


37
值得补充的是,打包管理是使用依赖管理器的概念相反的做法。 - konstin
值得注意的是,供应商的软件包定义上并不是免费的。一个很好的例子是Fullcalendar(非常优秀的软件,但价格不算便宜)。 - Brice Coustillas
2
一个使用 vendor 的原因是为了避免版本冲突(更详细的解释 - Martin Thoma

39

如果你的应用程序依赖于某些第三方代码,则可以声明一个依赖项,并让你的构建系统为你安装该依赖项。

然而,如果第三方代码的源不是非常稳定,那么你可以"vendor"(买进)该代码。你将第三方代码添加到应用程序中,采用更或多或少隔离的方式。如果你认真进行这种隔离,你应该在你的组织/工作环境内“发布”这个代码。

另一个使用项目供应商代码的原因是,如果你想使用某些第三方代码,但想对其进行一些修改(换言之,进行分支),你可以复制代码,进行更改,在内部发布它,然后让你的构建系统安装此代码片段。


3
我已经阅读了几次,但仍然不确定我理解“vendoring”的含义。它肯定不仅仅是在别人的代码上建立依赖关系的一个词,否则就不会有这个奇怪的新词“vendoring”了。请不要因为我而重新定义它,我已经知道足够多的词语,而且我认为我不需要学习“vendoring”的含义,如果它真的有任何意义的话。 - High Performance Mark
2
我认为“建立对他人代码分支的依赖”相当接近我的意思,所以谢谢你。然而,我感觉这不仅仅是那样,它还包括为特定用途“构建/发布自己的版本的他人代码”。 - Niels Bom
11
我想补充一下对这个术语词源的理解:在这种情况下,“vendor”的意思是软件的创建者(可能是您,因为我们在Stack Overflow上);而您正在发布“vendor”选择的依赖版本(与用户选择或更可能是用户系统选择的版本相对)。据我所知,这个术语已经存在了很长时间。 - ELLIOTTCABLE
嗯...我们选择fork一个仓库并将其用作依赖项,而不是在另一个项目中包含整个依赖项的代码,这样不是更好吗? - Ricky Robinson
@RickyRobinson,你的假设是“一个应用程序==一个代码库”。许多开发人员使用多个代码库将其应用程序分解为核心部分和库/插件。因此,外部依赖和内部依赖之间的区别并不是很大。 - Niels Bom
“我们是否最好fork一个我们选择的存储库,并将其用作依赖项”这取决于您的依赖项管理器有多灵活。” - Luiz Felipe

13

Vendoring 意味着将一个依赖项放入你的项目文件夹中 (与全局依赖相比) 并将其提交到仓库中。

例如,运行 cp /usr/local/bin/node ~/yourproject/vendor/node 并将其提交到仓库中,就可以 "vendor" Node.js 二进制文件 - 项目中的所有开发人员都将使用这个确切的版本。这在 node 自身中不常见,但是 Yarn 2 ("Berry") 就是这样使用的(也只能像这样使用;甚至不会将二进制文件安装到全局)。

提交操作很重要。例如,node_modules 已经安装在你的项目中,但是只有提交它们才能使它们成为 "vendored"。几乎没有人会这样做,但是 PnP + Yarn 2 的 Zero Installs 实际上是建立在 vendoring 周围的-您将带有许多 ZIP 文件的 .yarn/cache 提交到仓库中。

“Vendoring” 本质上在仓库大小(更长的克隆时间,更多的数据传输,本地存储要求等)和安装的可靠性/可重复性之间存在权衡。

3
据我所知,这个术语来自于Ruby on Rails。
它描述了一种约定,即在源代码控制中保留完整依赖项的快照,存储在包含软件包名称和版本号的目录中。
我找到的最早出现“vendor”作为动词的例子是在err博客上发布的vendor everything(2007年,比作者共同创立GitHub之前)的帖子。该帖子解释了动机以及如何添加依赖项。据我理解,当时没有特殊的工具支持将目录称为 vendor (补丁和代码片段正在流传)。
err博客文章链接到早期使用相同约定的文章,例如this fairly minimal way to add vendor subdirectories to the Rails import path(2006年)。
早期从错误博客引用的文章,比如这篇(2005年),似乎使用了lib目录,该目录没有区分自己的代码和未经修改的依赖项快照。

供应商目录的目标是更好地实现可重复性、更好的部署,以及人们目前使用容器的那种东西;以及通过源代码控制更好的透明度。
其他语言似乎已经采用了这个概念;一个相关的概念是锁文件,它以更紧凑的形式定义相同的依赖关系集合,涉及哈希和远程包存储库。锁文件可以用于重新创建供应商目录并检测任何更改。锁文件的概念可能来自Ruby gems社区,但请不要引用我。
我们想出的解决方案是将每个 Ruby 依赖项都放在“vendor”文件夹中。所有的依赖项,明白吗?这样每个人都在同一页上:我们不必担心谁有哪个 gem 的哪个版本(因为我们知道);我们也不必担心让每个人更新 gem(我们只需更新一次);我们也不必担心使用我们的库会破坏构建过程。 [...]
这里的目标很简单:始终使每个人,特别是您的生产环境,保持在同一页上。您不想猜测每个人是否拥有某些 gem。
还有一个微妙的点潜藏在背景中:一旦您的所有 gem 都受到版本控制,您可以轻松地在应用程序的任何阶段启动它而无需费心。您还可以很容易地看到您使用了哪些 gem 的哪些版本。真正的历史记录。

没有锁定文件的供应商管理的缺点是另一种依赖关系问题,这种问题通常由C++程序员经历,因为C++中的依赖关系管理基本上是失效的(是的,我知道vcpkg,但我仍然会供应我的vcpkg端口,具有讽刺意味的是,即使它有某种形式的锁定文件)。 - Luiz Felipe

1

总结其他过于冗长的回答:

Vendor是将常常被分叉的依赖项的版本硬编码。

通常涉及静态链接或某些复制,但不一定必须这样做。

无论对错,“硬编码”这个术语都有一个旧的、不好的声誉。因此,在公开使用Vendor的项目中不会找到它,但我想不到更准确的术语了。


“坏声誉”是一个愚蠢的概念。在工程中只有权衡取舍。有时候,硬编码项目的核心依赖是可行的,因为一切都建立在承重部件之上,它不应因为外部环境而失败。如果这意味着它已经过时或存在安全漏洞,那么也不会被外部(可能是自动化的)系统管理员工具随意更新,从而导致其垫子被拉掉。 因为可靠性更重要,如果存在安全漏洞,您可以更新供应商,连续交付系统将无论如何进行更新。 - Luiz Felipe
关于控制变更的问题,我们不能仅因为有安全漏洞被报告就突然更新软件,这就像是因为有人报告木柱易燃可能引发火灾,你立刻将它拆除,结果天花板就会倒下来,无论这个柱子有多易燃都不重要。如果服务停止了,再安全的应用程序也没有什么用处,因为用户不能使用它。 - Luiz Felipe
1
依赖管理确实是一个非常复杂的话题,像“移除木柱”这样的简化并不有用。如果你很幸运,有一个非常具体和专注于仅针对严重漏洞的更新可用,那么当然你会“突然”更新。但当然你并不总是那么幸运,生活并不总是那么简单,所以总会有权衡。 - MarcH

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