您好,登錄后才能下訂單哦!
架構(gòu)概述
本節(jié)描述了Theia的整體架構(gòu)。
Theia被設(shè)計為一個可以在本地運行的桌面應(yīng)用程序,也可以在瀏覽器和遠(yuǎn)程服務(wù)器之間工作。為了支持這兩種工作方式,Theia運行在兩個獨立的進(jìn)程中,它們被稱之為前端和后端,相互之間通過WebSockets上的JSON-RPC消息或HTTP上的REST APIs來通信。對于Electron而言,前端和后端都在本地運行,而在遠(yuǎn)程上下文中,后端運行在遠(yuǎn)程服務(wù)器上。
前端和后端進(jìn)行都有它們各自的依賴注入(DI)容器(詳見下文),以方便開發(fā)者進(jìn)行擴展。
前端
前端部分負(fù)責(zé)客戶端的UI呈現(xiàn)。在瀏覽器中,它只是簡單地在渲染循環(huán)中運行。而在Electron中,它運行在Electron窗口中,這是一個包含Electron和Node.js APIs的瀏覽器窗口。因此,任何前端代碼都可以把瀏覽器而不是Node.js作為一個運行平臺。
啟動前端進(jìn)程將首先加載所有擴展包的DI模塊,然后獲取一個FrontendApplication的實例并在上面調(diào)用start()。
后端
后端進(jìn)程運行在Node.js上。我們使用express作為HTTP服務(wù)器,它可以不使用任何需要瀏覽器平臺的代碼(DOM API)。
啟動后端應(yīng)用程序?qū)⑹紫燃虞d所有擴展包的DI模塊,然后獲取一個BackendApplication的實例并在上面調(diào)用start(portNumber)。
默認(rèn)情況下后端的express服務(wù)器也為前端提供代碼。
按平臺進(jìn)行區(qū)分
在擴展包的根目錄下,包含如下子目錄層級,按不同的平臺進(jìn)行區(qū)分:
common目錄下包含的代碼不依賴于任何運行時。
browser目錄下包含的代碼需要運行在現(xiàn)代瀏覽器平臺上(DOM API)。
electron-browser目錄下包含了需要DOM API及Electron渲染進(jìn)程特定的APIs的前端代碼。
node目錄包含了需要運行在Node.js下的后端代碼。
node-electron目錄包含了Electron特定的后端代碼。
參見
可以查看這篇文章了解有關(guān)Theia架構(gòu)的簡要概述:
利用JS實現(xiàn)多語言IDE——目標(biāo)和架構(gòu)(Multi_Language IDE Implemented in JS - Scope and Architecture)
擴展包
Theia由擴展包構(gòu)成。一個擴展包就是一個npm包,在這個npm包中公開了用于創(chuàng)建DI容器的多個DI模塊(ContainerModule)。
通過在應(yīng)用程序的package.json中添加npm包的依賴項來使用擴展包。擴展包能夠在運行時安裝和卸載,這將觸發(fā)重新編譯和重啟。
通過DI模塊,擴展包能提供從類型到具體實現(xiàn)的綁定,即提供服務(wù)和功能。
Services和Contributions
本節(jié)我們將描述一個擴展包如何使用另一個擴展包中的服務(wù),以及它們?nèi)绾谓oTheia提供功能。
依賴注入(DI)
Theia使用DI框架Inversify.js來連接不同的組件。
DI在創(chuàng)建時注入組件(作為構(gòu)造函數(shù)的參數(shù)),從而將組件從依賴項中徹底解耦出來。DI容器根據(jù)你在啟動時通過所謂的容器模塊提供的配置項來進(jìn)行創(chuàng)建。
例如,Navigator小部件需要訪問FileSystem用來在樹形結(jié)構(gòu)中顯示文件夾和文件,但是FileSystem接口的實現(xiàn)對Navigator來說并不重要,它可以大膽地假設(shè)與FileSystem接口一致的對象已經(jīng)準(zhǔn)備好并可以使用了。在Theia中,F(xiàn)ileSystem的實現(xiàn)僅僅是一個發(fā)送JSON-RPC消息到后端的代理,它需要一個特殊的配置和處理程序。Navigator不需要關(guān)心這些細(xì)節(jié),因為它將獲取一個被注入的FileSystem的實例。
此外,這種結(jié)構(gòu)的解耦和使用,允許擴展包在需要時能提供非常具體的功能實現(xiàn),例如這里提到的FileSystem,而不需要接觸到FileSystem接口的任何實現(xiàn)。
DI在Theia中是一個非常重要的部分,因此,我們強烈建議先學(xué)習(xí)Inversify.js的基礎(chǔ)知識。
Services
Service只是一個提供給其它組件使用的綁定。例如,一個擴展包可以公開SelectionService,這樣其它擴展包就可以獲得一個注入的實例并使用它。
Contribution-Points
如果一個擴展包想要提供一個鉤子,由其它擴展包來實現(xiàn)其中的功能,那么它應(yīng)該定義一個contribution-point。一個contribution-point就是一個可以被其它擴展包實現(xiàn)的接口。擴展包可以在需要時將它委托給其它部分。
例如,OpenerService定義了一個contribution point,允許其它擴展包注冊O(shè)penHandler。你可以查看這里的代碼。
Theia已經(jīng)提供了大量的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,現(xiàn)在,當(dāng)messageingModule啟動時,所有的ConnectionHandlers都將被初始化。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。