關注前端早早聊,跟進第三十屆|前端早早聊大會 BFF 專場(GraphQL、統一網關、API 接入管理、超大規模集羣,協議轉換、安全切面、高併發、可視化編排、統一穩定性建設...)8-14 全天直播,9 位講師,點擊報名看直播👉 ):html
前端早早聊大會,與掘金聯合舉辦。加 codingdreamer 進大會技術羣,贏在新的起跑線, 全部往期都有全程錄播,上手年票一次性解鎖所有前端
歡迎你們來到今天的早早聊跨端跨棧專場,今天我分享的主題是《如何基於 Electron 開發跨終端的應用》。 先作一下自我介紹,我叫逯子洋,17 年加入政採雲,目前主要負責政採雲前端工程化平臺敦煌以及政採雲電子招投標客戶端的建設。這邊是咱們團隊的微信公衆號,你們若是想對咱們團隊有更多的瞭解,能夠關注一下咱們的公衆號。git
首先咱們分享的第一塊叫端的延展。不知道你們對這張圖熟不熟悉,前段時間的新聞你們應該都聽到過,硅谷鋼鐵俠艾隆馬斯克發佈了第一款商業化的載人龍飛船,這張圖片中就是龍飛船的控制檯,知乎上有人對這張圖的評價叫 Js 上天了。爲何說叫 Js 上天了呢?由於有傳言說它是基於 Electron 開發的,不過這個消息並無獲得證明。可是能夠證明的一點是航天飛船的觸控界面 UI ,確實是基於 Chromium + JavaScript 這樣的架構來實現的。這也從某種程度上說明了這種架構的一個可用性和穩定性的能力。 web
下面咱們一塊兒來回顧一下前端在整個端領域的發展歷程。在早期,前端工程師的定義多是基於瀏覽器運行環境的 Web 開發,可是隨着 09 年 Node.js 的出現,讓前端工程師有了脫離瀏覽器運行環境的開發能力。咱們擁有了能夠面向服務端開發的能力,前端的能力延展到了服務端。npm
隨着 HTML5 標準的制定,以及移動端設備技術的發展,前端工程師也能夠更多的擁抱面向移動端場景的開發。也出現了像今天上午兩位講師所講到的移動端領域 React Native 這樣的跨平臺技術方案。隨着移動 APP 成爲一個主流,基於這些智能化的設備以及芯片的計算能力,前端也普及到了物聯網設備方向,前端能夠擁有了面向 Iot 的開發能力,也誕生了像 Thing.js 這樣的面向物聯網設備開發的 Js 框架。json
今天所要講的主題是桌面端,隨着 Electron 這樣的跨終端 Js 框架的出現,整個前端工程師的能力也是延展到了桌面端。當咱們擁有了這樣的一個桌面端的開發能力以後,它能帶給咱們的價值是什麼呢?首先看一下桌面端給咱們帶來哪些不同的體驗。 你們看到左邊這張圖,是早期電腦的 DOS 系統的運行的截圖,右邊則是 1983 年蘋果電腦發佈的第一款 Apple Lisa 我的電腦,它是全球第一款搭載圖形用戶界面(也就是咱們所說的 GUI)的一臺我的電腦,正是由於這款電腦的問世,讓後期我的電腦大衆化的普及得以實現。爲何它會帶動我的電腦的普及化,是由於圖形界面對於用戶來講,在視覺上更容易接受,學習的成本也是大幅的降低。相信用過 MAC 系統的同窗都會對蘋果優秀的界面設計以及總體的交互體驗,有比較深入的感覺。 小程序
那麼,這樣的桌面端 GUI 的技術,能給個人前端開發工做帶來什麼不同呢?後端
左邊這個流程相信你們不陌生,在咱們開始新項目開發的時候,可能須要作哪些事情?首先第一步多是須要去建立一個 Git 倉庫,建立完成以後將倉庫克隆到本地,而後經過團隊內部的 CLI 工具的安裝以後,去執行例如 xxx-cli create
這樣的命令去建立一個項目。建立項目完成以後,若是想進行開發,咱們須要去運行 npm install
,安裝所需的依賴包,最終將整個項目提交到 Git 倉庫上去。這是咱們新項目的建立,基於 CLI 方式的一個操做流程。 若是說基於客戶端的能力的,咱們能夠作哪些改變呢?咱們能夠看到,右邊的圖是咱們團隊前端工程化平臺敦煌的系統截圖。若是是建立一個新項目,只須要選擇本身的建立方式,而後輸入一些必要的建立參數,好比說選擇你須要建立的 Git 倉庫 Group、項目名稱、腳手架類型,點擊建立項目以後,它會自動幫你將左邊的這一系列的流程所有執行完畢。就是說將左邊 6 個步驟簡化到了 2 個步驟,大大的簡化了操做的鏈路。前端工程化
GUI 賦予了咱們哪些價值呢?首先它能夠將分散的任務點進行一個串聯整合,提供了一個更簡化的操做鏈路,同時它還能夠抹平不一樣同窗使用時一些流程間的差別,以及流程所依賴的一些環境的差別,而且基於 GUI 的一個整合能力,咱們還能夠將其餘能力進行一個橫向的串通,而且經過 GUI 來設計插件化的機制,還能夠創造一個可共建的生態。同時基於 GUI 的圖形界面操做低學習成本,以及它對整個流程的託管,也是能夠大大的下降團隊同窗的研發複雜度。瀏覽器
下面是基於 Electron 開發的一些重點應用的落地場景。這是我所負責的政採雲電子招投標客戶端的業務。它主要的功能是幫助用戶由傳統的線下招投標,紙質的標書,轉變爲電子標書,咱們提供這樣的客戶端能夠幫助用戶串聯整個製做標書的流程。同時基於 Electron 所提供的 Node.js 的能力,用戶本地標書文件的讀寫,以及本地文件的加解密操做,均可以在客戶端裏面完成。
這邊是 Electron 在咱們的工程化平臺上的實踐,這就是咱們前面所提到的前端工程化平臺-敦煌。它主要作的內容是對整個前端研發流程的託管,像咱們剛纔所提到的項目建立就是其中的一個環節。下面咱們還會詳細的介紹一些這方面的應用。
上面咱們大概介紹了一下 Electron 的一些價值。若是說咱們想基於 Electron 開發一個跨平臺的桌面端應用,應該如何來作?下面一塊兒來看一下,第二部分**開發模式。**Electron 的開發模式跟咱們平時的 Web 開發有哪些不同的地方?
首先這是 Electron 的一個總體的架構,它是由 Github 開發了一個開源框架,容許咱們使用來 HTML + CSS + Javascript 來構建開發桌面應用,大大下降了桌面應用的開發的複雜度。總體架構的核心組成是由 Chromium + Node.js + Native APIs 組成的。其中 Chromium 提供了 UI 的能力,Node.js 讓 Electron 有了底層操做的能力,Navtive APIs 則解決了跨平臺的一些問題,好比說 Windows 系統、MAC OS 系統及 Linux 系統以前一些差別的屏蔽,而且它還提供了一個比較統一體驗的原生能力。
咱們來介紹一下它的一些核心的能力點。
Electron 提供這些能力點大大的下降了桌面端開發的成本,以及上手的門檻。固然開發桌面端的話,除了 Electron 外,還會有一些其餘的選型,咱們看一下它跟其餘的選型相比較的話有哪些差別點。
因此基於上面的比較,開發桌面客戶端,對前端工程師來講,Electron 是一個很是好的選擇。
下面來看一下,若是想開發一個桌面客戶端,應該怎麼作呢? 這邊是一個最簡單的 Electron 桌面應用的結構,咱們只須要有三個文件,首先咱們經過 package.json 中的 main
字段,經過 main
字段來定義應用的一個啓動入口。咱們將入口文件定義爲 main.js
,在 mian.js
裏咱們作了哪些事情呢?首先 app 表明着整個應用,監聽 app 的狀態,當整個應用達到一個 ready 的狀態以後,經過 Electron 提供的 BrowserWindow
,去新建立一個瀏覽器窗口。建立瀏覽器窗口以後,去加載 index.html
文件,這樣的話咱們就完成了一個最基礎版桌面端應用的實現。基於 Electron 開發桌面端應用,和平時的開發 web 端應用有哪些不同的,咱們須要瞭解的兩個核心概念就是:主進程和渲染進程,以及兩個進程間的通訊如何實現。在剛纔的示例中,其中 main.js
是運行在主進程中, index.html
則是運行在渲染進程之中。下面咱們經過一個簡單的 Demo,來看一下如何實現兩個進程之間的通訊,而且如何經過主進程來進行一些 Node.js 能力調用的。
咱們想要實現這樣的效果,頁面上有一個按鈕,當點擊按鈕以後,向主進程發送了一個 say-hello
的消息,當主進程接收到消息以後,它會在系統桌面上建立一個文件叫 hello.txt
。並寫入內容 Hello Mac!。
具體的咱們是怎麼作的?
首先在渲染進程裏面,咱們應該在頁面上會進行一個按鈕操做事件,當事件觸發以後,咱們經過 Electron 提供的 ipcRenderer
API 向主進程發送一個叫 say-hello
這樣的一個消息。當咱們的主進程接收到這樣一個消息以後,則能夠在主進程中直接調用 Node.js 的 fs 模塊,一個文件讀寫的模塊。首先先建立一個文件,而且對這個文件寫入咱們所傳輸的內容。當文件寫入成功以後,對渲染進程進行回覆,經過調用 Electron 提供的 Notification
模塊,顯示系統通知去告知用戶,這是一個簡單的 Demo 的實現,其核心的點就是須要關注主進程和渲染進程的概念,以及兩個進程之間是如何經過 IPC 機制進行通訊的,這邊是一個簡單的實現。還有一些更多的應用的場景,這塊就再也不對 API 進行過多的介紹。
下面咱們會根據一個實際的應用,來介紹一下 Electron 開發的實踐。以咱們的前端工程化平臺敦煌爲例,介紹一下咱們是如何經過 Electron 將工程化能力由 CLI 式 變爲 GUI 式的使用。 首先你們先看一個視頻,這個視頻就是咱們在最開始所提到的項目建立的整個流程的運行的演示。你們能夠看到咱們整個流程完成了 Git 倉庫的建立、項目模板的建立、項目模板到倉庫的推送,而且對 Git 項目進行本地克隆,克隆完成以後,會進行依賴的安裝,而且在客戶端進行從新載入和管理這樣一個流程。將以前分散的單點命令操做,經過 GUI 的方式進行一個串聯。 這個流程只是工程化平臺中的一塊,咱們在整個工程化平臺中,實現了不少的單點命令到工做流的串聯。
這邊是咱們整個前端應用管理平臺的系統架構,大概看一下。核心流程就是上面所寫到的一個 I2P 的概念,就是 install to publish
。它完成了組件、模板和項目這三個級別,從建立到發佈的全流程託管。
在上面的整個 I2P 的流程中,咱們沉澱出一些項目數據,包括流程數據,可能還有一些相似於組件管理的數據。以數據爲鏈接點,能夠將整個的研發流程與其餘的一些技術建設能力進行一個串聯打通,包括用戶行爲分析、頁面級、項目級的性能分析報告,還有錯誤監控的機制,均可以接入到整個工程化平臺上。 支撐咱們整個工程化平臺就是一些基礎能力以及 Electron 所提供的桌面端能力。 基礎能力,包括一些常規的 GIt 操做、NPM 操做、一些命令執行和一些本地的 logger 服務。Electron 提供了桌面端包括更新、窗口管理、通訊,以及些原生能力。
下面咱們就具體來看一下如何實現由一個單點命令到任務流這樣的一個串聯。將單點命令的操做變爲任務流的串聯模式,咱們要從如下 4 個切入點來實現。 • 首先咱們要將常規的一些命令調用變爲函數式的調用。 • 基於這些函數式的調用,進行一個任務流的編排和組裝,根據實際的開發場景,去定製一個任務流。 • 第三塊咱們所須要的是整個任務流的任務進度反饋機制,如何將任務執行,經過 GUI 的能力,讓用戶能夠直觀感覺到整個任務的執行鏈路和進度。 • 最後,在整個任務流中,很重要的一塊就是對整個流程的數據收集。
下面是咱們剛纔所演示的項目建立流程的架構設計。當咱們在調用項目建立模塊的時候,首先會經過 Server 接口,去建立 Git 項目。先對整個用戶的權限作一層校驗,校驗經過以後,經過調用 Gitlab API,進行一個倉庫的建立,以後,根據所選用的模板信息拉取統一維護的項目模板,根據用戶所輸的項目名稱、項目描述等信息,來生成真正的項目文件,調用 Gitlab API 將整個項目文件推送到建立好的倉庫。關於 Gitlab API 的使用這一塊,在掘金上有進行過文章的分享,你們感興趣的話能夠去了解一下,這邊就再也不進行詳細的闡述。在咱們整個服務端完成了一系列的 Git 建立操做以後,會將建立成功的倉庫 url,給到咱們的桌面端,桌面端接收到這樣建立成功的任務結果以後,開始執行一些本地操做的任務流程。將 Git 倉庫克隆到本地的工做區內,同時完成整個項目的依賴安裝。在依賴安裝以後,咱們會藉助桌面端的通知能力,包括釘釘的接口去完成通知和反饋。 其中克隆、依賴的安裝以及通知反饋是在咱們桌面端的主進程內完成的。在咱們整個任務流中,它有實時與渲染進程的消息反饋。咱們會將整個任務的進度,包括命令執行的日誌輸出、命令執行結果,經過 IPC 的方式實時的與渲染進行通訊,最終在界面上給到用戶反饋。在整個流程中,也會對項目數據和流程數據進行存儲。
實現這樣的整個流程,在實踐上有哪些是須要說的呢,下面咱們來看一下具體的代碼。
首先在進行命令調用的時候,要將 npm install
這樣一個命令行的調用方式變成變爲一個函數式的調用,會變爲 npm.install()
這樣一個調用方式。
相似 Git 的命令,也會變成函數式調用
下面咱們看一下,具體場景,如何將命令式調用變成函數式調用。 首先是將命令執行 Promise 化。例如 git init
這樣的操做,在執行整個命令的時候,咱們更多關心的是整個命令執行的結果,可能不太會關心命令執行過程當中的一些輸出的內容。這樣的話咱們就能夠經過 Node.js 中的 spawn
,啓動子進程來執行命令。經過監聽子進程輸出來判斷咱們整個命令的執行狀態,而後對整個命令進行 Promise 封裝,咱們就完成了 git init
這樣一個命令行調用變爲 git.init()
這樣一個異步的函數調用。
在另一個場景,好比說 npm install
,依賴安裝,或者說啓動本地開發服務,整個命令的執行過程可能會比較長,咱們更關注的是過程當中實時的日誌輸出。咱們怎麼來作呢? 首先咱們這邊是先建立一個 EventEmitter
實例,做爲咱們的日誌的分發管理,一樣的咱們也是經過 spwan
來啓動一個子進程來執行命令,而且實時的監聽子進程的輸出,將輸出的日誌經過 emitter
實例將它分發出去。當咱們在主進程中拿到這樣的實時日誌輸出以後,能夠經過主進程跟渲染進程間的 IPC 的通訊,將日誌實時的輸出到渲染進程當中。
將命令式調用變爲函數式調用,有了這樣的能力以後,就能夠經過對這些函數的調用,進行任務流的編排。例如剛纔咱們所提到的項目建立,這多是一個比較通用的流程,還有組件管理、模板管理和以及項目發佈等。你們能夠根據本身實際的業務須要,來去編排本身一個任務流。
上面咱們提到的是主進程中對整個命令執行方式的一些改變。那麼在咱們的渲染進程當中,咱們要怎樣去實現相似於剛纔視頻中的終端日誌反饋呢?反饋的方式有不少,咱們能夠經過設計一些任務的步驟條,或者進度條這樣的方式來給予整個任務進度的反饋。可是更好的方式是咱們能夠把任務的進度,包括整個任務輸出日誌進行一個及時的反饋。這邊咱們使用的是 xterm.js。它是一個基於 ts 所編寫的一個前端終端組件,能夠在瀏覽器內實現終端應用,VsCode 也是基於 xterm.js 來實現的終端的。要如何將主進程的日誌來輸出到渲染進程當中,就是咱們上面所提到的,在拿到一個 EventEmitter 所廣播的的輸出以後,要經過主進程與渲染進程之間的通訊,將數據推送到渲染進程,在渲染進程所須要作的一個處理,把接受到的命令輸出,實時的渲染到 xterm 實現的終端組件上面來。
這樣的話咱們就完成了整個任務流的反饋機制。
以上就是咱們在工程化平臺中一個任務流的實現,藉助於 Electron 能力,咱們就能夠很方便的實現整個流程任務的編排,以及實現對應流程的界面交互,對整個流程進行簡化。除了任務流的實現以外,咱們更多須要關注的是整個過程當中的數據收集,包括流程數據以及流程中建立的項目、組件數據沉澱,也包括流程當中一些異常數據,由於這些數據是將流程與其餘的基礎建設能力進行打通的基礎,同時也能讓咱們對整個流程持續的優化,
在完成客戶端的開發以後,須要考慮的則是後續的更新,一塊兒來看一下,咱們如何實現客戶端的自動更新的功能。 Electron 提供了一套比較完善的打包更新機制。
經過 Election-builder 把咱們的應用構建以後,會輸出一個 latest-mac.yml 文件,以及應用的 zip 包,將這兩個文件放到更新服務器上,更新服務器的實現方案有不少,咱們選用的是 CDN 來作爲更新服務器。 咱們如何去設計整個更新的流程,在渲染進程內,通常會提供手動檢測更新的觸發入口,或者經過輪詢任務,來定時進行版本更新檢測。 渲染進程發起版本檢測求以後,會在渲染進程內調用 autoUpdater
模塊,它是 Electron
內置的更新管理模塊。 首先須要設置 feedUrl,就是最新的更新包在更新服務端地址。當收到一個渲染進程的版本檢測請求以後,調用 checkForUpdates
方法,以後,它會觸發下面一系列的一些事件,咱們能夠經過對整個更新事件的各個生命週期的監聽,來完成整個更新流程的把控。
經過 Electron 內置的一個更新機制要面臨的問題是更新包體積比較大。由於咱們經過 Electron 所構建的桌面端的應用,它將整個 Chromium 進行了集成,就會致使即便咱們寫了一個很小的 Hello world 這樣一個應用,它的體積壓縮後也會有 40MB 左右,常規的一個應用來講可能佔用 100MB 左右。這樣的問題就是有一些比較小的改動的時候,就須要全量的更新,對於用戶的一個體驗來講並非很好,對於這些咱們有哪些解決方案?首先咱們是能夠對整個更新的交互設計上作一個優化。咱們須要提供的是對整個更新流程的一個進度反饋,另一點就是咱們能夠經過 autoUpdater,實現後臺的下載。當咱們完成了整個更新包的下載以後,而後再通知用戶對整個應用進行一個重啓,而後更新整個應用,這樣的話就才從交互層面上,必定程度的避免了增量更新對用戶所體驗上的一些影響。固然全量更新還會存在的一個問題,若是用戶量比較大的話,就會比較浪費網絡資源。
下面是咱們的一些在增量發佈上面的一些實踐。首先對整個 Renderer 層的靜態資源進行 CDN 託管。對於咱們整個應用,不會將 Renderer 層的靜態資源打包到最終的桌面端程序內,將資源遠程託管,同時咱們根據一些特定的業務場景,能夠利用 service worker 能力,對整個資源作一個離線緩存,而且對靜態資源作版本控制。
Renderer 層的一個更新流程是這樣的,當頁面發請求的時候,首先會匹配本地有沒有這樣的一個資源的緩存,若是咱們匹配到資源,就會返回匹配到的結果。若是說本地沒有匹配到的話,就從新請求最新資源,同時將請求的資源進行緩存。若是說在整個請求的過程當中出現了錯誤,須要有一個可以使用的默認版本的資源,而且將錯誤進行上報。 這裏咱們所實現的一個是基於 UI 層的一個增量更新。實際的業務場景,須要根據不一樣資源的更新頻率,來決定應該是進行更新的體驗優化,仍是使用 UI 層增量更新,或者安裝包的增量更新。
這邊是整個應用管理平臺的架構,在咱們的整個工程實踐中,除了實現了對整個項目、組件還有模板的 I2P 全流程託管以外,咱們還提供了其餘能力,例如團隊入口的收斂,包括文檔入口,輸出入口,同時還將團隊內部的一些工具進行一個整合,將一些分散在各個地方的一些工具,好比說文檔站點生成工具、圖牀工具,iconfont 管理工具進行了一個整合,同時咱們還對整個客戶端的用戶行爲數據作了採集,經過數據分析來持續迭代。
以上咱們基於 Electron 的前端工程化平臺的實踐。固然 Electron 還會有一些其餘的應用場景,咱們一塊兒來看一下。 首先 VS code,以及支付寶小程序的 IDE,也是基於 Electron 框架實現的 左邊是一個接口管理的桌面端工具,爲開發過程提供輔助的功能。另一個 switchhosts,它是一個本地環境管理工具。你們能夠看到基於 Electron 開發的桌面端的應用,在咱們整個的研發流程中,從咱們的本地環境管理、流程管理,開發輔助以及研發編輯階段都有涉及。工程化管理平臺是對整個研發生命週期流程上的串通,可是在實際的編碼階段,其實仍是有一個脫離的環節,依然須要依賴 IDE 的能力。基於 Electron 在 IDE 方向的一些可能性,咱們將來的一個方向也是,但願將整個 IDE 的本地編碼環境與咱們的整個研發流程進行一個串通,真正意義上的實現整個研發鏈路的串通以及效率升級。
固然還有更多的可能性,就是前面提到的 spaceX 這樣更大的一個場景~
下面是我我的所推薦的一本書《少有人走的路》,從書中能夠收穫的是如何以更成熟的心智去看待所遇到的問題。在成長過程當中,限制咱們的,更多是認知以及思惟侷限性。以什麼認知和心態去看待遇到的問題,就會決定會以什麼樣的反應和什麼樣的能力去迴應這些問題。這本書會讓咱們更多的去探索,怎樣以更成熟的心智去看待所遇到的問題。 但願經過這本書能讓你們收穫如何更好的面對技術之外的問題,更好的解決問題。
以上就是我今天的全部的分享,這邊是咱們團隊公衆號的二維碼,你們能夠去了解一下咱們團隊的一些輸出,同時咱們近期也是在招聘前端實習生、資深、高級前端工程師。若是有興趣的話,能夠向下面的郵箱 進行簡歷的投遞,感謝你們~
請問子洋:如何進行熱更新呢?據我瞭解 Electron 打包出來的頁面是放在包內的,如何進行在線更新?
我理解問題應該是 UI 層界面的更新。其實剛纔我有提到過,咱們對頁面的一些靜態資源是作了一個 cdn 上的託管,在更新的時候,會有一個檢測更新的機制,它能夠經過輪詢或者服務端推送來實現,當收到靜態資源版本更新的通知,經過主進程對渲染進程進行一個忽略緩存的強制刷新,或者說能夠經過在主進程有相應的交互,包括升級提醒和更新日誌,讓用戶觸發頁面重載,去更新 UI 層面的靜態資源。
請問子洋:Electron 和 NW.js 的區別能請您對比一下嗎?
它們兩個最大的區別是在於對 Node.js 和 Chromium 事件循環機制的整合的處理方式是不同的。首先 NW.js 是經過修改源碼的方式,讓 Chromium 與 Node.js 的事件循環機制進行打通; Electron 實現的機制是經過啓用一個新的安全線程,在 Node.js 和 Chromium 之間作事件轉發,這樣來實現二者的打通。這樣的一個好處就是 Chromium 和 Node.js 的事件循環機制不會有這麼強的耦合。另外的區別則是 NW.js 支持 xp 系統,Electron 是不支持的。相比較而言 Electron 有着更活躍的社區,以及更多的大型應用如 VS code、Atom 的實踐案例,更多的區別能夠參考 Electron 官方的一篇介紹:www.electronjs.org/docs/develo…
請問子洋:更新包的文件是放在私有文件服務器仍是 Gitlab 或者 Github 上面?
有比較多方式,咱們的實現是經過 CDN 的託管,也能夠經過 Github 或者私有文件服務器的搭建來實現。根據本身實際的業務場景和技術棧來選擇。
關注前端早早聊,跟進學習更多 BFF/GraphQL,請關注第三十屆|前端早早聊大會 BFF 專場 - 玩轉先後端接口(GraphQL、統一網關、API 接入、API 管理、協議轉換、統一安全切面、高併發處理、可視化編排、統一穩定性建設...)8-14 全天直播,9 位講師,報名上車看直播👉 ):