如何避免节点需要加载相同的模块两次

Posted

技术标签:

【中文标题】如何避免节点需要加载相同的模块两次【英文标题】:How to avoid node require loading same module twice 【发布时间】:2012-12-04 02:56:06 【问题描述】:

我正在开发一个节点模块my-module,它又依赖于另一个模块other-module。因此,other-module 是我模块的 package.json 中明确列出的依赖项。

由于我的模块只是通过成为required 来修改other-module 的行为,因此重要的是other-module 只加载一次,并且这个唯一的“实例”是在任何文件中引用的唯一“实例”需要myother 的应用程序。

根据节点的模块缓存策略,我希望这会成立,但我在编写一个简单的测试应用程序时遇到的是这样的:

如果my-modulenpm installed 之前 other-module 则后者作为前者的依赖项引入。 npm installing other-module 之后再次将其带入 node_modules 层次结构。然后,当我的模块需要other-module 时,节点会加载我模块的“本地”副本,当应用程序requires 第二次加载它时,节点再次,(这次是安装的版本由于第二个npm install)。这显然不是预期的结果。

如果my-modulenpm installed 之后 other-module 那么我最终在node_modules 中只有一份 other-module 并且我的测试应用程序作为预计。

这种行为让我再次查看节点的相关政策,果然我遇到了“模块缓存警告”:

模块根据其解析的文件名进行缓存。由于模块可能会根据调用模块的位置(从 node_modules 文件夹加载)解析为不同的文件名,因此不能保证 require('foo') 将始终返回完全相同的对象,如果它会解析为不同的文件.

在这一点上,我的模块可能会或可能不会按预期运行,具体取决于npm installs 的顺序。

我是否缺少任何最佳实践?有什么办法可以在不改变我的模块工作方式的情况下避免这种混乱?

【问题讨论】:

【参考方案1】:

简短的回答:你不能。

正如您所指出的,节点将从最本地的位置加载所需的模块。据我所知,这是包管理器独有的,它使您不必关心模块的确切依赖关系树。 Node 和 npm 会为你解决这个问题。在我看来,这是一件非常好的事情。

通过让您的模块有机会要求他们需要的确切版本,可以避免依赖地狱。

我认为除非我不完全理解您的问题,否则您正在尝试做的不是良好的节点实践。模块被加载并分配给一个局部变量。应该避免使用全局状态,因为这会导致相当笨拙和不可测试的代码。此外,如果您成功地将修改后的模块注入到其他人的代码中,则无法保证他们的代码仍然可以工作。这就像在旧的 Prototype.js_ 日子里,可以使用 javascript 的内置全局变量,如 StringArray ,这导致了一些灾难性的代码。

但请记住,本文仅代表一个人的观点。如果您在此处找不到更多答案,请将您的问题发布到节点的 IRC 频道等其他地方。

【讨论】:

实际上,如果您使用符号链接,那么您最终可能会遇到模块被加载两次的情况,这样只有一个包源的实际副本,但包链接到 node_modules其中一个包。【参考方案2】:

我在用 jest 开发测试时遇到了类似的问题。

以下语句将允许您在不同的上下文中再次加载相同的模块:

jest.resetModules();

【讨论】:

以上是关于如何避免节点需要加载相同的模块两次的主要内容,如果未能解决你的问题,请参考以下文章

如何避免在 MongoDB(使用 Mongoid)或 ActiveRecord(使用 MySQL 的 Rails)中插入两次相同的记录?

Requirejs多次加载相同的Javascript文件

Spring Mongo 条件查询两次相同的字段

当用户双击提交按钮时,需要避免向服务器提交两次表单

django如何两次渲染相同的模板[重复]

如何让 OSX 打开同一个包两次?