如何避免节点需要加载相同的模块两次
Posted
技术标签:
【中文标题】如何避免节点需要加载相同的模块两次【英文标题】:How to avoid node require loading same module twice 【发布时间】:2012-12-04 02:56:06 【问题描述】:我正在开发一个节点模块my-module
,它又依赖于另一个模块other-module
。因此,other-module
是我模块的 package.json 中明确列出的依赖项。
由于我的模块只是通过成为require
d 来修改other-module
的行为,因此重要的是other-module
只加载一次,并且这个唯一的“实例”是在任何文件中引用的唯一“实例”需要my
和other
的应用程序。
根据节点的模块缓存策略,我希望这会成立,但我在编写一个简单的测试应用程序时遇到的是这样的:
如果my-module
是npm install
ed 之前 other-module
则后者作为前者的依赖项引入。 npm install
ing other-module
之后再次将其带入 node_modules 层次结构。然后,当我的模块需要other-module
时,节点会加载我模块的“本地”副本,当应用程序require
s 第二次加载它时,节点再次,(这次是安装的版本由于第二个npm install
)。这显然不是预期的结果。
如果my-module
是npm installe
d 之后 other-module
那么我最终在node_modules 中只有一份 other-module
并且我的测试应用程序作为预计。
这种行为让我再次查看节点的相关政策,果然我遇到了“模块缓存警告”:
模块根据其解析的文件名进行缓存。由于模块可能会根据调用模块的位置(从 node_modules 文件夹加载)解析为不同的文件名,因此不能保证 require('foo') 将始终返回完全相同的对象,如果它会解析为不同的文件.
在这一点上,我的模块可能会或可能不会按预期运行,具体取决于npm install
s 的顺序。
我是否缺少任何最佳实践?有什么办法可以在不改变我的模块工作方式的情况下避免这种混乱?
【问题讨论】:
【参考方案1】:简短的回答:你不能。
正如您所指出的,节点将从最本地的位置加载所需的模块。据我所知,这是包管理器独有的,它使您不必关心模块的确切依赖关系树。 Node 和 npm 会为你解决这个问题。在我看来,这是一件非常好的事情。
通过让您的模块有机会要求他们需要的确切版本,可以避免依赖地狱。
我认为除非我不完全理解您的问题,否则您正在尝试做的不是良好的节点实践。模块被加载并分配给一个局部变量。应该避免使用全局状态,因为这会导致相当笨拙和不可测试的代码。此外,如果您成功地将修改后的模块注入到其他人的代码中,则无法保证他们的代码仍然可以工作。这就像在旧的 Prototype.js_ 日子里,可以使用 javascript 的内置全局变量,如 String 或 Array ,这导致了一些灾难性的代码。
但请记住,本文仅代表一个人的观点。如果您在此处找不到更多答案,请将您的问题发布到节点的 IRC 频道等其他地方。
【讨论】:
实际上,如果您使用符号链接,那么您最终可能会遇到模块被加载两次的情况,这样只有一个包源的实际副本,但包链接到 node_modules其中一个包。【参考方案2】:我在用 jest 开发测试时遇到了类似的问题。
以下语句将允许您在不同的上下文中再次加载相同的模块:
jest.resetModules();
【讨论】:
以上是关于如何避免节点需要加载相同的模块两次的主要内容,如果未能解决你的问题,请参考以下文章
如何避免在 MongoDB(使用 Mongoid)或 ActiveRecord(使用 MySQL 的 Rails)中插入两次相同的记录?