实现工具自由!开源的桌面工具箱
來源:?HelloGitHub
Rubick,因?yàn)殚_源所有更自由
在一切開始之前,首先要致敬 uTools!如果沒有它就沒有 Rubick。
大家好,我是“拉比克”(Rubick)項(xiàng)目的作者木偶。我做的 Rubick 是一款基于 Electron 的開源桌面工具箱,簡單講就是好多工具的集合,然后加上快速啟動(dòng)、豐富的插件擴(kuò)展等功能于一體。
沒錯(cuò)!它的使用方式和外觀幾乎和 uTools 一摸一樣。那我為什么放著免費(fèi)的 uTools 不用,非要自己搞一個(gè)呢?
事情的起因是這樣的,出于安全方面的考慮有一些僅適用于公司內(nèi)部的插件不能發(fā)布到插件市場(chǎng),所以不能接入 uTools。但實(shí)在眼饞 uTools 式的便捷、用完即走的極簡操作體驗(yàn)。在搜尋解決方案無果,同時(shí)也發(fā)現(xiàn)其他的小伙伴也有同樣的訴求,所以我動(dòng)手做了,然后把它開源了。
Rubick 一款呼出超快、用完即走的開源工具箱,因?yàn)殚_源所以更自由!
項(xiàng)目地址:https://github.com/clouDr-f2e/rubick
希望它能幫助你解決同樣的煩惱,但目前僅支持 Windows 和 macOS,Linux 版本正在開發(fā)中。想借助開源的力量讓 Rubick 變強(qiáng),成為金牌輔助!幫助大家輕松“超神”!
在做 Rubick 的過程中還是遇到了不少問題和挑戰(zhàn),下面就分享下我的心路歷程。
緣
起
初識(shí) Electron
Electron 是 GitHub 開源的一個(gè)框架。它通過 Node.js 和 Chromium 的渲染引擎完成跨平臺(tái)的桌面 GUI 應(yīng)用程序的開發(fā)。我起初沒有接觸過 Electron,最開始接觸它是因?yàn)榭吹搅?PicGo 的一個(gè)核心功能非常吸引我,就是 macOS 下可以直接拖拽圖片進(jìn)入任務(wù)托盤上傳圖片:
當(dāng)時(shí)正好我們團(tuán)隊(duì)也需要搞一個(gè)內(nèi)部的 CDN 圖片資源管理圖床,用于項(xiàng)目圖片資源壓縮并直接上傳到 CDN 上,之前我們做了個(gè)網(wǎng)頁版。而這里我深刻的感受到了 Electron 的強(qiáng)大,可以極大的提高工作效率,參考 PicGo 我嘗試做了第一個(gè) Electron 項(xiàng)目,完成了圖片壓縮上傳到內(nèi)部 CDN 的桌面端應(yīng)用。
演化
之后公司內(nèi)部因?yàn)殚_發(fā)和后端進(jìn)行接口聯(lián)調(diào)測(cè)試環(huán)境時(shí),經(jīng)常會(huì)涉及到一些狀態(tài)改變要看交互樣式的問題。比如測(cè)試需要測(cè)商品的待支付、支付中、支付完成等各種節(jié)點(diǎn)的交互樣式是否符合預(yù)期,這種情況測(cè)試一般會(huì)去造數(shù)據(jù)或者讓后端改數(shù)據(jù)庫接口。有的小伙伴可能會(huì)用 Charles 修改返回?cái)?shù)據(jù)進(jìn)行測(cè)試,但 Charles 的抓包體驗(yàn)和配置體驗(yàn)感覺有點(diǎn)麻煩,對(duì)新人不是很友好所以我們自己做了個(gè)非常易用 抓包&mock 工具:
這也是 Rubick 最早的雛形。隨后,我們發(fā)現(xiàn)當(dāng)頁面發(fā)布線上的時(shí)候,沒有辦法在微信環(huán)境內(nèi)對(duì)線上頁面進(jìn)行調(diào)試,所以開發(fā)了一個(gè)基于 winner 的遠(yuǎn)程調(diào)試功能。
但隨著該 Rubick 在內(nèi)部不斷推廣和使用,所需功能也越來越多。我們需要 需求管理、性能評(píng)估、埋點(diǎn)檢測(cè) 等等工具。這些工具的增加一方面導(dǎo)致 Rubick 體積暴增,一方面又導(dǎo)致了用戶需要不斷更新軟件,導(dǎo)致用戶體驗(yàn)非常差。
其次,我們?cè)谕茝V給測(cè)試、UI 同學(xué)使用的時(shí)候,發(fā)現(xiàn)他們其實(shí)并不關(guān)注前面的頁面調(diào)試、性能測(cè)評(píng)等功能,可能只是用到其中某一項(xiàng),所以整個(gè)項(xiàng)目對(duì)他們來說就顯得很臃腫。
靈感
直到有一天,我在掘金上看到這樣一個(gè)沸點(diǎn):
下面有個(gè)評(píng)論提到了 uTools 這是我第一次和 uTools 產(chǎn)生了交集,在體驗(yàn)了 uTools 功能后,我長吸一口氣:這不就是我想要的嘛!然后就去 GitHub 上找 uTools 的源碼,發(fā)現(xiàn)它并沒有開源。
所以就想把上面提到的那些工具, 發(fā)布到 uTools 市場(chǎng)在 uTools 里通過插件的方式使用他們。但我發(fā)現(xiàn)發(fā)布插件只能發(fā)布到公網(wǎng),但這又涉及到數(shù)據(jù)安全的問題。
無奈,難道真的要自己做一個(gè)這樣的工具嗎?真的是有點(diǎn)頭大。不過想想也挺有意思的。至此,我萌生了要開發(fā)一個(gè)媲美 uTools 的開源工具箱的念頭。
研
發(fā)
Electron 是 GitHub 開源的一個(gè)框架。它通過 Node.js 和 Chromium 的渲染引擎完成跨平臺(tái)的桌面 GUI 應(yīng)用程序的開發(fā)。我起初沒有接觸過 Electron,最開始接觸它是因?yàn)榭吹搅?PicGo 的一個(gè)核心功能非常吸引我,就是 macOS 下可以直接拖拽圖片進(jìn)入任務(wù)托盤上傳圖片:
開篇第一步,按照我之前的套路都是先取好名字先占個(gè)坑。我是個(gè) Dota 玩家,之前寫了一本《從0開始可視化搭建》的小冊(cè),里面使用了 Dota 中一個(gè)英雄的名字 coco(船長)。這次我取名的是 rubick 即 拉比克。Rubick(拉比克) 也是 Dota 里面的英雄之一,其核心技能是插件化使用其他英雄的技能,用完即走。非常符合本工具的設(shè)計(jì)理念,所以取名 Rubick。
我的核心目標(biāo)就是需要讓 Rubick 支持插件化,解決前面提到的問題:
每個(gè)人的工具箱不同
軟件體積暴增
每增加一個(gè)工具就需要更新版本
其次,通過調(diào)研了解到團(tuán)隊(duì)內(nèi)有些同學(xué)已經(jīng)在使用 uTools 了,要想讓他們從 uTools 上把插件零成本遷移到 Rubick 上,就必須實(shí)現(xiàn) uTools 的部分 API 能力,以及插件的定義和寫法也需要和 uTools 規(guī)范保持一致。
開發(fā)者模式
插件開發(fā)需要和 Rubick 進(jìn)行聯(lián)調(diào),所以 Rubick 需要支持開發(fā)者模式,幫助開發(fā)者更好的開發(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" }開發(fā)者模式——核心字段
name?插件倉庫名稱
pluginName?插件名稱
description?插件描述,簡潔的說明這個(gè)插件的作用
main?入口文件,如果沒有定義入口文件,此插件將變成一個(gè)模版插件
version?插件的版本,用于版本更新提示
features?插件核心功能列表
features.code?插件某個(gè)功能的識(shí)別碼,可用于區(qū)分不同的功能
features.cmds?通過哪些方式可以進(jìn)入這個(gè)功
開發(fā)者模式——示例
開發(fā)插件的方式是復(fù)制?plugin.json?進(jìn)入到 Rubick 的搜索框,所以需要監(jiān)聽搜索框的?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)記為開發(fā)者type:?'dev',//?讀取?iconicon:?'image://'?+?path.join(fileUrl,?`../${config.logo}`),//?標(biāo)記是否是模板subType:?(()?=>?{if?(config.main)?{return?''}return?'template';})()};} }到這里我們已經(jīng)可以根據(jù)復(fù)制的?plugin.json?能獲取到插件的最基礎(chǔ)的信息,接下來就是需要展示搜索框:
?commit('commonUpdate',?{options:?[{name:?'新建rubick開發(fā)插件',value:?'new-plugin',icon:?'https://xxx.com/img.png',desc:?'新建rubick開發(fā)插件',click:?(router)?=>?{commit('commonUpdate',?{showMain:?true,selected:?{key:?'plugin',name:?'新建rubick開發(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',?{showMain:?false,selected:?null,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?頁,加載插件的基礎(chǔ)內(nèi)容,唯一需要注意的是?home?頁加載的內(nèi)容高度應(yīng)該是 Rubick 最大窗口的高度。所以需要調(diào)整窗口大小:
?ipcRenderer.send('changeWindowSize-rubick',?{height:?getWindowHeight(),});關(guān)于?renderer?里面的 Vue 代碼這里就不再詳細(xì)介紹了,因?yàn)榇蠖嗍?css 畫一下就好了,直接來看展示界面:
到這里,就完成了開發(fā)者模式,接下來再聊聊插件是如何在 Rubick 中跑起來的。
插件運(yùn)行原理
直到有一天,我在掘金上看到這樣一個(gè)沸點(diǎn):
運(yùn)行插件需要容器 Electron 提供了一個(gè) webview 的容器來加載外部網(wǎng)頁。所以可以借助 webview 的能力實(shí)現(xiàn)動(dòng)態(tài)網(wǎng)頁渲染,這里所謂的網(wǎng)頁就是插件。但是網(wǎng)頁無法使用 node 的能力,而且做插件的目的就是為了開放與約束,需要對(duì)插件開放一些內(nèi)置的 API 能力。好在 webview 提供了一個(gè) preload 的能力,可以在頁面加載的時(shí)候去預(yù)置一個(gè)腳本來執(zhí)行。
也就是說可以給自己的插件寫一個(gè)?preload.js?來加載。但這里需要注意既要保持插件的個(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.jspreload:?`File://${path.join(__static,?'./preload.js')}`,webview:?null,query:?this.$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ǔ)的插件加載,效果如下:
支持更多體驗(yàn)?zāi)芰?/strong>
隨后為了更加貼近 uTools 的體驗(yàn),我又開始著手讓 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è)推薦開源項(xiàng)目的平臺(tái),了解到鹵蛋也是喜歡打 Dota,我想那他應(yīng)該能感受到 Rubick 的魅力,所以我就抱著試一試的心態(tài)投稿了。先是有幸入選了月刊第 64 期,然后受邀寫了這篇關(guān)于 Rubick 的故事。
最后,感謝 HelloGitHub 讓 Rubick 被更多人發(fā)現(xiàn)和喜歡,特別感謝鹵蛋對(duì)文章的潤色和修改,讓本文增色不少。
總結(jié)
以上是生活随笔為你收集整理的实现工具自由!开源的桌面工具箱的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蓝色巨人IBM全力奔赴的混合云之旅能顺利
- 下一篇: 为什么要使用 Kubernetes 准入