開源版本的 uTools。可支援 uTools 所有外掛生態

muwooo發表於2021-06-29

話不多說,先放上截圖和倉庫地址:

開源版本的 uTools。可支援 uTools 所有外掛生態

程式碼倉庫:github

故事背景

網路抓包

之前公司內部因為開發需要,需要和後端進行介面聯調,測試環境的時候,經常會涉及到一些狀態改變要看互動樣式的問題。比如測試需要測商品的待支付、支付中、支付完成等各種節點的互動樣式是否符合預期,這種情況測試一般會去造資料或者讓後端改資料庫介面。 有的小夥伴可能會用 Charles 修改返回資料進行測試。但是 Charles 的抓包體驗和配置體驗感覺有點麻煩,不是很友好,所以我們自己做了個抓包&mock工具:

開源版本的 uTools。可支援 uTools 所有外掛生態

傻瓜式互動一次性解決:抓包、代理、請求轉發、介面資料篡改 mock 、跨域訪問 等能力,並得到了廣泛使用和好評。

檔案上傳

隨著專案開發的繼續,有些使用者給我們反饋頁面載入圖片資源比較慢,我們看了一下很多圖片資源都沒有經過壓縮處理,這個時候我們可以通過 webpack 寫了一些 loader 來對圖片資源進行壓縮處理。這個時候我們的圖片資源大部分是存放在專案目錄下。而有的時候,我們是需要將圖片存放於 cdn 上的,此時我們又需要一個圖床工具,可以線上儲存圖片資源。於是乎,我們又整合了圖片壓縮和上傳的功能,做了個圖床工具:

開源版本的 uTools。可支援 uTools 所有外掛生態

效能測評

開發者開發頁面的時候,需要對頁面的效能進行評估,另一方面也可以把評估報告通知給測試同學,對其進行效能測試。之前大多采用的是 chrome 外掛 lighthouse 來做。但是這個東西對未登入使用者無法做到效能評估,因為使用者未登入直接測評了登入頁面,顯然不符合預期,其次,每個電腦上都得安裝外掛,受限於裝置的不同,可能會導致效能沒有同一的變數(網路、網速、解析度、CUP 等)。所以我們基於 pupeeteer-core 以及electron 做了一個免登的測評工具:

開源版本的 uTools。可支援 uTools 所有外掛生態

但是這些還遠遠不夠,我們隨著業務的增加,功能愈發的多了起來:我們的埋點檢測工具、需求管理工具、前端多環境切換工具 等等等....一方面導致 electron 體積變得臃腫起來,另一方面隨著釋出頻率增加,安裝下載的成本也越來越大,很多使用者就不願意再接著安裝,因為確實很麻煩。所以我們需要改變,讓功能不依賴與容器。這就需要把我們的功能全部獨立出去,做成外掛化。所以我注意到了 utools

外掛化之旅

一開始想到做外掛化,無非就是使用 electron 的 webview 能力,實現類似於原生內嵌h5那樣的方式,h5 頁面可以做獨立釋出,原生提供 nativaAPI 之間通過 jsBridge 來橋接呼叫原生的方法。這樣實現並無問題,我們也嘗試了做了一次。最終思路大概是:

electron webview 方式

1. electron 中使用 webview

<webview src="https://xxx.xx.com/index.html" preload="preload.js" />

2. 實現 bridge

// preload.js
window.rubickBridge = {
  sayHello() {
    console.log('hello world')
  }
}

3. 外掛藉助 bridge 呼叫 electron 的能力

<html>
 <body>
     <div>這是一個外掛<div>
 </body>
 <script>
  window.rubickBridge.sayHello()
</script>
</html>

4. 通訊

因為 proload.js 是 electron 的 renderer 程式的,所以如果需要使用部分 main 程式的能力,則需要使用通訊機制:

// main process
ipcMain.on('msg-trigger', async (event, arg) => {
    const window = arg.winId ? BrowserWindow.fromId(arg.winId) : mainWindow
    const operators = arg.type.split('.');
    let fn = Api;
    operators.forEach((op) => {
      fn = fn[op];
    });
    const data = await fn(arg, window);
    event.sender.send(`msg-back-${arg.type}`, data);
});
  
// renderer process
ipcRenderer.send('msg-trigger', {
  type: 'getPath',
  name,
});
ipcRenderer.on(`msg-back-getPath`, (e, result) => {
  console.log(result)
});

為什麼後來我們又放棄了這條路? ?

其實上面的思路大致是沒啥問題的,我們也基於上面的思路成功把功能抽成了外掛,按照外掛的方式進行安裝載入。直到我們注意到 utools 的強大,感覺 utools 的生態非常豐富,我們要是能整合 utools 的生成那該多好呀!所以我們秉持著幹不過他就成為他的原則,我們嘗試著成為他。但是 utools 本身並沒有開源,所以沒有辦法去吸取一些優秀的程式碼實現,但是我們可以看他的官方文件。

我們發現其實 utools 大多數外掛都是和 container 層分離的,也就是說 utools 只是一個外掛的容器,為外掛提供了一些 api 能力和方法。所以一旦我們實現了utools載入外掛的能力,實現 utools 的所有 API 函式,是不是就約等於實現了 utools ! 我們就可以使用 utools 的外掛?

utools 方式

按照 utools 的 文件,首先我們需要實現一個外掛,必須要有個 plugin.json,這玩意就是用來告訴 utools 外掛的資訊。我們也按照文件來寫:

{
    "pluginName": "helloWorld",
    "description": "我的第一個 uTools 外掛",
    "main": "index.html",
    "version": "0.0.1",
    "logo": "logo.png",
    "features": [
        {
          "code": "hello",
          "explain": "hello world",
          "cmds":["hello", "你好"]
        }
    ]
}

接下來是將寫好的外掛用 utools 跑起來,按照 utools的互動是複製 plugin.json 到utools搜尋框即可,我們也可以實現:

// 監聽 input change
// 讀取剪下板內容
const fileUrl = clipboard.read('public.file-url').replace('file://', '');
// 複製檔案
if (fileUrl && value === 'plugin.json') {
  // 讀取 plugin.json 配置
  const config = JSON.parse(fs.readFileSync(fileUrl, 'utf-8'));
  const pluginConfig = {
    ...config,
    // index.html 檔案位置,用於 webview 載入
    sourceFile: path.join(fileUrl, `../${config.main || 'index.html'}`),
    id: uuidv4(),
    type: 'dev',
    icon: 'image://' + path.join(fileUrl, `../${config.logo}`),
    subType: (() => {
      if (config.main) {
        return ''
      }
      return 'template';
    })()
  };
}

實現效果如下:

開源版本的 uTools。可支援 uTools 所有外掛生態

接下來就是進行命令搜尋外掛:

開源版本的 uTools。可支援 uTools 所有外掛生態

實現這個功能其實也就是對之前儲存的pluginConfig的裡面的 features 進行遍歷,找到相應的 cmd 後進行下拉框展示即可。

然後我們要去實現選擇功能,用 webview 載入頁面的能力:

<template>
  <div>
    <webview id="webview" :src="path" :preload="preload"/>
  </div>
</template>
<script>
export default {
  data() {
    return {
      path: `File://${this.$route.query.sourceFile}`,
      preload: `File://${path.join(__static, './preload.js')}`,
      webview: null,
      query: this.$route.query,
      config: {}
    }
  }
}
</script>
開源版本的 uTools。可支援 uTools 所有外掛生態

到此結束了?並沒有!!!由於篇幅的原因,我們後續再說。本出寫的外掛 demo 已上傳 github: https://github.com/clouDr-f2e/rubick-plugin-demo

Far from enough 這只是開始

載入 utools 生態外掛

鬥圖: https://github.com/vst93/doutu-uToolsPlugin

開源版本的 uTools。可支援 uTools 所有外掛生態

視窗分離

開源版本的 uTools。可支援 uTools 所有外掛生態

utools doc 模板

uTools 的外掛開發給予了開發者最大的自由度,你可以隨心所欲的設計頁面結構、樣式、互動,對於特別擅長前端開發的同學,這沒有什麼問題,但對於非前端開發者,要做出漂亮的、高質量的前端 UI 是一件困難的事情。

所以 Rubick 也實現了模板能力:

開源版本的 uTools。可支援 uTools 所有外掛生態

utools 自帶的系統命令

取色

開源版本的 uTools。可支援 uTools 所有外掛生態

截圖

開源版本的 uTools。可支援 uTools 所有外掛生態

最後

目前 rubick 已經實現 utools 大多數核心能力,最重要的是可以使用 utools 所有生態 ! 更多能力可以前往 github 體驗。如果感覺有用,可以幫忙反手一個 star ✨

Rubick github

相關文章