用React x Electron做個PR小工具

TomatoSoup
拯救世界的一千零一種方法
11 min readSep 17, 2022

用React開發桌面app幫自己省點時間

Talk is cheap. Show me the code.

repo放在前頭是禮貌,react菜雞歡迎批評指教(合掌)

https://github.com/TomatoSoup0126/PR-content-generator

繼去年用Vue + Electron做了個excel轉換器之後,一直覺得Electron是個讓前端無縫寫桌面app的好文明,在開了幾次讓人厭世的PR(Pull request)後,決定來寫個side project以解決撰寫PR內容緩慢的過程。

緣起:

公司專案在開PR的同時,會需要在標題註記該項PR對應的需求票號以自動同步該票的狀態(on dev / on production …),並在內容貼上該票連結,方便QA和需求單位驗收。

平常單項功能進到dev branch的情況,這個額外的小作業並不至於太麻煩,但輪到大進版時,整包release往master推的這種PR,就會需要爬commit或是看file diff來整理這支PR上所關聯的所有票號,整個過程就會變的相當耗時,再加上公司的需求票同時存在於redminejira兩套專案管理工具上(這說來話長先跳過),所以往往會花上不少時間在兩套專案管理工具上來回找查需求票,再將其剪剪貼貼到PR中,按照目前兩個禮拜一次的進板節奏,每到那時候就是個開PR到厭世的日子(眼神死

發想:

想讓上述手動作業自動化的念頭油然而生,整理一下工人智慧的情況下都幹了什麼:

  1. 開出PR,例如dev branch → release branch
  2. 肉眼掃commit,找出有註記票號的commit
  3. 辨識票號是哪種格式,是jira票號還是redmine票號
  4. 前往對應的專案管理工具,找出那張需求票
  5. 將票號貼進PR標題中、把票號網址貼進PR內容中
  6. 重複2. ~ 5.項作業,直到commit掃完

轉換成自動化的難點應該還是在資訊的取得,也就是:

  1. github是否有查詢branch diff的api?
  2. jira、redmine是否有查詢票號詳細內容的api?

有api的話,剩下的就和平時前端做的事情87%像,沒有的話就只好認份的用puppeteer爬資料了(?

很幸運的,爬文後都有XDDD

Github doc — compare-two-commits

Redmine Rest Issue

Jira REST APIs

大愉悅

上面三者分別需要對應服務的驗證機制,前兩者是Bearer token、後者為Basic auth,所以最好有個介面可以輸入token們和Basic auth的username,再讓我有個介面可以指定repo和branch供api查找…

理一下使用者故事大概就是:

  1. 可以輸入github token
  2. 可以輸入redmine token
  3. 可以輸入jira account、token
  4. 可以輸入兩個branch name
  5. 可以用1. 和 4. 的資訊打github api拉回branch diff
  6. 拉回branch diff後,從其中的commits用正規表達式濾出redmine和jira票號
  7. 若有redmine票號,用所有redmine票號搭配2. 逐項打api拿回相關資訊
  8. 若有jira票號,用所有jira票號搭配3. 逐項打api拿回相關資訊
  9. 將7.、8.的資訊整理成markdown並顯示在畫面上
  10. 9.的部分可以複製到剪貼簿,最後手動貼到PR上就算完成功能

技術選擇:

大概知道要做什麼之後,就輪到思考要用什麼技術來弄出這東西…

token等相關設定似乎不方便外流,而且又有點懶得部署到網路上…那就是Electron了,在自己桌面上直接啟動App來使用吧!

前端框架的部分倒是毫不猶豫地選了React,因為還沒用React實做過任何作品嘛(自找麻煩XD

Javascript的部分,也來嘗試一下Typescript好了,大不了之後寫成anyscript(不對

接著找尋有沒有現成的Electron + React template,翻了翻github上還不少這種template,就挑個順眼且結合了Vite的模板:electron-vite-react

UI library的部分就爬了些網路文章:

5 best React UI frameworks to build web applications faster in 2022

Top 8 React UI Framework and Component Libraries in 2022

看了看簡介再稍微看看各套件的文件,最後選了文件感覺較親切點的Material UI (隔壁的查克拉UI好搶眼啊!

最後的問題便是CSS library要用誰好,在unoCSS和Tailwind之中猶豫了幾秒…上面好像夠多未知數了,至少CSS這邊先用長期配合的切版好戰友Tailwind吧XD

所以最後的選擇變成:

ReactElectronViteMaterial uiTailwind

接著就來開工吧!

v1.0

打鐵趁熱,馬上一天內先弄出了個第一版體驗一下,大致上可以滿足上述一開始提出的功能,另外補上把設定寫入local storage的功能,減少每次打開就要一路貼token的額外麻煩。

v1.0,沒什麼用到tailwind的外觀

心得和難點稍微記錄一下:

  1. material ui的sx prop還滿強大的,library內部的的component都可以使用這個prop來進行排版,也是tailwind大幅減少出場機會的元兇。
  2. 正規表達式每次都上網找別人組好的,真的要自創pattern還是只能乖乖面對,靠regex101不斷的try and error才順利完成兩種pattern。
  3. 連續fetch jira和redmine的作法,原本傻傻地用forEach去逐項打api,但結果就是造成各種非同步狀態管理的不方便,最後使用Promise.all()來進行處理,直接使用一個函式去map票號陣列,回傳一個包含各個Promise fetch的陣列來進行Promise.all(),就可以很好的等待所有票號api都完成後再開始處理所有資料。
  4. jira和github token如果commit起來推到github上,會馬上寄訊息通知你token已外洩並強制註銷,頗為安心啊XD
  5. 剪貼板在electron內有自己的api,簡單好用。
  6. TS的型別檢查真的嚴格,花了不少時間解,不過很高機率是該方法可能回傳null和undefind的情況下,必須確保其型別已經有所列舉。

v2.0

開心的用著v1.0開PR幾分鐘後,就覺得…那些設定沒事可以不用看到吧?還有要對不同repo開PR,每次都要在input上剪剪貼貼也是挺麻煩的,以及branch只有dev、release、production三個選項,其他repo的staging和feature branch我也想用啊啊啊啊!

身為前端,滿足自己的UX應該也是很合理的吧?

於是開始思考優化的方向:

  1. 設定相關應該可以獨立出一個分頁,設定好應該就不用看它了
  2. repo和branch應該可以對選項進行CRUD,但Update有點麻煩,CRD就好(?
  3. 因為2的關係,repo欄位可以從input變為selector
  4. 該拆出component了,當前的v1.0全部都擠在App.tsx中

方向都有了,那就開始優化吧!

拆分大成功 ☆

同樣的記錄一下心得和難點:

  1. 因為主架構變為App內包含ActionPanel、SettingPanel兩個component,但ActionPanel會需要SettingPanel設定的資料,故設定相關資料依舊留在App內,再將資料與其set function用props往兩個Panel component傳下去。
  2. branch、repo的列表設定介面基本上就是個todo list component,另外將部分icon、placeholder、data、set function抽成props,就可以複用成兩個列表了。
  3. 子層input onInput事件去觸發父層的set function更新整個object會造成子層re-render,看起來像是輸入一個字元就強制blur的bug,目前解決方法是不即時觸發set function,待輸入完畢後按下儲存鈕再一次觸發所有set function來避免這情況。

v3.0

這版主要是來自同事的兩個需求,有其他使用者當然要好好照顧一下啊XD

來自同事的需求part 1:

白色好傷眼喔,可以有Dark mode嗎?

偉哉Material ui有內建Dark mode,主要是應用的react hooks的createContext,讓ThemeProvider內的所有元件都可以取得toggleColorMode來進行切換,並使用已包裝好的useTheme()來取得相關的設定值,再補上一些對應元件的顏色切換,和之前一樣把設定往local storage內儲存,便能開心完成Dark mode囉!

工程師友善介面

來自同事的需求part 2:

要追更新很麻煩耶,一般桌面軟體不是都有自動更新嗎?

看了下electron確實有auto update的套件,並且仰賴electron自家的server對指定repo的github release進行比對確認是否有更新釋出,完全不需要自架server來處理這段,實在是非常優秀XD

魔鬼藏在細節處QQ

馬上照著指引安裝套件,再將package.json內的repo設定好…

最後一步便是要設定Builds時的code-signed用以證明這個App無毒友善,macOS需要申請Apple Developer Program來能簽署,趕快來申請一下吧!

年費$3400的高牆阻擋於此

果斷放棄實作自動的念頭,直接把錢拿去刷了github copilot,感謝蘋果讓我如此果斷,side project寫一寫順便刷了copilot,真香XDDD

但是自動更新的需求還是沒有解決,重新思考一下,問題應該是在:

使用者不主動查詢的情況下,不會知道軟體發佈更新了

不能自動下載安裝更新,但換成通知使用者有更新,後面的下載安裝交給使用者自助,應該有機會吧?

於是找到有基於原有服務的通知版套件electron-update-notifier,基本設定和原有服務一樣,馬上可以直接沿用,重啟App便會自動偵測到new release並跳出通知啦!

按下Download就會導至release頁面囉

早知道這功能應該先做上去的,相見恨晚莫過於此。

目前這專案就更新到v3.0.1,相較一開始的需求要多做了點東西上去,整體開發體驗也是挺舒服的(除了那個Apple Developer Program),暫時如果沒有其他需求被提出來可能就是偶爾修修bug或是improvement吧!

另外就是electron打包後的檔案肥碩問題暫時好像無解,這專案安裝後居然就要200多MB,讓人意外到不行,下次來試看看其他資深大大建議基於Rust和webview的Tauri,看起來可以有效減低打包體積呢!

最後還有個和開發較無相關的部分,就是為了不想用預設的App icon,請教了公司的UI/UX如何使用figma做點簡單的圖示,成果就是一開始的圖片啦,寫side project就是會點到其他技能樹呢(?

若有其他指教歡迎留言或是發PR,或是有相關需求歡迎許願讓我練練手喔!

--

--