基于Jenkins、Figma插件實現原理探究web系統插件化架構

背景:對于大型web應用而言,功能極其豐富復雜,為了具備擴展性,部分項目選擇插件化架構方式,開放一部分系統Hook給具備開發能力的用戶,不但提升用戶的體驗感,還同時豐富平臺功能,一舉兩得。如何構建具備插件化能力的平臺?本文嘗試通過分析jenkins jar包插件實現方式及Figma前端插件實現方式探究插件化架構方案。

我們常見的支持插件化的應用是一些桌面端編輯器,如VSCode,Eclipse,Idea,Sublime等,也有支持動態擴展的web應用,如構建工具Jenkins,支持前端插件擴展的web應用,如設計工具Figma。不管哪種應用方式,基本的設計邏輯大致如下。

插件系統通用方案.png

我們當前主要研究的是web系統的插件化構架方案,本地插件化軟件先不討論。主要以jenkins和figma的兩種實現方式進行探討。

Jenkins插件化系統

10.png

Jenkins可以支持git, svn, maven等很多功能,這些都是Jenkins的插件,Jenkins通過擴展點及前端視圖模板來提供插件擴展能力,以jar包的方式上傳到指定目錄,創建類加載器 class-loader,使用插件策略PluginStrategy加載可以激活的插件。

(一)擴展點

Jenkins有很多的擴展點ExtensitonPoint),它是Jenkins系統的某個方面的接口或抽象類。這些接口定義了需要實現的方法,而Jenkins插件需要實現這些方法,也可以叫做在此擴展點之上進行擴展Jenkins。有關擴展點的詳細信息,請參閱Jenkins 官方ExtentionPoints文檔。通過這些擴展點我們可以寫插件來實現自己的需求。
下面是一些常用的擴展點:

  • Scm :代表源碼管理的一個步驟,如下面的Git,Subversion就是擴展的Scm
11.png
  • Builder : 代表構建的一個步驟,如下圖中在構建過程中,我們可以增加一個構建步驟,而每一個選項都是對應一個Builder,在每一個Builder中都有自己不同的功能。如Execute shell,這就是一個ShellBuilder,意味著在構建過程中會執行一個shell命令

    12.png

  • Trigger:代表一個構建的觸發,當滿足一個什么樣的條件時觸發這個項目開始構建。比較常用的觸發就是當代碼變更時觸發,如果我們需要實現一些比較復雜的觸發邏輯,就需要擴展Trigger這個擴展點

13.png
  • Publisher:Publisher代表一個項目構建完成后需要執行的步驟,如選項中的E-Mail Notifaction就是一個Publisher插件,選擇這個選項后,當項目構建完成,就會使用email來通知用戶,假如想要在項目構建完成后將構建目標產物發送到服務器上,則可以擴展此擴展點。
14.png
(二)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 設計工具,具有插件擴展功能,只要有前端開發能力的用戶均可開發自己的插件來擴展設計體驗。

image-20210611163806313.png

Figma的插件是純前端的插件方式,沒有后端代碼,它的插件系統是如何工作的?

這是一個基于 TypeScript + React 技術棧,使用 Webpack 構建的 Figma 插件目錄結構如下:

├── README.md
├── figma.d.ts
├── manifest.json
├── package-lock.json
├── package.json
├── src
│   ├── code.ts
│   ├── logo.svg
│   ├── ui.css
│   ├── ui.html
│   └── ui.tsx
├── tsconfig.json
└── webpack.config.js

在其 manifest.json 文件中包含了一些簡單的信息。

{  
"name": "React Sample",  
"id": "738168449509241862",  
"api": "1.0.0",  
"main": "dist/code.js",  
"ui": "dist/ui.html"
}

ui展示是通過如下代碼加載,會彈出個DIV,展示manifest.josn中指定的ui地址內容:

figma.showUI(__html__);

可以看出 Figma 將插件入口分為了 mainui 兩部分, main 中包含了插件實際運行時的邏輯,而 ui 則是一個插件的 HTML 片段。即 UI 與邏輯分離。 main 中的 js 文件被包裹在一個 iframe 里加載到頁面上。而 ui 中的 HTML 最終也被包裹在一個 iframe 里渲染出來。

為什么這么要用iframe包裹?

  1. 首先是安全性考慮
    iframe,一個瀏覽器自帶的沙箱環境。將插件代碼由 iframe 包裹起來,由于 iframe 天然的限制,這將確保插件代碼無法操作 Figma 主界面上下文,同時也可以只開放一份白名單 API 供插件調用。
    iframe參考
  2. 其次是避免樣式污染
    這將有效的避免插件 UI 層 CSS 代碼導致全局樣式污染,使主程序與插件樣式相互獨立。

插件如何與主程序通信?
在上一層使用 window.addEventListener進行監控,事件通信使用 parent.postMessage,發送事件及數據。

Inner Plugin Iframe:

document.getElementById('create').onclick = () => {
        const textbox = document.getElementById('count');
        const count = parseInt(textbox.value, 10);
        parent.postMessage({ pluginMessage: { type: 'create-rectangles', count } }, '*')
    }
                
document.getElementById('cancel').onclick = () => {
        parent.postMessage({ pluginMessage: { type: 'cancel' } }, '*')
    }

Shim Plugin Iframe:

var messageHandler = (event) => {
        var pluginIframeElement = document.getElementById("plugin-iframe")
        if (pluginIframeElement && event.source === pluginIframeElement.contentWindow) {
            parent.postMessage({ origin: event.origin, data: event.data }, window.location.origin)
        }
    }
    window.addEventListener("message", messageHandler)
    window.__FIGMA_PLUGIN_SANDBOX_PAGE_LOADED = true
            
        

整體架構圖描述,大致如下:

Figma插件系統.png

開發的插件可在本地app中進行調試,最終發布到服務器。

image-20210611171346786.png

總結

插件系統在設計時要考慮的基本內容,如何開放數據接口,如何加載插件,何時何地啟動插件,插件如何與主程序通信問題,如何保證插件安全性?前端插件化使用iframe sandbox是一個通用可行的辦法,但依然會有很多問題。

參考文檔

How Plugins Run · Figma Developers

Figma 插件開發 101

大型 Web 應用插件化架構探索

iframe參考

window.postMessage

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容