typescript - Typescript、CommonJS 和 Browserify 的循环依赖问题

标签 typescript circular-dependency browserify commonjs

我正在将一个相当大的 typescript 项目从内部模块移动到外部模块。我这样做是因为我想创建一个核心包,如果需要,它可以加载其他包。我牢记的第二个要求是,我希望能够在服务器上使用 nodeJS 运行 bundle (如果需要,可以进行一些修改)。

我首先尝试使用 AMD 和 require.js 来构建核心包,但我遇到了循环依赖的问题。在读到这在 require.js 中很常见并且 commonJS 通常被建议用于大型项目后我尝试了。但现在它与 browserify 一起设置,当我运行编译的包时,我在完全相同的地方出现了完全相同的问题。

我有大约 10 个基类,它们相互依赖并形成多个循环依赖关系。我看不出有什么办法可以将它们全部删除。

一个简化的设置来解释为什么我认为我不能删除循环依赖:

Triples are made of 3 Resources (subject,predicate,object)
Resource has TripleCollections to keep track of which triples its used in
Resource has multiple functions which rely on properties of Triple
Triple has some functions which handle TripleCollections
TripleCollection has multiple functions which uses functions of Triple
TripleCollection.getSubjects() returns a ResourceCollection
ResourceCollection.getTriples() returns a TripleCollection
Resource keeps track of the objects of its triples in ResourceCollections
ResourceCollection uses multiple functions of Resource

我在 SO 上阅读了多个相关问题(this one 最有帮助),据我所知,我只有几个选择:

1) 将所有具有循环依赖的基类放在一个文件中。

这意味着它将成为一个 hell 般的文件。导入总是需要别名:

import core = require('core');
import BaseA = core.BaseA;

2) 使用内部模块

当我使用内部 typescript 模块和引用文件时,核心包运行良好(具有循环依赖性)。但是,如果我想创建单独的包并在运行时加载它们,我将不得不为所有带有 require.js 的模块使用垫片。


虽然我不太喜欢所有别名,但我想我现在会尝试选项 1,因为如果它有效,我可以继续使用 CommonJS 和 browserify,稍后我还可以更轻松地在节点中的服务器上运行所有内容.如果 1 不起作用,我将不得不求助于选项 2。

Q1:有没有我没有提到的可能的解决方案?

问题 2:具有 1 个核心包的 typescript 项目的最佳设置是什么,该核心包按需加载其他包(构建在核心上)。这似乎无法绕过循环依赖。并且最好可以同时在客户端和服务器上运行。

或者我只是在要求不可能的事情? :)

最佳答案

简单地说(也许是简单化,但我不这么认为),如果你有 ModuleAModuleB 并且两者相互依赖,它们就不是模块.它们位于不同的文件中,但它们的行为不像模块

在你的情况下,这些类是高度相互依赖的,你不能在不需要它们的情况下使用这些类中的任何一个,所以除非你可以重构程序来尝试使依赖关系成为单向的,而不是双向的(例如),我会将这组类视为一个模块。

Dependencies

如果你确实将所有这些都放在一个模块中,你仍然可以通过移动一些依赖项将它分解成多个模块,例如(所有这些问题在很大程度上都是修辞性的,因为它们是那种问题你需要问问自己),TripleResource 相互共享什么?可以将其转移到他们都可以依赖的类(class)中吗?为什么 Triple 需要了解 TripleCollection(可能是因为它表示一些分层数据)?您可能只能移动一些东西,但是从当前设计中删除任何依赖项都会降低复杂性。例如,如果可以删除 TripleResource 之间的双向关系。

可能你现在不能实质性地改变这个设计,在这种情况下你可以把它全部放在一个模块中,这将在很大程度上解决模块加载问题,它还将把可能改变的代码放在一起出于同样的原因。

所有这一切的总结是:

If you have a two way module dependency, make it a one-way module dependency. Do this by moving code to make the dependency one way or by moving it all into a single larger module that more honestly represents the coupling between the modules.

所以我对你的选择的看法与你的问题略有不同......

1) 尝试重构代码以减少耦合,看看是否可以保留较小的模块

失败了...

2) 将所有具有循环依赖的基类放在一个文件中。

我不会将内部模块选项放在列表中 - 我认为外部模块是管理大型程序的更好方法。

关于typescript - Typescript、CommonJS 和 Browserify 的循环依赖问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26886769/

相关文章:

javascript - Vue JS - vue-class-component 绑定(bind)输入

javascript - node_modules/rxjs-compat/operator/shareReplay.d.ts(2,10) : 中出现错误

typescript - 如何从 Typescript 中的常量定义字符串文字联合类型

webpack - 将 vue 模板预编译为渲染函数

javascript - 需要带有 Browserify 的 Angular。 'Uncaught object' 错误

javascript - ES6 模块 + Gulp

javascript - @Inject 无法在带有 typescript 的 vue 中工作

python - 动态更改 urwid.MainLoop 小部件的首选方法

javascript - 在 Lerna Monorepo 中检测循环依赖

c# - 不同解决方案的两个项目之间的循环依赖