使用Electron開發桌面級程式——J.A.R.V.I.S誕生記

李文楊發表於2019-06-05

 

 

那一天我二十一歲,在我一生的黃金時代,我有好多奢望。我想愛,想吃,還想在一瞬間變成天上半明半暗的雲,後來我才知道,生活就是個緩慢受錘的過程,人一天天老下去,奢望也一天天消逝,最後變得像捱了錘的牛一樣。可是我過二十一歲生日時沒有預見到這一點。我覺得自己會永遠生猛下去,什麼也錘不了我。

 

現在是凌晨一點,可能是在夜裡的時候人會變得比較感性,所以突然想到了王小波在黃金時代中寫下的這段話,沒有理由的在這篇技術文章中將它作為引言。希望大家在自己的黃金時代永遠的生猛下去,什麼也錘不了你。

 

書歸正傳,我們們上回書說到在我的第一版小程式釋出系統被伺服器拍倒在沙灘上後,我把目光從web轉移到了app上,並準備使用Electron來構建一套app安裝在電腦上用來解決伺服器不支援部署小程式開發者工具的坑,接下來我將此次開發過程的思考和問題進行總結,從多個角度來介紹本專案。

 

J.A.R.V.I.S是做什麼的?

它是一個安裝在Mac或Windows上的app程式,可以隨時從Git上拉取最新程式碼選取分支和tag並自動打包構建不同環境上傳至小程式後臺的釋出系統。

 

為什麼叫J.A.R.V.I.S?

老賈是唐尼的智慧管家,專案啟動的時候正值復聯四熱映,主要是為了紀念一下唐尼吧,在星期五和Jarvis兩個名字中猶豫了好久,最後還是覺得Jarvis比較酷一點。嗯,就是這麼隨意。

 

設計思路

 

工作原理

electron本質上就是一個將web打包成桌面應用的 Node. js 的變體,在開啟app的同時就會啟動一個node服務,通過node可以實現很多前端無法實現的事情,一個釋出系統整個流程都是千篇一律的,無非就是拉程式碼、拉分支、切分支、構建開發包、上傳後臺。其中拉程式碼、切分支、構建這種平時在命令列內進行的操作,可以將它交給nodeJs提供的child-process衍生子程式的功能進行不同目錄下的shell指令碼執行,最關鍵的上傳則需要通過node請求微信開發中工具提供的api為渲染層提供上傳介面進行相應操作。最後將electron專案打包為app,分別裝在開發者的電腦上就可以實現一個基礎版的小程式上傳系統。

 

工作流程

配置

第一次使用需要先進行基礎配置,將本機使用者名稱、專案地址、開發者暱稱一併儲存到本地Stroage,為後續操作提供基礎資訊。儲存的同時將專案拉取到本地的Applications目錄中並新建一個jarvis目錄,此目錄用來儲存以後所有需要構建的小程式專案,此時jarvis目錄作為一個黑盒子,所有的資訊都是從git拉下來的最新提交,與本地專案的開發程式碼會形成隔離,你的本地任何程式碼改動操作都不會影響到盒子內專案的資訊,除非你進行了commit。

 

打包構建

切換分支

配置完基礎資訊後呼叫gitlabApi拉取該專案的分支和tag資訊,渲染到下拉選單選擇切換本地分支,同時在皮膚展示分支的基礎資訊,專案名稱、當前分支名稱、提交時間、提交描述、提交成員、提交id......

專案編譯

接下來需要填寫本次上傳的版本號和版本描述並選擇打包環境,然後進行專案構建。這裡選擇環境選擇的是需要打包專案的根目錄中的構建命令,比如我的小程式專案使用gulp構建,gulpfile中定義了四種打包命令,那麼在點選開始專案構建後,程式會自動切換到黑盒中的專案根目錄下執行對應命令並打包為dist檔案。

 

上傳

打包完之後的檔案通過微信官方提供的http呼叫介面,先獲取到開發者工具在本地的埠號檔案,通過呼叫upload的api拼接埠號、專案路徑、描述、版本號進行上傳。上傳成功後在皮膚上展示上傳資訊和上傳狀態並且通過釘釘群同步推送上傳訊息,包含釋出版本、描述、釋出人,最後在微信公眾平臺選擇設定體驗版。到此,一個完整的編譯打包上傳流程全部完成。

 

談談基礎架構

整體使用vue-electron框架,分為五個大模組

  • dist——src的輸出目錄

  • src--開發目錄

  • static——靜態資原始檔目錄

  • build——打包檔案目錄

  • .electron-vue——webpack配置目錄

 

.electron-vue——webpack配置目錄

此目錄下儲存著不同的webpack配置檔案,使用vue-loader、babel-loader、url-loader、vue-html-loader、post-css等外掛使專案成為支援解析.vue檔案,可使用高階js語法的現代化工程,並且會將開發目錄打包為標準的electron專案。

 

dist electron輸出目錄

通過webpack將專案打包為一個electron的標準專案,輸出到dist目錄下,package.json將會以此目錄下的mian.js作為入口檔案進行執行。

 

src——開發目錄

src作為核心內容,包含三大部分main(electron主程式檔案目錄)、render(前端渲染層頁面——vue+element)、service(後端提供服務介面——express)。

 

main作為一個橋樑的存在,連結著渲染層和服務端程式。其中service-main.js作為service中express的的啟動檔案匯出,並在main/index.js中與electron同時啟動,index.js為啟動electron的核心檔案,最後會被webpack編譯輸出到輸出目錄下——dist/electron/main.js

 

render負責前端頁面的視覺化渲染,使用vue+element可以快速的構建出一套現代化的介面,某些情況下也可能會與原生app進行通訊,如去除預設邊框、自定義快捷命令等,所以渲染層常用的一個方法就是ipcRenderer,通過ipcRenderer可以與electron進行通訊呼叫electron提供的一些原生api。

 

示例(關閉、放大、縮小)

 

這是vue定義的點選事件,通過傳送不同的引數與electron的mian進行互動。

main.js負責監聽通訊並執行動作

示例(解決打包後無法複製貼上的問題)

 

 if (process.platform === 'darwin') {    const template = [      {        label: "Application",        submenu: [          { label: "Quit", accelerator: "Command+Q", click: function() { app.quit(); }}        ]      },       {        label: "Edit",        submenu: [          { label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },          { label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },        ]      }    ];    Menu.setApplicationMenu(Menu.buildFromTemplate(template))  } else {    Menu.setApplicationMenu(null)  }

 

service為分為rutes、views、app.js三部分,rutes負責整個前端頁面提供呼叫介面,app.js負責服務的啟動和介面路由的註冊,view內使用pug模板承載一些異常狀態的訪問頁面。

示例(實現分環境打包介面)

這裡需要注意一下,這個介面的實現是非常靈活的,需要根據你當前專案的編譯檔案進行配置,比如我的專案開發時使用gulp打包編譯環境到dist,其編譯命令分別為:

  • gulp build:Dev(聯調環境)

  • gulp build:Test(測試環境)

  • gulp build:Slave(預釋出環境)

  • gulp build:Prod(線上環境)

 

那麼同理,配置好dist輸出檔案目錄,收到請求後執行事先實現好的shell命令即可完成打包這一步,如果你不太瞭解環境編譯打包這塊內容,可以參考我之前的一篇文章"《武裝你的小程式——開發流程指南》"

 

程式碼實現

build 打包app目錄

 build是app打包完成後的輸出目錄,這個檔案可以存放你的專案圖示,打包的時候electron會預設在這個目錄下找圖示,如果找不到就會使用electron預設圖示。

使用electron遇到的問題

  • 官方強烈推薦使用yarn安裝依賴,淘寶映象安裝的依賴會在打包的時候導致超級多的未知bug!!!比如我一不小心使用了cnpm安裝了elemnent-ui最後打包導致無法解析該模組,只能刪除node-modules重新使用yarn安裝。

  • error:Cannot assign to read only property 'exports' of object '#<Object>' 在express專案裡使用了model.exports方式匯出模組,但webpack 2中不允許混用import和module.exports 解決辦法:

1.解決辦法就是統一改成ES6的方式編寫即可. import {a} from './a'; export default a;

2.引入外掛transform-es2015-modules-commonjs yarn add babel-plugin-transform-es2015-modules-commonjs 然後在 babelrc中配置
{ "plugins": ["transform-es2015-modules-commonjs"] } 即可解決

  • 如果在electron中使用了child_process去開啟一個子程式執行shell的話,像是gulp,npm這種在開發環境可以正常執行,但打包app後node執行的環境變數就會被更改,導致執行失敗,可以將process.env.PATH手動更改為process.env.PATH+=':/usr/local/bin'即可。

  • 打包的app圖示不是自己配置的圖示?

腳手架的pacage.json有三個欄位

你可以在這裡配置你的專案圖示。

 

專案展望

當前專案已經可以在公司內部的生產環境中使用,但與內部專案耦合嚴重,不夠靈活,同時還有一些未知的問題和不足,我會在後續慢慢完善和優化,待解耦完成程式碼足夠健壯的情況下會選擇將專案程式碼開源出來,下面列出後續將要實現的功能。

 

  1. 專案管理器功能,可配置多個不同專案分別進行打包上傳。

  2. 高度自定義的配置資訊:gitlab的token、釘釘機器人的token、不同專案的打包執行指令碼、不同的環境配置。

  3. 支援自定義分支列表而不是一次全部拉取出來,這對一些擁有超多的分支大型專案來說是不靈活的。

  4. 除了介面的shell指令碼執行結果外打包後的驗證功能,可以通過讀取部分差異化檔案進行比對打包結果。

  5. 同時支援支付寶小程式的上傳功能。

 

結語

經過兩個多月的空閒時間開發,期間算上demo做了三個版本,從layui+express的前後端耦合版的1.0.0版本demo,到分離前後端分離的1.1.0的初版一切完成準備部署線上開發環境,因為前期思考的一些失誤導致專案部署失敗,再到從web轉移到使用electron開發app安裝在本地的1.2.0版本這個過程中收穫滿滿,這個過程使我在思考問題和程式碼設計、專案架構的搭建各個方面都有了一個全新的認識,與此同時也學習到了一些新的技術框架,再此還要感謝同事大佬們的幫助為我提供各種思路和技術支援。

 

現在是凌晨四點鐘,寫不動了兩個眼皮已經開始打架了,你看過北京凌晨四點鐘的太陽麼?emmm....根本就沒有太陽,可能洛杉磯天亮的比較早,真羨慕科比大佬。今天是週六可以睡個懶覺起床吃飯打農藥,熬夜的癮是戒不掉了,但還是奉勸大家不要熬夜了,因為夜熬得太爛了就不好吃了。

 

 

相關文章