使用Theia——創建擴展包


上一篇:使用Theia——構建你自己的IDE

創建Theia擴展包

  本例中,我們將添加一個菜單項“Say hello”用來顯示一個通知“Hello world!”。本文將指導你完成所有必要的步驟。

Theia的架構

  Theia應用程序由所謂的擴展包(extensions)構成。一個擴展包提供一組特定功能的小部件、命令和處理程序等。Theia本身提供了一些擴展包,如編輯器、終端、項目視圖等。每一個擴展包都屬於它們各自的npm包。

  Theia定義了大量的contribution接口,允許擴展包將功能添加到應用程序的各個部分。只需要按名稱搜索 *Contribution就可以找到這些接口。擴展包實現了這些contribution接口的具體功能。在本例中,我們將實現 CommandContributionMenuContribution。擴展包與Theia應用程序之間還可以通過各種 servicesmanagers來進行交互。
  在Theia中,所有的東西都是通過依賴注入( Dependency Injection)的方式連接起來的。一個擴展包定義了一個或多個依賴注入模塊。這些依賴注入模塊就是綁定並實現contribution接口的地方,它們被列在擴展包的 package.json文件中。擴展包可以用於前端,例如提供UI擴展,也可以用於后端,例如提供語言服務。當應用程序啟動時,所有這些模塊合並起來為前端和后端各自配置一個全局的依賴注入容器。然后在運行時通過多次注入的方式將這些特定類型的contributions收集起來。

必要條件

  你需要安裝node 10版本(譯者:事實上最新的node穩定版即可):
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.5/install.sh | bash
nvm install 10

  以及yarn:

npm install -g yarn

  還需要確保已安裝python 2.x,可通過python --version來檢查。

項目結構

  我們將創建一個名為 theia-hello-world-extension的monorepo(一個包含多個npm包的倉庫),其中包含三個包: hello-world-extensionbrowser-appelectron-app。第一個即我們的擴展包,后兩個是在瀏覽器和electron模式下運行我們擴展包的Theia應用程序。這里我們使用 yarn而不是 npm來安裝,因為它可以在workspace中構造monorepo倉庫的結構。在我們的示例中,每一個workspace都包含它們自己的 npm包。這些包的公共依賴項通過 yarn被“hoisted”到它們的公共根目錄中。另外我們還將使用 lerna跨workspace運行腳本。
  為了簡化每個倉庫的設置,我們創建了一個 代碼生成器來幫助我們快速生成項目的腳手架。它也會生成 hello-world示例,通過下面的命令運行:
npm install -g yo generator-theia-extension
mkdir theia-hello-world-extension
cd theia-hello-world-extension
yo theia-extension hello-world-extension

  我們來看下生成的代碼。根目錄下的package.json文件中定義了workspaces、依賴項lerna以及一些用來給瀏覽器或electron構件本地包的scripts。

{
  "private": true,
  "scripts": {
    "prepare": "lerna run prepare",
    "rebuild:browser": "theia rebuild:browser",
    "rebuild:electron": "theia rebuild:electron"
  },
  "devDependencies": {
    "lerna": "2.4.0"
  },
  "workspaces": [
    "hello-world-extension", "browser-app", "electron-app"
  ]
}

  同時也生成了lerna.json文件,用來配置lerna

{
  "lerna": "2.4.0",
  "version": "0.1.0",
  "useWorkspaces": true,
  "npmClient": "yarn",
  "command": {
    "run": {
      "stream": true
    }
  }
}

實現擴展包

  接下來看下 hello-world-extension目錄中我們的擴展包生成的代碼。我們從 package.json文件開始,它定義了包的元數據、對(最新的)Theia核心包的依賴項、一些腳本以及開發依賴項、還有theia-extensions。
  keywords中的 theia-extension非常重要:它允許Theia應用程序能夠識別並從 npm安裝Theia擴展包。
{
  "name": "hello-world-extension",
  "keywords": [
    "theia-extension"
  ],
  "version": "0.1.0",
  "files": [
    "lib",
    "src"
  ],
  "dependencies": {
    "@theia/core": "latest"
  },
  "devDependencies": {
    "rimraf": "latest",
    "typescript": "latest"
  },
  "scripts": {
    "prepare": "yarn run clean && yarn run build",
    "clean": "rimraf lib",
    "build": "tsc",
    "watch": "tsc -w"
  },
  "theiaExtensions": [
    {
      "frontend": "lib/browser/hello-world-frontend-module"
    }
  ]
}
  最后一個屬性 theiaExtensions,其中列出了一些JavaScript模塊,這些模塊導出了擴展包中定義的contribution的DI模塊。本例中,我們只提供了一個前端功能(一個命令行和一個菜單項)。類似地,你也可以定義對后端的contribution,例如定義一個使用語言服務的language contribution。
  在前端模塊中,我們導出了一個默認對象, InversifyJSContainerModule,其中綁定了一個command contribution和一個menu contribution。
export default new ContainerModule(bind => {
    // add your contribution bindings here
    bind(CommandContribution).to(HelloWorldCommandContribution);
    bind(MenuContribution).to(HelloWorldMenuContribution);
});

  Command被定義為一種簡單的數據結構,其中包含id和label。id中包含了在command contribution中注冊的處理程序,用來實現command的功能。代碼生成器已經添加了一個command和一個處理程序,用於顯示一個“Hello World!”的消息。

export const HelloWorldCommand = {
    id: 'HelloWorld.command',
    label: "Shows a message"
};

@injectable()
export class HelloWorldCommandContribution implements CommandContribution {

    constructor(
        @inject(MessageService) private readonly messageService: MessageService,
    ) { }

    registerCommands(registry: CommandRegistry): void {
        registry.registerCommand(HelloWorldCommand, {
            execute: () => this.messageService.info('Hello World!')
        });
    }
}
...
  請注意我們是如何在構造函數中使用 @inject來獲取 MessageService的,以及如何在稍后的處理程序中使用它。這就是依賴注入優雅的地方:在客戶端,我們並不關心這些依賴來自於何處,而且也不關心它們的生命周期。
  為了能在UI層訪問,我們需要實現 MenuContribution,在菜單欄的edit菜單的Search/Replace部分添加一項。
...
@injectable()
export class HelloWorldMenuContribution implements MenuContribution {

    registerMenus(menus: MenuModelRegistry): void {
        menus.registerMenuAction(CommonMenus.EDIT_FIND, {
                commandId: HelloWorldCommand.id,
                label: 'Say Hello'
            });
    }
}

在瀏覽器中運行擴展包

  現在來看看我們的擴展包是如何工作的。為此,生成器在browser-app目錄中創建了一個package.json文件,定義了一個含有幾個擴展包的Theia瀏覽器應用程序,其中包含了我們的hello-world-extension。目錄中剩余的其它文件都是由yarn在構建過程中通過theia-cli工具自動生成的,如scripts部分中所定義的。

{
  "name": "browser-app",
  "version": "0.1.0",
  "dependencies": {
    "@theia/core": "latest",
    "@theia/filesystem": "latest",
    "@theia/workspace": "latest",
    "@theia/preferences": "latest",
    "@theia/navigator": "latest",
    "@theia/process": "latest",
    "@theia/terminal": "latest",
    "@theia/editor": "latest",
    "@theia/languages": "latest",
    "@theia/markers": "latest",
    "@theia/monaco": "latest",
    "@theia/typescript": "latest",
    "@theia/messages": "latest",
    "hello-world-extension": "0.1.0"
  },
  "devDependencies": {
    "@theia/cli": "latest"
  },
  "scripts": {
    "prepare": "theia build",
    "start": "theia start",
    "watch": "theia build --watch"
  },
  "theia": {
    "target": "browser"
  }
}

  現在所有構建和運行應用程序需要的部分都准備好了,要運行它,輸入下面的命令:

cd browser-app
yarn start <path to workspace>

  然后在瀏覽器中輸入http://localhost:3000,在打開的應用程序中選擇Edit>Say Hello,你將會看到 “Hello World!”的消息彈出。

在Electron中運行擴展包

  Electron應用程序中的 package.json與瀏覽器應用程序中的類似,除了name和target屬性不同。
{
  "name": "electron-app",
  ...
  "theia": {
    "target": "electron"
  }
}

  在運行electron應用程序之前,你需要重新構建一些本地的模塊:

yarn rebuild:electron
cd electron-app
yarn start <path to workspace>

部署擴展包

  如果你想公開你的擴展包,我們建議你將它發布到npm。你可以通過在擴展包的目錄中調用yarn publish來完成,當然前提是你需要一個有效的賬戶。

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM