-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cloud IDE Theia 插件系统拓展探索 #83
Comments
总算是看到了,che-plugin还添加了一个backend的扩展,来处理前端对api-provider的请求,把文件返回给webworker。 |
有个问题,我基本上按照che-plugin的在写了 |
我有点混乱了,这几个究竟是什么关系啊? |
你可以看成是 Eclipse 官方重写了一个 VS Code,名字叫 Theia,很多能力、架构包括接口设计等都是和 VS Code 相通的。 |
Eclipse Theia 是一个可扩展的平台,可以利用最先进的 Web 技术开发多语言的 Cloud & Desktop IDE。
名词解释
概述
拓展 Theia Plugin 能力,让业务方简单、灵活地深度定制 IDE 的功能和界面。
动机
Theia Plugin 拓展方式和 能力 和 VSCode Extension 类似,并不满足我们的需求:
因此,需要拓展 Theia 的插件系统。
原则
设计概览
设计总结
整体设计图示
tide 项目结构
IDE Core 和 Taro IDE 暂时放在同一个项目 tide 里,建议参考:che-theia。
npm 包发布在
@tide
Scope 下。VS Code Extension(概念上等同于 Theia 的 Plugin)能力是以下三种方式拓展:
详细设计
项目将参考 VS Code Extension 的拓展接口及规范,从配置、Command 、VS Code API 等方面拓展插件系统,其中,VSCode 最具代表性的拓展例子应该是 Tree View API,兼具以上三者方式。
Contribution Points 配置拓展
Contribution Points
是package.json
中contributes
字段的一系列 JSON 声明,插件通过注册Contribution Points
来拓展 VSCode 的功能。contributes
配置的处理可以分为配置扫描(scanner)和配置处理(handler)。主要在 plugin-ext 里实现。scanner
plugin-ext/src/hosted/node/scanners/scanner-theia.ts 里的
TheiaPluginScanner
类实现了所有 package.json 配置的读取方法,包括 contribution 配置、activationEvents 配置等。我们应该是不需要添加新的配置读取,所以不需要修改这里。
handler
contribution 最终配置的 handle 都是在
PluginContributionHandler
里注入实际 handler 类统筹处理的。拓展
和 API 拓展不同专门预留了拓展注入点
ExtPluginApiProvider
不同,Theia 代码里类似的并没有预留专门的接口,暂时采用以下步骤拓展:TidePluginContributionHandler
继承PluginContributionHandler
类handleContributions
方法rebind(TidePluginContributionHandler).to(PluginContributionHandler).inSingletonScope();
如果有更好的方式,请指正。
Command 拓展
Commands 触发
Theia/VSCode
的 actions。VSCode 代码里包含大量 built-in commands,你可以使用这些命令与编辑器交互、控制用户界面或执行后台操作。Command 拓展可以参考:packages/plugin-ext-vscode/src/browser/plugin-vscode-commands-contribution.ts
首先定义
XXXCommandsContribution
类实现CommandContribution
,并注入对应的服务,如然后在XXXCommandsContribution
中通过commands.registerCommand
进行 Command 拓展,如:然后 bind 到 container 即可:
XXXCommandsContribution 会被注入到对应的 ContributionProvider,然后进行处理:
Command 可以传入对象作为参数,无法暴露接口和组件。
API 拓展
相对上面两种拓展方式,API 的拓展方式比较复杂。
方式一:plugin-ext-vscode 的方式
这种方式是 VSCode 采用的方式,通过修改
PluginLifecycle
里面的backendInitPath
或frontendInitPath
,这两个脚本类似于 preload 脚本,在插件加载前进行预加载,初始化插件环境。具体是 VsCodePluginScanner 类里的
getLifecycle()
方法的backendInitPath
。在这里 backendInitPath 被初始化为:backendInitPath: __dirname + '/plugin-vscode-init.js'
然后在 PluginHostRPC 类里
new PluginManagerExtImpl()
实例时,在传入的 init 钩子中调用的initContext
中通过require()
方法加载。注意:
initContext
里面的backendInitPath
来自于PluginLifecycle
,并不是ExtPluginApiProvider
。而 backendInitPath 配置的
plugin-vscode-init.ts
文件提供了doInitialization
方法,在doInitialization
方法中通过Object.assign
合并 Theia API 到 vscode namespace,添加简单的 API 和字段。这种方法本质是在插件加载前运行脚本,不涉及到 RPC,通过
Object.assign
合并简单的 API。这种方式不如 ExtPluginApiProvider 的方式优雅,社区有人提里 PR 将其改成 ExtPluginApiProvider 的形式:Make "theia" and "vscode" contributed API's #8142,目前为止依然还没有被合并。
方式二:ExtPluginApiProvider 的方式
eclipse/che-theia 就是采用了这种方式,功能非常强大。具体可见:ChePluginApiProvider
Theia 官方文档没有提到这种方式,不过在 plugin-ext/doc 下倒是有一片简单的介绍文档:This document describes how to add new plugin api namespace
Che-Theia plug-in API 提供了 che 的 namespace。
主要步骤
主要步骤如下:
frontendExtApi
和后端入口backendInitPath
。createAPIFactory(rpc)
,然后分别挂载到前端及后端插件运行时。che-api-worker-provider.js
,实现并export initializeApi
方法。在 initializeApi 中,通过createAPIFactory(rpc)
定义接口。export provideApi()
,然后在overrideInternalLoad()
方法中改写module._load
,通过createAPIFactory(rpc)
定义接口。1. ExtPluginApiProvider 提供前后端入口
首先声明 ExtPluginApiProvider 实现:
然后注入到 backend moudule:
这样,前端及后台都有了插件拓展的入口。
2. Client API 的接口
createAPIFactory(rpc)
createAPIFactory 用于定义 Client API 接口,然后分别挂载到前端及后端插件运行时的 namespace。
createAPIFactory 方法的实现,和 Theia 源码中
packages/plugin-ext/src/plugin/plugin-context.ts
里 createAPIFactory 的实现一致:前后端 Client API 注入
new PluginManagerExtImpl()
传入的第一个参数 host 是 PluginHost 类型,其中的 initExtApi 等方法前端后台分别实现:initExtApi 前端,挂在 window 下。
其中
const pluginsModulesNames = new Map<string, Plugin>();
插件的集合。initExtApi 后端,直接 require,并运行 provideApi()
3. 前端入口 initializeApi,挂载 API 到 namespace
前端入口脚本
che-api-worker-provider.js
,实现并export initializeApi
方法。在 initializeApi 中,传入 RPC,挂载到 che namespace。4. 后端入口 provideApi,load 时代理 API
后端入口脚本
che-api-node-provider.js
,代码里需要暴露export provideApi()
。后端也是通过 createAPIFactory 定义 Client API 接口。
然后在
overrideInternalLoad()
方法中改写module._load
,使require('@eclipse-che/plugin')
返回定义的 Client API。5. Server API 的注入
MainPluginApiProvider 的实现应该包含新命名空间的 Plugin API 的 main(接口实现)部分。
注入到浏览器的 HostedPluginSupport 中,然后在 initRpc方法一次调用注入 MainPluginApiProvider 的 initialize 方法进行初始化。
简化的 API 通信架构图大致如下:
ExtPluginApiProvider 的拓展方式非常成熟优雅且功能强大,建议采用这一种。
Demo
见 Tide 项目 master 分支 extension/tide-theia-plugin-ext 模块。
参考
The text was updated successfully, but these errors were encountered: