背景:对于大型web应用而言,功能极其丰富复杂,为了具备扩展性,部分项目选择插件化架构方式,开放一部分系统Hook给具备开发能力的用户,不但提升用户的体验感,还同时丰富平台功能,一举两得。如何构建具备插件化能力的平台?本文尝试通过分析jenkins jar包插件实现方式及Figma前端插件实现方式探究插件化架构方案。
我们常见的支持插件化的应用是一些桌面端编辑器,如VSCode,Eclipse,Idea,Sublime等,也有支持动态扩展的web应用,如构建工具Jenkins,支持前端插件扩展的web应用,如设计工具Figma。不管哪种应用方式,基本的设计逻辑大致如下。
我们当前主要研究的是web系统的插件化构架方案,本地插件化软件先不讨论。主要以jenkins和figma的两种实现方式进行探讨。
Jenkins插件化系统
Jenkins可以支持git, svn, maven等很多功能,这些都是Jenkins的插件,Jenkins通过扩展点及前端视图模板来提供插件扩展能力,以jar包的方式上传到指定目录,创建类加载器 class-loader,使用插件策略PluginStrategy加载可以激活的插件。
(一)扩展点
Jenkins有很多的扩展点(ExtensitonPoint),它是Jenkins系统的某个方面的接口或抽象类。这些接口定义了需要实现的方法,而Jenkins插件需要实现这些方法,也可以叫做在此扩展点之上进行扩展Jenkins。有关扩展点的详细信息,请参阅Jenkins 官方ExtentionPoints文档。通过这些扩展点我们可以写插件来实现自己的需求。
下面是一些常用的扩展点:
Scm :代表源码管理的一个步骤,如下面的Git,Subversion就是扩展的Scm
Builder : 代表构建的一个步骤,如下图中在构建过程中,我们可以增加一个构建步骤,而每一个选项都是对应一个Builder,在每一个Builder中都有自己不同的功能。如Execute shell,这就是一个ShellBuilder,意味着在构建过程中会执行一个shell命令
Trigger:代表一个构建的触发,当满足一个什么样的条件时触发这个项目开始构建。比较常用的触发就是当代码变更时触发,如果我们需要实现一些比较复杂的触发逻辑,就需要扩展Trigger这个扩展点
Publisher:Publisher代表一个项目构建完成后需要执行的步骤,如选项中的E-Mail Notifaction就是一个Publisher插件,选择这个选项后,当项目构建完成,就会使用email来通知用户,假如想要在项目构建完成后将构建目标产物发送到服务器上,则可以扩展此扩展点。
(二)Jenkins中的视图
Jenkins 使用jelly来编写视图,Jelly 是一种基于 Java
技术和 XML
的脚本编制和处理引擎。Jelly 的特点是有许多基于 JSTL (JSP 标准标记库,JSP Standard Tag Library)、Ant、Velocity 及其它众多工具的可执行标记。Jelly 还支持 Jexl(Java 表达式语言,Java Expression Language),Jexl 是 JSTL 表达式语言的扩展版本。Jenkins的界面绘制就是通过Jelly实现的。
另外一个开源的插件化后台管理系统:grape: 前后端可插件开发的后台管理系统 (gitee.com)
Figma前端插件系统
Figma 是一个在线协作式 UI 设计工具,具有插件扩展功能,只要有前端开发能力的用户均可开发自己的插件来扩展设计体验。
Figma的插件是纯前端的插件方式,没有后端代码,它的插件系统是如何工作的?
这是一个基于 TypeScript + React 技术栈,使用 Webpack 构建的 Figma 插件目录结构如下:
1 | ├── README.md |
在其 manifest.json
文件中包含了一些简单的信息。
1 | { |
可以看出 Figma 将插件入口分为了 main
与 ui
两部分, main 中包含了插件实际运行时的逻辑,而 ui 则是一个插件的 HTML 片段。即 UI 与逻辑分离。 main
中的 js 文件被包裹在一个 iframe 里加载到页面上。而 ui
中的 HTML 最终也被包裹在一个 iframe 里渲染出来,这将有效的避免插件 UI 层 CSS 代码导致全局样式污染。
ui展示是通过如下代码加载,会弹出个DIV,展示manifest.josn中指定的ui地址内容:
1 | figma.showUI(__html__); |
在上一层使用 window.addEventListener
进行监控,事件通信使用 parent.postMessage,发送事件及数据。figma使用了两层iframe来嵌套装载插件内容。
我画了架构图来描述,大致如下:
开发的插件可在本地app中进行调试,最终发布到服务器。
总结
插件系统在设计时要考虑的基本内容,如何开放数据接口,如何加载插件,何时何地启动插件,插件如何与主程序通信问题,如何保证插件安全性?前端插件化使用iframe sandbox是一个通用可行的办法,但依然会有很多问题。