在我最近的一次采访中,有人问我关于npm
或pip
的程序包管理器工具如何在内部确定首先安装哪些依赖项的工作方式。
例如,假设您要安装依赖于软件包B的软件包A,而后者又依赖于软件包C。在这种情况下,应先安装软件包C,再安装B,然后再安装A。
依赖跟踪会变得更加复杂,我相信可以以图形的形式表示。现在的问题是弄清楚这些软件包之间是否存在周期性的依赖关系,如果不存在,则以安装它们的顺序打印这些软件包。
我无法及时提出正确/最佳解决方案,但也许有人可以帮忙吗?
谢谢!
答案 0 :(得分:5)
包之间的依赖关系可以建模为Directed Acyclic Graph。
依赖关系图如果包含一个循环,则无效,您可以参考以下算法在有向图中检测循环:https://www.geeksforgeeks.org/detect-cycle-in-a-graph/
如果图中没有循环,则可以执行拓扑排序以获得应安装依赖项的顺序:https://www.geeksforgeeks.org/topological-sorting/
希望这可以回答您的问题。干杯!
答案 1 :(得分:3)
请按照this link of npm algo进行详细说明
依赖性解决方案
我正在使用npm文档中提供的确切示例。
注意:从v3开始,依赖关系解析算法已更改,因此该示例适用于v3及更高版本的npm。
让我们考虑以下示例:
Module-A, depends on Module B v1.0.
Module-C, depends on Module B v2.0.
请注意提到的模块顺序,因为它在依赖关系解析中起着重要作用。
所以首先是模块A顺序,它取决于模块B v1.0,npm将在/node_modules
目录的平面内安装模块A及其依赖项模块B。
序列的下一个是模块C,它再次依赖于模块B,但版本不同。 npm通过将新的,不同的模块B版本依赖项嵌套在需要它的模块下来解决此问题
现在,如果我们安装另一个依赖于模块B v1.0的模块会发生什么?或模块B v2.0?
所以可以说:
Module-D, depends on Module B v2.0.
Module-E, depends on Module B v1.0.
由于B v1.0已经是顶级依赖项,因此我们无法将B v2.0安装为顶级依赖项。因此,即使我们已经安装了副本,也将模块B v2.0安装为模块D的嵌套依赖关系,嵌套在模块C下。模块B v1.0已经是顶级依赖关系,我们不需要重复和嵌套它。我们只需安装模块E,它与模块A共享模块B v1.0。
现在有趣的部分是,如果我们将模块A更新到v2.0,这取决于模块B v2.0,而不是模块B v1.0,会发生什么?
关键是要记住安装顺序很重要。
即使通过我们的package.json
首先安装了模块A(作为v1.0),使用npm install
命令也意味着模块A v2.0是最后安装的软件包。
因此,在安装模块A v2.0时,npm会执行以下操作
It removes Module A v1.0.
It installs Modules A v2.0.
It leaves Module Bv1.0 because Module E v1.0 still depends on it.
It installs Module Bv2.0 as a nested dependency under Module A v2.0, since Module B v1.0 is already occupying the top level in the directory hierarchy.
最后,我们也将模块E更新到v2.0,这也依赖于模块B v2.0而不是模块B v1.0,就像模块A更新一样。
npm执行以下操作:
It removes Module E v1.0.
It installs Module E v2.0.
It removes Module B v1.0 because nothing depends on it anymore.
It installs Module B v2.0 in the top level of the directory because there is no other version of Module B there.
现在,这显然不理想。几乎每个目录中都有模块B v2.0。要消除重复,我们可以运行:
npm dedupe
此命令通过将所有软件包依赖关系重定向到Module B v2.0的顶层副本,并删除所有嵌套的副本,从而解决了对Module B v2.0的所有依赖关系。
结论
因此,此示例的关键之处在于安装顺序很重要,只有在添加或更新项目中的任何软件包时使用npm命令才能确保这一点。 npm生成的依赖关系树可能会在不同的本地开发计算机上有所不同,但它不会影响您的应用程序的行为,因为即使这些树不同,也要充分安装所有依赖关系并将其指向所有依赖关系,因此在树上。您仍然拥有所需的一切,只是碰巧处于不同的配置中。
如果您希望自己的node_modules目录与使用npm install
命令相同,则该命令专门用于从package.json
安装软件包时,将始终生成同一棵树。这是因为来自package.json
的安装顺序总是按字母顺序。相同的安装顺序意味着您将获得相同的树。
只要对node_modules
进行更改,就可以通过删除npm install
目录并运行package.json
来可靠地获得相同的依赖关系树。