Theia架构

Theia使用DI框架 Inversify.js
来连接不同的组件。
DI在创建时注入组件(作为构造函数的参数),从而将组件从依赖项中彻底解耦出来。DI容器根据你在启动时通过所谓的容器模块提供的配置项来进行创建。

例如, Navigator
小部件需要访问 FileSystem
用来在树形结构中显示文件夹和文件,但是 FileSystem
接口的实现对 Navigator
来说并不重要,它可以大胆地假设与 FileSystem
接口一致的对象已经准备好并可以使用了。在Theia中, FileSystem
的实现仅仅是一个发送JSON-RPC消息到后端的代理,它需要一个特殊的配置和处理程序。Navigator不需要关心这些细节,因为它将获取一个被注入的 FileSystem
的实例。

此外,这种结构的解耦和使用,允许扩展包在需要时能提供非常具体的功能实现,例如这里提到的 FileSystem
,而不需要接触到 FileSystem
接口的任何实现。

DI在Theia中是一个非常重要的部分,因此,我们强烈建议先学习 Inversify.js
的基础知识。

Services

Service只是一个提供给其它组件使用的绑定。例如,一个扩展包可以公开 SelectionService
,这样其它扩展包就可以获得一个注入的实例并使用它。

Contribution-Points

如果一个扩展包想要提供一个钩子,由其它扩展包来实现其中的功能,那么它应该定义一个 contribution-point
。一个 contribution-point
就是一个可以被其它扩展包实现的接口。扩展包可以在需要时将它委托给其它部分。

例如, OpenerService
定义了一个contribution point,允许其它扩展包注册 OpenHandler
。你可以查看 这里
的代码。

Theia已经提供了大量的contribution points列表,查看已存在的contribution points的一个好方法是查找 bindContributionProvider
的引用。

Contribution Providers

一个contribution provider基本上是contributions的容器,其中的contributions是绑定类型的实例。
这是非常通用的。
要将类型绑定到contribution provider,你可以这样做:
(来自messageing-module.ts)

export const messagingModule = new ContainerModule(bind => {
    bind(BackendApplicationContribution).to(MessagingContribution);
    bindContributionProvider(bind, ConnectionHandler)
});

最后一行将一个ContributionProvider绑定到一个包含所有ConnectionHandler绑定实例的对象上。
像这样来使用:
(来自messageing-module.ts)

constructor( @inject(ContributionProvider) @named(ConnectionHandler) protected readonly handlers: ContributionProvider) {
    }

这里我们注入了一个ContributionProvider,它的name值是ConnectionHandler,这个值之前是由 bindContributionProvider
绑定的。
这使得任何人都可以绑定ConnectionHandler,现在,当messageingModule启动时,所有的ConnectionHandlers都将被初始化。

原文地址: https://theia-ide.org/docs/architecture