Theia架構

架構概述

  本節描述了Theia的總體架構。前端

  Theia被設計爲一個能夠在本地運行的桌面應用程序,也能夠在瀏覽器和遠程服務器之間工做。爲了支持這兩種工做方式,Theia運行在兩個獨立的進程中,它們被稱之爲前端和後端,相互之間經過WebSockets上的JSON-RPC消息或HTTP上的REST APIs來通訊。對於Electron而言,前端和後端都在本地運行,而在遠程上下文中,後端運行在遠程服務器上。node

  前端和後端進行都有它們各自的依賴注入(DI)容器(詳見下文),以方便開發者進行擴展。git

前端

  前端部分負責客戶端的UI呈現。在瀏覽器中,它只是簡單地在渲染循環中運行。而在Electron中,它運行在Electron窗口中,這是一個包含Electron和Node.js APIs的瀏覽器窗口。所以,任何前端代碼均可以把瀏覽器而不是Node.js做爲一個運行平臺。github

  啓動前端進程將首先加載全部擴展包的DI模塊,而後獲取一個FrontendApplication的實例並在上面調用start()。express

後端

  後端進程運行在Node.js上。咱們使用express做爲HTTP服務器,它能夠不使用任何須要瀏覽器平臺的代碼(DOM API)。npm

  啓動後端應用程序將首先加載全部擴展包的DI模塊,而後獲取一個BackendApplication的實例並在上面調用start(portNumber)。json

  默認狀況下後端的express服務器也爲前端提供代碼。後端

按平臺進行區分

  在擴展包的根目錄下,包含以下子目錄層級,按不一樣的平臺進行區分:瀏覽器

  • common目錄下包含的代碼不依賴於任何運行時。
  • browser目錄下包含的代碼須要運行在現代瀏覽器平臺上(DOM API)。
  • electron-browser目錄下包含了須要DOM API及Electron渲染進程特定的APIs的前端代碼。
  • node目錄包含了須要運行在Node.js下的後端代碼。
  • node-electron目錄包含了Electron特定的後端代碼。

參見

  能夠查看這篇文章瞭解有關Theia架構的簡要概述:服務器

  利用JS實現多語言IDE——目標和架構(Multi_Language IDE Implemented in JS - Scope and Architecture)

擴展包

  Theia由擴展包構成。一個擴展包就是一個npm包,在這個npm包中公開了用於建立DI容器的多個DI模塊(ContainerModule)。

  經過在應用程序的package.json中添加npm包的依賴項來使用擴展包。擴展包可以在運行時安裝和卸載,這將觸發從新編譯和重啓。

  經過DI模塊,擴展包能提供從類型到具體實現的綁定,即提供服務和功能。

Services和Contributions

  本節咱們將描述一個擴展包如何使用另外一個擴展包中的服務,以及它們如何給Theia提供功能。

依賴注入(DI)

  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>(BackendApplicationContribution).to(MessagingContribution);
bindContributionProvider(bind, ConnectionHandler)

});

  最後一行將一個ContributionProvider綁定到一個包含全部ConnectionHandler綁定實例的對象上。

  像這樣來使用:

(來自messageing-module.ts)

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

}

  這裏咱們注入了一個ContributionProvider,它的name值是ConnectionHandler,這個值以前是由bindContributionProvider綁定的。

  這使得任何人均可以綁定ConnectionHandler,如今,當messageingModule啓動時,全部的ConnectionHandlers都將被初始化。

相關文章
相關標籤/搜索