<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          實(shí)現(xiàn)工具自由!開(kāi)源的桌面工具箱

          共 10432字,需瀏覽 21分鐘

           ·

          2021-08-15 21:50

          在一切開(kāi)始之前,首先要致敬 uTools!如果沒(méi)有它就沒(méi)有 Rubick。

          大家好,我是“拉比克”(Rubick)項(xiàng)目的作者木偶。我做的 Rubick 是一款基于 Electron 的開(kāi)源桌面工具箱,簡(jiǎn)單講就是好多工具的集合,然后加上快速啟動(dòng)、豐富的插件擴(kuò)展等功能于一體。

          沒(méi)錯(cuò)!它的使用方式和外觀幾乎和 uTools 一摸一樣。那我為什么放著免費(fèi)的 uTools 不用,非要自己搞一個(gè)呢?

          事情的起因是這樣的,出于安全方面的考慮有一些僅適用于公司內(nèi)部的插件不能發(fā)布到插件市場(chǎng),所以不能接入 uTools。但實(shí)在眼饞 uTools 式的便捷、用完即走的極簡(jiǎn)操作體驗(yàn)。在搜尋解決方案無(wú)果,同時(shí)也發(fā)現(xiàn)其他的小伙伴也有同樣的訴求,所以我動(dòng)手做了,然后把它開(kāi)源了。

          Rubick 一款呼出超快、用完即走的開(kāi)源工具箱,因?yàn)殚_(kāi)源所以更自由!

          項(xiàng)目地址:https://github.com/clouDr-f2e/rubick

          希望它能幫助你解決同樣的煩惱,但目前僅支持 Windows 和 macOS,Linux 版本正在開(kāi)發(fā)中。想借助開(kāi)源的力量讓 Rubick 變強(qiáng),成為金牌輔助!幫助大家輕松“超神”!

          在做 Rubick 的過(guò)程中還是遇到了不少問(wèn)題和挑戰(zhàn),下面就分享下我的心路歷程。

          一、緣起

          1.1 初識(shí) Electron

          Electron 是 GitHub 開(kāi)源的一個(gè)框架。它通過(guò) Node.js 和 Chromium 的渲染引擎完成跨平臺(tái)的桌面 GUI 應(yīng)用程序的開(kāi)發(fā)。我起初沒(méi)有接觸過(guò) Electron,最開(kāi)始接觸它是因?yàn)榭吹搅?PicGo 的一個(gè)核心功能非常吸引我,就是 macOS 下可以直接拖拽圖片進(jìn)入任務(wù)托盤(pán)上傳圖片:

          當(dāng)時(shí)正好我們團(tuán)隊(duì)也需要搞一個(gè)內(nèi)部的 CDN 圖片資源管理圖床,用于項(xiàng)目圖片資源壓縮并直接上傳到 CDN 上,之前我們做了個(gè)網(wǎng)頁(yè)版。而這里我深刻的感受到了 Electron 的強(qiáng)大,可以極大的提高工作效率,參考 PicGo 我嘗試做了第一個(gè) Electron 項(xiàng)目,完成了圖片壓縮上傳到內(nèi)部 CDN 的桌面端應(yīng)用。

          1.2 演化

          之后公司內(nèi)部因?yàn)殚_(kāi)發(fā)和后端進(jìn)行接口聯(lián)調(diào)測(cè)試環(huán)境時(shí),經(jīng)常會(huì)涉及到一些狀態(tài)改變要看交互樣式的問(wèn)題。比如測(cè)試需要測(cè)商品的待支付、支付中、支付完成等各種節(jié)點(diǎn)的交互樣式是否符合預(yù)期,這種情況測(cè)試一般會(huì)去造數(shù)據(jù)或者讓后端改數(shù)據(jù)庫(kù)接口。有的小伙伴可能會(huì)用 Charles 修改返回?cái)?shù)據(jù)進(jìn)行測(cè)試,但 Charles 的抓包體驗(yàn)和配置體驗(yàn)感覺(jué)有點(diǎn)麻煩,對(duì)新人不是很友好所以我們自己做了個(gè)非常易用 抓包&mock 工具:

          這也是 Rubick 最早的雛形。隨后,我們發(fā)現(xiàn)當(dāng)頁(yè)面發(fā)布線上的時(shí)候,沒(méi)有辦法在微信環(huán)境內(nèi)對(duì)線上頁(yè)面進(jìn)行調(diào)試,所以開(kāi)發(fā)了一個(gè)基于 winner 的遠(yuǎn)程調(diào)試功能。

          但隨著該 Rubick 在內(nèi)部不斷推廣和使用,所需功能也越來(lái)越多。我們需要 需求管理、性能評(píng)估、埋點(diǎn)檢測(cè) 等等工具。這些工具的增加一方面導(dǎo)致 Rubick 體積暴增,一方面又導(dǎo)致了用戶(hù)需要不斷更新軟件,導(dǎo)致用戶(hù)體驗(yàn)非常差。

          其次,我們?cè)谕茝V給測(cè)試、UI 同學(xué)使用的時(shí)候,發(fā)現(xiàn)他們其實(shí)并不關(guān)注前面的頁(yè)面調(diào)試、性能測(cè)評(píng)等功能,可能只是用到其中某一項(xiàng),所以整個(gè)項(xiàng)目對(duì)他們來(lái)說(shuō)就顯得很臃腫。

          1.3 靈感

          直到有一天,我在掘金上看到這樣一個(gè)沸點(diǎn):

          下面有個(gè)評(píng)論提到了 uTools 這是我第一次和 uTools 產(chǎn)生了交集,在體驗(yàn)了 uTools 功能后,我長(zhǎng)吸一口氣:這不就是我想要的嘛!然后就去 GitHub 上找 uTools 的源碼,發(fā)現(xiàn)它并沒(méi)有開(kāi)源。

          所以就想把上面提到的那些工具, 發(fā)布到 uTools 市場(chǎng)在 uTools 里通過(guò)插件的方式使用他們。但我發(fā)現(xiàn)發(fā)布插件只能發(fā)布到公網(wǎng),但這又涉及到數(shù)據(jù)安全的問(wèn)題。

          無(wú)奈,難道真的要自己做一個(gè)這樣的工具嗎?真的是有點(diǎn)頭大。不過(guò)想想也挺有意思的。至此,我萌生了要開(kāi)發(fā)一個(gè)媲美 uTools 的開(kāi)源工具箱的念頭。

          二、研發(fā)

          開(kāi)篇第一步,按照我之前的套路都是先取好名字先占個(gè)坑。我是個(gè) Dota 玩家,之前寫(xiě)了一本《從0開(kāi)始可視化搭建》的小冊(cè),里面使用了 Dota 中一個(gè)英雄的名字 coco(船長(zhǎng))。這次我取名的是 rubick 即 拉比克。Rubick(拉比克) 也是 Dota 里面的英雄之一,其核心技能是插件化使用其他英雄的技能,用完即走。非常符合本工具的設(shè)計(jì)理念,所以取名 Rubick。

          我的核心目標(biāo)就是需要讓 Rubick 支持插件化,解決前面提到的問(wèn)題:

          • 每個(gè)人的工具箱不同
          • 軟件體積暴增
          • 每增加一個(gè)工具就需要更新版本

          其次,通過(guò)調(diào)研了解到團(tuán)隊(duì)內(nèi)有些同學(xué)已經(jīng)在使用 uTools 了,要想讓他們從 uTools 上把插件零成本遷移到 Rubick 上,就必須實(shí)現(xiàn) uTools 的部分 API 能力,以及插件的定義和寫(xiě)法也需要和 uTools 規(guī)范保持一致。

          2.1 開(kāi)發(fā)者模式

          插件開(kāi)發(fā)需要和 Rubick 進(jìn)行聯(lián)調(diào),所以 Rubick 需要支持開(kāi)發(fā)者模式,幫助開(kāi)發(fā)者更好的開(kāi)發(fā)插件。首先先建一個(gè) plugin.json 用于描述插件的基礎(chǔ)信息:

          {
            "pluginName""測(cè)試插件",
            "author""muwoo",
            "description""我的第一個(gè) rubick 插件",
            "main""index.html",
            "version""0.0.2",
            "logo""logo.png",
            "name""rubick-plugin-demo",
            "gitUrl""",
            "features": [
              {
                "code""hello",
                "explain""這是一個(gè)測(cè)試的插件",
                "cmds":["hello222""你好"]
              }
            ],
            "preload""preload.js"
          }

          2.1.1 核心字段

          • name 插件倉(cāng)庫(kù)名稱(chēng)
          • pluginName 插件名稱(chēng)
          • description 插件描述,簡(jiǎn)潔的說(shuō)明這個(gè)插件的作用
          • main 入口文件,如果沒(méi)有定義入口文件,此插件將變成一個(gè)模版插件
          • version 插件的版本,用于版本更新提示
          • features 插件核心功能列表
          • features.code 插件某個(gè)功能的識(shí)別碼,可用于區(qū)分不同的功能
          • features.cmds 通過(guò)哪些方式可以進(jìn)入這個(gè)功能

          2.1.2 示例

          開(kāi)發(fā)插件的方式是復(fù)制 plugin.json 進(jìn)入到 Rubick 的搜索框,所以需要監(jiān)聽(tīng)搜索框的 change 事件,用于讀取當(dāng)前剪切板復(fù)制的內(nèi)容:

          onSearch ({ commit }, paylpad) {
            // 獲取剪切板復(fù)制的文件路徑
            const fileUrl = clipboard.read('public.file-url').replace('file://''');
            
            // 如果是復(fù)制 plugin.json 文件
            if (fileUrl && value === 'plugin.json') {
               // 讀取 json 文件
               const config = JSON.parse(fs.readFileSync(fileUrl, 'utf-8'));
               // 生成插件配置
               const pluginConfig = {
                  ...config,
                  // 記錄 index.html 存方的路徑
                  sourceFile: path.join(fileUrl, `../${config.main || 'index.html'}`),
                  id: uuidv4(),
                  // 標(biāo)記為開(kāi)發(fā)者
                  type'dev',
                  // 讀取 icon
                  icon'image://' + path.join(fileUrl, `../${config.logo}`),
                  // 標(biāo)記是否是模板
                  subType(() => {
                    if (config.main) {
                      return ''
                    }
                    return 'template';
                  })()
                };
            }
          }

          到這里我們已經(jīng)可以根據(jù)復(fù)制的 plugin.json 能獲取到插件的最基礎(chǔ)的信息,接下來(lái)就是需要展示搜索框:

           commit('commonUpdate', {
              options: [
                {
                  name'新建rubick開(kāi)發(fā)插件',
                  value'new-plugin',
                  icon'https://xxx.com/img.png',
                  desc'新建rubick開(kāi)發(fā)插件',
                  click(router) => {
                    commit('commonUpdate', {
                      showMaintrue,
                      selected: {
                        key'plugin',
                        name'新建rubick開(kāi)發(fā)插件'
                      },
                      current: ['dev'],
                    });
                    ipcRenderer.send('changeWindowSize-rubick', {
                      height: getWindowHeight(),
                    });
                    router.push('/home/dev')
                  }
                },
                {
                  name'復(fù)制路徑',
                  desc'復(fù)制路徑',
                  value'copy-path',
                  icon'https://xxx.com/img.png',
                  click() => {
                    clipboard.writeText(fileUrl);
                    commit('commonUpdate', {
                      showMainfalse,
                      selectednull,
                      options: [],
                    });
                    ipcRenderer.send('changeWindowSize-rubick', {
                      height: getWindowHeight([]),
                    });
                    remote.Notification('Rubick 通知', { body'復(fù)制成功' });
                  }
                }
              ]
          });

          到這里,當(dāng)復(fù)制 plugin.json 進(jìn)入搜索框時(shí),便可直接出現(xiàn) 2 個(gè)選項(xiàng),一個(gè)新建插件,一個(gè)復(fù)制路徑的功能:

          當(dāng)點(diǎn)擊 新建 rubick 插件 功能時(shí),則需要跳轉(zhuǎn)到 home 頁(yè),加載插件的基礎(chǔ)內(nèi)容,唯一需要注意的是 home 頁(yè)加載的內(nèi)容高度應(yīng)該是 Rubick 最大窗口的高度。所以需要調(diào)整窗口大?。?/p>

           ipcRenderer.send('changeWindowSize-rubick', {
              height: getWindowHeight(),
           });

          關(guān)于 renderer 里面的 Vue 代碼這里就不再詳細(xì)介紹了,因?yàn)榇蠖嗍?css 畫(huà)一下就好了,直接來(lái)看展示界面:

          到這里,就完成了開(kāi)發(fā)者模式,接下來(lái)再聊聊插件是如何在 Rubick 中跑起來(lái)的。

          2.3 插件運(yùn)行原理

          運(yùn)行插件需要容器 Electron 提供了一個(gè) webview 的容器來(lái)加載外部網(wǎng)頁(yè)。所以可以借助 webview 的能力實(shí)現(xiàn)動(dòng)態(tài)網(wǎng)頁(yè)渲染,這里所謂的網(wǎng)頁(yè)就是插件。但是網(wǎng)頁(yè)無(wú)法使用 node 的能力,而且做插件的目的就是為了開(kāi)放與約束,需要對(duì)插件開(kāi)放一些內(nèi)置的 API 能力。好在 webview 提供了一個(gè) preload 的能力,可以在頁(yè)面加載的時(shí)候去預(yù)置一個(gè)腳本來(lái)執(zhí)行。

          也就是說(shuō)可以給自己的插件寫(xiě)一個(gè) preload.js 來(lái)加載。但這里需要注意既要保持插件的個(gè)性又得向插件內(nèi)注入全局 API 供插件使用,所以可以直接加載 Rubick 內(nèi)置 preload.js,在 preload.js 內(nèi)再加載個(gè)性化的 preload.js

          // webview plugin.vue
          <webview id="webview" :src="path" :preload="preload"></webview>
          <script>
          export default {
            name"index.vue",
            data() {
              return {
                path`File://${this.$route.query.sourceFile}`,
                // 加載當(dāng)前 static 目錄中的 preload.js
                preload`File://${path.join(__static, './preload.js')}`,
                webviewnull,
                querythis.$route.query,
                config: {},
              }
            }
          }
          </script>

          對(duì)于 preload.js 就可以這么用啦:

          if (location.href.indexOf('targetFile') > -1) {
            filePath = decodeURIComponent(getQueryVariable('targetFile'));
          else {
            filePath = location.pathname.replace('file://''');
          }


          window.utools = {
            // utools 所有的 api 實(shí)現(xiàn)
          }
          // 加載插件 preload.js
          require(path.join(filePath, '../preload.js'));

          到這里就已經(jīng)實(shí)現(xiàn)了一個(gè)最基礎(chǔ)的插件加載,效果如下:

          2.4 支持更多體驗(yàn)?zāi)芰?span style="display: none;">

          隨后為了更加貼近 uTools 的體驗(yàn),我又開(kāi)始著手讓 Rubick 支持更多原生體驗(yàn)增強(qiáng)的特性:超級(jí)面板、模板、系統(tǒng)命令、全局快捷鍵等

          三、最后

          再次致敬 uTools!我做 Rubick 旨在技術(shù)分享,并不以商業(yè)化為目的。

          以上就是我和 Rubick 的故事,如果 Rubick 對(duì)您有幫助,那么就請(qǐng)給個(gè) Star ? 鼓勵(lì)一下:

          https://github.com/clouDr-f2e/rubick


          機(jī)緣巧合我發(fā)現(xiàn)了 HelloGitHub 一個(gè)推薦開(kāi)源項(xiàng)目的平臺(tái),了解到鹵蛋也是喜歡打 Dota,我想那他應(yīng)該能感受到 Rubick 的魅力,所以我就抱著試一試的心態(tài)投稿了。先是有幸入選了月刊第 64 期,然后受邀寫(xiě)了這篇關(guān)于 Rubick 的故事。



          瀏覽 64
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产成人免费视频 | 一级A片电影网址 | 久久久久国产欧美久久久aaa | 久久黄色视频免费看 | 日韩乱轮 |