如何基於 Electron 開發跨終端的應用

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/70\/70b710e23f5592cb318a4845155ff072.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先我們分享的第一塊叫"},{"type":"text","marks":[{"type":"strong"}],"text":"端的延展"},{"type":"text","text":"。不知道大家對這張圖熟不熟悉,前段時間的新聞大家應該都聽到過,硅谷鋼鐵俠艾隆馬斯克發佈了第一款商業化的載人龍飛船,這張圖片中就是龍飛船的控制檯,知乎上有人對這張圖的評價叫 JS 上天了。爲什麼說叫 JS 上天了呢?因爲有傳言說它是基於 Electron 開發的,不過這個消息並沒有得到證實。但是可以證實的一點是航天飛船的觸控界面 UI ,確實是基於 Chromium + JavaScript 這樣的架構來實現的。這也從某種程度上說明了這種架構的一個可用性和穩定性的能力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/e6\/e60486221aafddf0500a0457dc6f45fb.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我們一起來回顧一下前端在整個端領域的發展歷程。在早期,前端工程師的定義可能是基於瀏覽器運行環境的 Web 開發,但是隨着 09 年 Node.js 的出現,讓前端工程師有了脫離瀏覽器運行環境的開發能力。我們擁有了可以面向服務端開發的能力,前端的能力延展到了服務端。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/bd\/bd95865c5f0971dcdadcf313751e3463.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隨着 HTML5 標準的制定,以及移動端設備技術的發展,前端工程師也可以更多的擁抱面向移動端場景的開發。也出現了像今天上午兩位講師所講到的移動端領域 React Native 這樣的跨平臺技術方案。隨着移動 APP 成爲一個主流,基於這些智能化的設備以及芯片的計算能力,前端也普及到了物聯網設備方向,前端可以擁有了面向 Iot 的開發能力,也誕生了像 Thing.js  這樣的面向物聯網設備開發的 Js 框架。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"CLI -> GUI"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"今天所要講的主題是"},{"type":"text","marks":[{"type":"strong"}],"text":"桌面端"},{"type":"text","text":",隨着 Electron 這樣的跨終端 JS 框架的出現,整個前端工程師的能力也是延展到了桌面端。當我們擁有了這樣的一個桌面端的開發能力之後,它能帶給我們的價值是什麼呢?首先看一下桌面端給我們帶來哪些不一樣的體驗。大家看到左邊這張圖,是早期電腦的 DOS 系統的運行的截圖,右邊則是 1983 年蘋果電腦發佈的第一款 Apple Lisa 個人電腦,它是全球第一款搭載圖形用戶界面(也就是我們所說的 GUI)的一臺個人電腦,正是因爲這款電腦的問世,讓後期個人電腦大衆化的普及得以實現。爲什麼它會帶動個人電腦的普及化,是因爲圖形界面對於用戶來說,在視覺上更容易接受,學習的成本也是大幅的下降。相信用過 MAC 系統的同學都會對蘋果優秀的界面設計以及整體的交互體驗,有比較深刻的感受。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/88\/88a52b9109393a452c7a1712d1af7517.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼,這樣的桌面端 GUI 的技術,能給我的前端開發工作帶來什麼不一樣呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"左邊這個流程相信大家不陌生,在我們開始新項目開發的時候,可能需要做哪些事情?首先第一步可能是需要去創建一個 Git 倉庫,創建完成之後將倉庫克隆到本地,然後通過團隊內部的 CLI 工具的安裝之後,去執行例如 "},{"type":"codeinline","content":[{"type":"text","text":"xxx-cli create"}]},{"type":"text","text":" 這樣的命令去創建一個項目。創建項目完成之後,如果想進行開發,我們需要去運行 "},{"type":"codeinline","content":[{"type":"text","text":"npm install"}]},{"type":"text","text":" ,安裝所需的依賴包,最終將整個項目提交到 Git 倉庫上去。這是我們新項目的創建,基於 CLI 方式的一個操作流程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/6a\/6a0694ae8b6a5e13d10fa5fc9acf0b5d.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果說基於客戶端的能力的,我們可以做哪些改變呢?我們可以看到,右邊的圖是我們團隊前端工程化平臺敦煌的系統截圖。如果是創建一個新項目,只需要選擇自己的創建方式,然後輸入一些必要的創建參數,比如說選擇你需要創建的 Git 倉庫 Group、項目名稱、腳手架類型,點擊創建項目之後,它會自動幫你將左邊的這一系列的流程全部執行完畢。就是說將左邊 6 個步驟簡化到了 2 個步驟,大大的簡化了操作的鏈路。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"GUI 賦予的價值"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GUI 賦予了我們哪些價值呢?首先它可以將分散的任務點進行一個串聯整合,提供了一個更簡化的操作鏈路,同時它還可以抹平不同同學使用時一些流程間的差異,以及流程所依賴的一些環境的差異,並且基於 GUI 的一個整合能力,我們還可以將其他能力進行一個橫向的串通,並且通過 GUI 來設計插件化的機制,還可以創造一個可共建的生態。同時基於 GUI 的圖形界面操作低學習成本,以及它對整個流程的託管,也是可以大大的降低團隊同學的研發複雜度。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/06\/063bd86b61ddf07ccfb876d7e8df8ff0.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"業務場景應用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是基於 Electron 開發的一些重點應用的落地場景。這是我所負責的政採雲電子招投標客戶端的業務。它主要的功能是幫助用戶由傳統的線下招投標,紙質的標書,轉變爲電子標書,我們提供這樣的客戶端可以幫助用戶串聯整個製作標書的流程。同時基於 Electron 所提供的 Node.js 的能力,用戶本地標書文件的讀寫,以及本地文件的加解密操作,都可以在客戶端裏面完成。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/c6\/c60e98886f464bb33f1e24fb76373dc3.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"基建場景應用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這邊是 Electron 在我們的工程化平臺上的實踐,這就是我們前面所提到的前端工程化平臺-敦煌。它主要做的內容是對整個前端研發流程的託管,像我們剛纔所提到的項目創建就是其中的一個環節。下面我們還會詳細的介紹一些這方面的應用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/25\/25ad2078c0f8de9ffdcb6976e6e569dc.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"開發模式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面我們大概介紹了一下 Electron 的一些價值。如果說我們想基於 Electron 開發一個跨平臺的桌面端應用,應該如何來做?下面一起來看一下,第二部分:開發模式。Electron 的開發模式跟我們平時的 Web 開發有哪些不一樣的地方?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/85\/85b80185c03e43523790a1cf7fe30555.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Electron 架構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先這是 Electron 的一個整體的架構,它是由 Github 開發了一個開源框架,允許我們使用來 HTML + CSS + Javascript 來構建開發桌面應用,大大降低了桌面應用的開發的複雜度。整體架構的核心組成是由 Chromium + Node.js + Native APIs 組成的。其中 Chromium 提供了 UI 的能力,Node.js 讓 Electron 有了底層操作的能力,Navtive APIs 則解決了跨平臺的一些問題,比如說 Windows 系統、MAC OS 系統及 Linux 系統之前一些差異的屏蔽,並且它還提供了一個比較統一體驗的原生能力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/6e\/6e19be0a76f256a3b8834c7cc9f352ba.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"能力點"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們來介紹一下它的一些核心的能力點。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先是 Chromium,我們可以把它理解爲是一個擁有最新版瀏覽器特性的一個 Chrome 瀏覽器,它帶給我們的好處就是在開發過程中無需考慮瀏覽器的兼容性,我們可以使用一些 ES6、ES7 最新的語法,可以放心的使用 Flex 佈局,以及瀏覽器的最新特性,都可以嘗試,不需要考慮兼容性的問題。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Node.js 則是提供了一個文件讀寫、本地命令調用、以及第三方擴展的能力,並且基於 Node.js 整個強大的生態,將近幾十萬的 Node.js 模塊都可以在整個客戶端內使用。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Native APIs 提供了一個統一的原生界面的能力,還包括一些系統通知、快捷鍵,還可以通過它來獲取一些系統的硬件信息。還提供了桌面客戶端的基礎能力,像更新機制、崩潰報告這樣的能力。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/e4\/e4210cd30b76e5365d50c111396a4cc2.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"其他桌面端選型對比"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Electron 提供這些能力點大大的降低了桌面端開發的成本,以及上手的門檻。當然開發桌面端的話,除了 Electron 外,還會有一些其他的選型,我們看一下它跟其他的選型相比較的話有哪些差異點。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開發桌面端首先可以選擇 Native 開發,但是,在開發不同的平臺的時候,需要使用不同的語言,但它的優點是具有比較好的原生體驗,以及比較好的運行性能,但是它的門檻相對來說還是比較高的。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"QT 是一個基於 C++ 的跨平臺桌面端開發框架,它所使用的語言是使用 C++,整體性能和體驗上來說,跟Native 開發的話是可以相媲美的,但由於技術棧原因,開發門檻相對來說也是比較高的。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外兩個就是 Electron 和 NW.js。這兩個都是使用 Javascript 作爲一個開發語言。相較於 Native 和 QT 來說,它們對前端工程師來說是相當友好的,並且它們兩個有着比較相似的一個架構,都是基於 Chromium + Node.js 實現,同時它們也都有一個跨平臺的支持能力。但兩個的差異點是:Electron 相對來說有一個更好的一個社區的生態和社區的活躍度,我們平時如果遇到了一些問題,在社區內可能會有比較多、比較完善的解決方案,同時它對 issue 的響應速度也是比較快的。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以基於上面的比較,開發桌面客戶端,對前端工程師來說,Electron 是一個非常好的選擇。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/28\/286f79dc74f90588bf6f61e052f1c922.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"簡單 Electron 應用的結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面來看一下,如果想開發一個桌面客戶端,應該怎麼做呢?這邊是一個最簡單的 Electron 桌面應用的結構,我們只需要有三個文件,首先我們通過 package.json 中的 "},{"type":"codeinline","content":[{"type":"text","text":"main"}]},{"type":"text","text":" 字段,通過 "},{"type":"codeinline","content":[{"type":"text","text":"main"}]},{"type":"text","text":" 字段來定義應用的一個啓動入口。我們將入口文件定義爲 "},{"type":"codeinline","content":[{"type":"text","text":"main.js"}]},{"type":"text","text":" ,在 "},{"type":"codeinline","content":[{"type":"text","text":"mian.js"}]},{"type":"text","text":" 裏我們做了哪些事情呢?首先 app 代表着整個應用,監聽 app 的狀態,當整個應用達到一個 ready 的狀態之後,通過 Electron 提供的 "},{"type":"codeinline","content":[{"type":"text","text":"BrowserWindow"}]},{"type":"text","text":" ,去新創建一個瀏覽器窗口。創建瀏覽器窗口之後,去加載 "},{"type":"codeinline","content":[{"type":"text","text":"index.html"}]},{"type":"text","text":" 文件,這樣的話我們就完成了一個最基礎版桌面端應用的實現。基於 Electron 開發桌面端應用,和平時的開發 web 端應用有哪些不一樣的,我們需要了解的兩個核心概念就是:"},{"type":"text","marks":[{"type":"strong"}],"text":"主進程和渲染進程,以及兩個進程間的通信如何實現"},{"type":"text","text":"。在剛纔的示例中,其中 "},{"type":"codeinline","content":[{"type":"text","text":"main.js"}]},{"type":"text","text":" 是運行在主進程中, "},{"type":"codeinline","content":[{"type":"text","text":"index.html"}]},{"type":"text","text":" 則是運行在渲染進程之中。下面我們通過一個簡單的 Demo,來看一下如何實現兩個進程之間的通信,並且如何通過主進程來進行一些 Node.js 能力調用的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/9a\/9ac21681bdef7b9c1136d2713ea88d1d.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"進程間的通信"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們想要實現這樣的效果,頁面上有一個按鈕,當點擊按鈕之後,向主進程發送了一個 "},{"type":"codeinline","content":[{"type":"text","text":"say-hello"}]},{"type":"text","text":" 的消息,當主進程接收到消息之後,它會在系統桌面上創建一個文件叫 "},{"type":"codeinline","content":[{"type":"text","text":"hello.txt"}]},{"type":"text","text":"。並寫入內容 "},{"type":"codeinline","content":[{"type":"text","text":"Hello Mac!。"}]},{"type":"text","text":"具體的我們是怎麼做的?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先在渲染進程裏面,我們應該在頁面上會進行一個按鈕操作事件,當事件觸發之後,我們通過 Electron 提供的 "},{"type":"codeinline","content":[{"type":"text","text":"ipcRenderer"}]},{"type":"text","text":"  API 向主進程發送一個叫 "},{"type":"codeinline","content":[{"type":"text","text":"say-hello"}]},{"type":"text","text":" 這樣的一個消息。當我們的主進程接收到這樣一個消息之後,則可以在主進程中直接調用 Node.js 的 fs 模塊,一個文件讀寫的模塊。首先先創建一個文件,並且對這個文件寫入我們所傳輸的內容。當文件寫入成功之後,對渲染進程進行回覆,通過調用 Electron 提供的 "},{"type":"codeinline","content":[{"type":"text","text":"Notification"}]},{"type":"text","text":"模塊,顯示系統通知去告知用戶,這是一個簡單的 Demo 的實現,其核心的點就是需要關注主進程和渲染進程的概念,以及兩個進程之間是如何通過 IPC 機制進行通信的,這邊是一個簡單的實現。還有一些更多的應用的場景,這塊就不再對 API 進行過多的介紹。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/69\/69803ec141413c8b6b75fd0e39cf44b5.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我們會根據一個實際的應用,來介紹一下 Electron 開發的實踐。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"工程化發展 CLI -> GUI"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/e4\/e40de2931ed6e41e719e9930d2348cf8.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以我們的前端工程化平臺敦煌爲例,介紹一下我們是如何通過 Electron 將工程化能力由 CLI 式 變爲 GUI 式的使用。首先大家先看一個視頻,這個視頻就是我們在最開始所提到的項目創建的整個流程的運行的演示。大家可以看到我們整個流程完成了 Git 倉庫的創建、項目模板的創建、項目模板到倉庫的推送,並且對 Git 項目進行本地克隆,克隆完成之後,會進行依賴的安裝,並且在客戶端進行重新載入和管理這樣一個流程。將之前分散的單點命令操作,通過 GUI 的方式進行一個串聯。這個流程只是工程化平臺中的一塊,我們在整個工程化平臺中,實現了很多的單點命令到工作流的串聯。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/53\/5365c0fb6b2287de35b1e9b2ef0efad8.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"I2P(Install To Publish)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這邊是我們整個前端應用管理平臺的系統架構,大概看一下。核心流程就是上面所寫到的一個 I2P 的概念,就是 "},{"type":"codeinline","content":[{"type":"text","text":"install to publish"}]},{"type":"text","text":" 。它完成了組件、模板和項目這三個級別,從創建到發佈的全流程託管。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"創建階段,主要提供了包括本地創建、Git 創建、統一的創建模板管理、創建的流程審批和創建完成的反饋。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開發階段,提供了一個 Dev Server 的運行能力,對項目級的頁面管理、依賴管理、分支管理,還有一鍵式的升級能力。同時還打通了 CI\/CD 持續集成能力。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"發佈階段,則提供了一個發佈前的權限校驗和合規檢測、資源推送以及發佈的審批機制。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據分析,是我們整個流程中比較核心的一塊,是對我們整個流程進行一些數據沉澱,並且將這些數據以可視化報表的形式進行成輸出,基於這些數據將整個 I2P 的流程與其他的能力進行一個串聯。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上面的整個 I2P 的流程中,我們沉澱出一些項目數據,包括流程數據,可能還有一些類似於組件管理的數據。以數據爲連接點,可以將整個的研發流程與其他的一些技術建設能力進行一個串聯打通,包括用戶行爲分析、頁面級、項目級的性能分析報告,還有錯誤監控的機制,都可以接入到整個工程化平臺上。支撐我們整個工程化平臺就是一些基礎能力以及 Electron 所提供的桌面端能力。基礎能力,包括一些常規的 GIt 操作、NPM 操作、一些命令執行和一些本地的 logger 服務。Electron 提供了桌面端包括更新、窗口管理、通信,以及些原生能力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/fd\/fd82ae518748f695a7774fb83d28b5dc.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"由點到線"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1c\/1c57e6c0e81f20433abedb9a7baae65d.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"單點命令 -> 任務流"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我們就具體來看一下如何實現由一個單點命令到任務流這樣的一個串聯。將單點命令的操作變爲任務流的串聯模式,我們要從以下 4 個切入點來實現。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"• 首先我們要將常規的一些命令調用變爲函數式的調用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"• 基於這些函數式的調用,進行一個任務流的編排和組裝,根據實際的開發場景,去定製一個任務流。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"• 第三塊我們所需要的是整個任務流的任務進度反饋機制,如何將任務執行,通過 GUI 的能力,讓用戶可以直觀感受到整個任務的執行鏈路和進度。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"• 最後,在整個任務流中,很重要的一塊就是對整個流程的數據收集。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/40\/40165eb59f803ea377d1e185d39bac36.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"流程的設計"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是我們剛纔所演示的項目創建流程的架構設計。當我們在調用項目創建模塊的時候,首先會通過 Server 接口,去創建 Git 項目。先對整個用戶的權限做一層校驗,校驗通過之後,通過調用 Gitlab API,進行一個倉庫的創建,之後,根據所選用的模板信息拉取統一維護的項目模板,根據用戶所輸的項目名稱、項目描述等信息,來生成真正的項目文件,調用 Gitlab API 將整個項目文件推送到創建好的倉庫。關於 Gitlab API 的使用這一塊,在掘金上有進行過文章的分享,大家感興趣的話可以去了解一下,這邊就不再進行詳細的闡述。在我們整個服務端完成了一系列的 Git 創建操作之後,會將創建成功的倉庫 url,給到我們的桌面端,桌面端接收到這樣創建成功的任務結果之後,開始執行一些本地操作的任務流程。將 Git 倉庫克隆到本地的工作區內,同時完成整個項目的依賴安裝。在依賴安裝之後,我們會藉助桌面端的通知能力,包括釘釘的接口去完成通知和反饋。其中克隆、依賴的安裝以及通知反饋是在我們桌面端的主進程內完成的。在我們整個任務流中,它有實時與渲染進程的消息反饋。我們會將整個任務的進度,包括命令執行的日誌輸出、命令執行結果,通過 IPC 的方式實時的與渲染進行通信,最終在界面上給到用戶反饋。在整個流程中,也會對項目數據和流程數據進行存儲。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/cc\/ccc93d21d6861f7d80179e7ea87d8bc7.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實現這樣的整個流程,在實踐上有哪些是需要說的呢,下面我們來看一下具體的代碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"npm install 變爲 npm.install()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先在進行命令調用的時候,要將 "},{"type":"codeinline","content":[{"type":"text","text":"npm install"}]},{"type":"text","text":" 這樣一個命令行的調用方式變成變爲一個函數式的調用,會變爲 "},{"type":"codeinline","content":[{"type":"text","text":"npm.install()"}]},{"type":"text","text":" 這樣一個調用方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a0\/a0ed510add90749863786ce3a884fa96.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"git init 變爲 git.init()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"類似 Git 的命令,也會變成函數式調用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/4d\/4d221c7d40519caeede24453fce8f648.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"將命令式執行 Promise 化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我們看一下,具體場景,如何將命令式調用變成函數式調用。首先是將命令執行 Promise 化。例如 "},{"type":"codeinline","content":[{"type":"text","text":"git init"}]},{"type":"text","text":" 這樣的操作,在執行整個命令的時候,我們更多關心的是整個命令執行的結果,可能不太會關心命令執行過程中的一些輸出的內容。這樣的話我們就可以通過 Node.js 中的 "},{"type":"codeinline","content":[{"type":"text","text":"spawn"}]},{"type":"text","text":" ,啓動子進程來執行命令。通過監聽子進程輸出來判斷我們整個命令的執行狀態,然後對整個命令進行 Promise 封裝,我們就完成了 "},{"type":"codeinline","content":[{"type":"text","text":"git init"}]},{"type":"text","text":" 這樣一個命令行調用變爲 "},{"type":"codeinline","content":[{"type":"text","text":"git.init()"}]},{"type":"text","text":" 這樣一個異步的函數調用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/12\/127883edc506407cb47d6c8d91c51675.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"實時輸出命令執行日誌"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在另外一個場景,比如說 "},{"type":"codeinline","content":[{"type":"text","text":"npm install"}]},{"type":"text","text":" ,依賴安裝,或者說啓動本地開發服務,整個命令的執行過程可能會比較長,我們更關注的是過程中實時的日誌輸出。我們怎麼來做呢?首先我們這邊是先創建一個 "},{"type":"codeinline","content":[{"type":"text","text":"EventEmitter"}]},{"type":"text","text":" 實例,作爲我們的日誌的分發管理,同樣的我們也是通過 "},{"type":"codeinline","content":[{"type":"text","text":"spwan"}]},{"type":"text","text":" 來啓動一個子進程來執行命令,並且實時的監聽子進程的輸出,將輸出的日誌通過 "},{"type":"codeinline","content":[{"type":"text","text":"emitter"}]},{"type":"text","text":" 實例將它分發出去。當我們在主進程中拿到這樣的實時日誌輸出之後,可以通過 Electron 主進程跟渲染進程間的 IPC 的通信,將日誌實時的輸出到渲染進程當中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/bf\/bf4b8001e8aee31a556d06ed39511d42.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將命令式調用變爲函數式調用,有了這樣的能力之後,就可以通過對這些函數的調用,進行任務流的編排。例如剛纔我們所提到的項目創建,這可能是一個比較通用的流程,還有組件管理、模板管理和以及項目發佈等。大家可以根據自己實際的業務需要,來去編排自己一個任務流。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"模擬終端:反饋任務進度"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面我們提到的是主進程中對整個命令執行方式的一些改變。那麼在我們的渲染進程當中,我們要怎樣去實現類似於剛纔視頻中的終端日誌反饋呢?反饋的方式有很多,我們可以通過設計一些任務的步驟條,或者進度條這樣的方式來給予整個任務進度的反饋。但是更好的方式是我們可以把任務的進度,包括整個任務輸出日誌進行一個及時的反饋。這邊我們使用的是 xterm.js。它是一個基於 ts 所編寫的一個前端終端組件,可以在瀏覽器內實現終端應用,VsCode 也是基於 xterm.js 來實現的終端的。要如何將主進程的日誌來輸出到渲染進程當中,就是我們上面所提到的,在拿到一個 EventEmitter 所廣播的的輸出之後,要通過主進程與渲染進程之間的通信,將數據推送到渲染進程,在渲染進程所需要做的一個處理,把接受到的命令輸出,實時的渲染到 xterm 實現的終端組件上面來。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣的話我們就完成了整個任務流的反饋機制。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/dd\/ddb78c4ebb6015d76973002b427f1861.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以上就是我們在工程化平臺中一個任務流的實現,藉助於 Electron 能力,我們就可以很方便的實現整個流程任務的編排,以及實現對應流程的界面交互,對整個流程進行簡化。除了任務流的實現之外,我們更多需要關注的是整個過程中的數據收集,包括流程數據以及流程中創建的項目、組件數據沉澱,也包括流程當中一些異常數據,因爲這些數據是將流程與其他的基礎建設能力進行打通的基礎,同時也能讓我們對整個流程持續的優化,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"更新"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在完成客戶端的開發之後,需要考慮的則是後續的更新,一起來看一下,我們如何實現客戶端的自動更新的功能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a4\/a49ac274fd68c9bdabfb434c8e6ad45b.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Electron 提供了一套比較完善的打包更新機制。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過 Election-builder 把我們的應用構建之後,會輸出一個 latest-mac.yml 文件,以及應用的 zip 包,將這兩個文件放到更新服務器上,更新服務器的實現方案有很多,我們選用的是 CDN 來做爲更新服務器。我們如何去設計整個更新的流程,在渲染進程內,一般會提供手動檢測更新的觸發入口,或者通過輪詢任務,來定時進行版本更新檢測。渲染進程發起版本檢測求之後,會在渲染進程內調用  "},{"type":"codeinline","content":[{"type":"text","text":"autoUpdater"}]},{"type":"text","text":" 模塊,它是 "},{"type":"codeinline","content":[{"type":"text","text":"Electron"}]},{"type":"text","text":" 內置的更新管理模塊。首先需要設置 feedUrl,就是最新的更新包在更新服務端地址。當收到一個渲染進程的版本檢測請求之後,調用 "},{"type":"codeinline","content":[{"type":"text","text":"checkForUpdates"}]},{"type":"text","text":" 方法,之後,它會觸發下面一系列的一些事件,我們可以通過對整個更新事件的各個生命週期的監聽,來完成整個更新流程的把控。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/f6\/f6bb8470adf30e2fece481dbb7af57d3.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過 Electron 內置的一個更新機制要面臨的問題是更新包體積比較大。因爲我們通過 Electron 所構建的桌面端的應用,它將整個 Chromium 進行了集成,就會導致即使我們寫了一個很小的 Hello world 這樣一個應用,它的體積壓縮後也會有 40MB 左右,常規的一個應用來說可能佔用 100MB 左右。這樣的問題就是有一些比較小的改動的時候,就需要全量的更新,對於用戶的一個體驗來說並不是很好,對於這些我們有哪些解決方案?首先我們是可以對整個更新的交互設計上做一個優化。我們需要提供的是對整個更新流程的一個進度反饋,另外一點就是我們可以通過 autoUpdater,實現後臺的下載。當我們完成了整個更新包的下載之後,然後再通知用戶對整個應用進行一個重啓,然後更新整個應用,這樣的話就才從交互層面上,一定程度的避免了增量更新對用戶所體驗上的一些影響。當然全量更新還會存在的一個問題,如果用戶量比較大的話,就會比較浪費網絡資源。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"增量發佈"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是我們的一些在增量發佈上面的一些實踐。首先對整個 Renderer 層的靜態資源進行 CDN 託管。對於我們整個應用,不會將 Renderer 層的靜態資源打包到最終的桌面端程序內,將資源遠程託管,同時我們根據一些特定的業務場景,可以利用 service worker 能力,對整個資源做一個離線緩存,並且對靜態資源做版本控制。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/70\/70365589d2020c683a3b774d21ca2dba.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"更新流程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Renderer 層的一個更新流程是這樣的,當頁面發請求的時候,首先會匹配本地有沒有這樣的一個資源的緩存,如果我們匹配到資源,就會返回匹配到的結果。如果說本地沒有匹配到的話,就重新請求最新資源,同時將請求的資源進行緩存。如果說在整個請求的過程中出現了錯誤,需要有一個可使用的默認版本的資源,並且將錯誤進行上報。這裏我們所實現的一個是基於 UI 層的一個增量更新。實際的業務場景,需要根據不同資源的更新頻率,來決定應該是進行更新的體驗優化,還是使用 UI 層增量更新,或者安裝包的增量更新。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/f1\/f12a5fcb9ea86aced602ee818b3a0e6b.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"敦煌工程化平臺技術架構圖"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這邊是整個應用管理平臺的架構,在我們的整個工程實踐中,除了實現了對整個項目、組件還有模板的 I2P 全流程託管之外,我們還提供了其他能力,例如團隊入口的收斂,包括文檔入口,輸出入口,同時還將團隊內部的一些工具進行一個整合,將一些分散在各個地方的一些工具,比如說文檔站點生成工具、圖牀工具,iconfont 管理工具進行了一個整合,同時我們還對整個客戶端的用戶行爲數據做了採集,通過數據分析來持續迭代。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/c1\/c154cd3c9fe6e8ee1ddea2039869ca4d.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"更多場景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以上我們基於 Electron 的前端工程化平臺的實踐。當然 Electron 還會有一些其他的應用場景,我們一起來看一下。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/96\/96e851275021c6c624a495527d29e453.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先 VS code,以及支付寶小程序的 IDE,也是基於 Electron 框架實現的"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/cc\/cc4b174385761ba60434f2ffb7c9cc9d.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"左邊是一個接口管理的桌面端工具,爲開發過程提供輔助的功能。另外一個 switchhosts,它是一個本地環境管理工具。大家可以看到基於 Electron 開發的桌面端的應用,在我們整個的研發流程中,從我們的本地環境管理、流程管理,開發輔助以及研發編輯階段都有涉及。工程化管理平臺是對整個研發生命週期流程上的串通,但是在實際的編碼階段,其實還是有一個脫離的環節,依然需要依賴 IDE 的能力。基於 Electron 在 IDE 方向的一些可能性,我們未來的一個方向也是,希望將整個 IDE 的本地編碼環境與我們的整個研發流程進行一個串通,真正意義上的實現整個研發鏈路的串通以及效率升級。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/71\/716ee301c3d7da74920600d167f8dd1f.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然還有更多的可能性,就是前面提到的 spaceX 這樣更大的一個場景~"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/e6\/e60486221aafddf0500a0457dc6f45fb.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"推薦一本書"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是我個人所推薦的一本書《少有人走的路》,從書中可以收穫的是如何以更成熟的心智去看待所遇到的問題。在成長過程中,限制我們的,更可能是認知以及思維侷限性。以什麼認知和心態去看待遇到的問題,就會決定會以什麼樣的反應和什麼樣的能力去迴應這些問題。這本書會讓我們更多的去探索,怎樣以更成熟的心智去看待所遇到的問題。希望通過這本書能讓大家收穫如何更好的面對技術以外的問題,更好的解決問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/2b\/2bad2aa8629ec2a9b6a4e74293958cbb.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"頭圖:Unsplash"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者:子洋"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文:https:\/\/mp.weixin.qq.com\/s\/qucl_k9pFCga1krHlNTSyQ"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文:如何基於 Electron 開發跨終端的應用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"來源:政採雲前端團隊 - 微信公衆號 [ID:Zoo-Team]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"轉載:著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章