時間過得真快,在忙碌的工作中,2020 年就已經過去了。
雖然到了 2021 年,年齡增加了一歲,白頭髮多了很多,技術學了很多,但是工資卻沒有見漲。
那能如何呢?難道 xxx 不再剝削了,打工人就能自由了?
「打工人,打工魂,打工才是人上人」,透露出小人物在平凡生活中的不懈追求,有著更積極的樂觀主義色彩。
這是一種自嘲,也是一直激勵。同為打工人,那就一起來學習一直很火的 electron 吧。
閱讀本文需要一定的 node 基礎知識。知道 electron 是開發桌面應用程式的技術。
本文主要介紹了桌面應用程式的歷史和 electron 的歷史,分析了 electron 原理和 electron-vue 項目架構,快速上手了 electron-vue 項目。
關鍵詞Electron Electron-vue
正文一、 背景在開發 xxx 項目的時候,需要用到 electron 技術,為了讓更多同學了解和喜歡 electron,我想通過本文分享這些年的實戰經驗。
二、 桌面應用程式的歷史桌面應用程式,又稱為 GUI 程序。
從古到今,開發桌面應用程式有很多種技術,每種技術的優劣,大家可能耳熟能詳了:
VB上古程式設計師的開發工具,曾經全球第一的開發語言,拖拽式的圖形化開發讓它成為極佳的桌面開發工具。微軟依靠其作業系統的優勢,一直壓制同時期的競爭對手 delphi。C++的win32API其 MFC 方案是基於窗口中組合控制項和消息傳遞機制。這也是 20 多年前的技術,所以 API 設計的不是很友好。幾年前微軟已經停止維護,簡單來說它已經過時了。Winform但是從開發體驗角度來說自定義、美化控制項會比較麻煩。C#的.net framework代表就是 WPF,它的原生特性是其他類庫無法比擬的:High DPI、Split Screen 以及對 DirectX 的天然優勢。但是並不開源,需要依賴 .net 框架,還有就是啟動會比較慢。Java的swing/javaFx這是一類比較大的陣營,優勢是跨平臺和流行開發語言 Java 的天然結合,但是界面不太美觀。C++的Qt這是很多客戶端跨平臺的首選,因為開源、UI 庫和各種功能的類庫非常豐富,但是學習成本比較高。C++的duilib這是 windows 下開源的 directUI(微軟提出的分離 UI 和邏輯的思想)庫,它是迎合網際網路桌面軟體小而美的趨勢發展起來的,可能大家對它的關注度比較少。但是用它開發出的產品大名鼎鼎,比如 QQ、微信、愛奇藝等很多知名度高的軟體。Objective-c/swift cocoa這是 mac 平臺下的方案。可以方便調用底層的 API,缺點是不跨平臺,文檔不友好,UI 庫並不豐富。現在這種方式開發的越來越少了。從 B/S 和 C/S 架構逐漸融合的角度來說,基於 Web 技術進行桌面程序的開發漸漸變成了主流。因為對界面的代碼部分可以做到復用。
這類技術早期的方案是用 vb 內嵌 webBrowser 控制項,基於 IE 內核,正好很多網頁開發也有用 activeX 的需求,但這種方式具有明顯的缺陷,就是非常依賴於用戶的環境,會因為組件缺失導致程序各種崩潰。嵌入式網頁框架,這類技術主要是基於瀏覽器引擎實現 UI 渲染。比較典型的就是 appkit 上面 UIWebView 和 CEF (chro-mium embeded framework)。這種方法可以使用網頁 HTML5+CSS 實現各種酷炫的效果,但是缺點也比較明顯,就是桌面程序裡面嵌入了一個類似 Chrome 的瀏覽器,內存的開銷會比較大。後面出現了 nwjs 和 electron,electron 相比 CEF 有了單獨執行 js 的 v8 引擎,可以運行 Node.js 來完成伺服器端功能,通過和內部瀏覽器的 v8 引擎交互可以實現一個獨立的客戶端,這不同於 CEF 需要寄宿在其他程序內部。
三、 Electron的歷史Electron(最初名為 Atom Shell)是 GitHub 開發的一個開源框架。它允許使用 Node.js(作為後端)和 Chromium(作為前端)完成桌面 GUI 應用程式的開發。Electron 現已被多個開源 Web 應用程式用於前端與後端的開發,著名項目包括 GitHub 的 Atom 和微軟的 Visual Studio Code。
圖 1 ATM編輯器
圖 2 vscode編輯器
官網上第一段話就是:Electron 是一個框架,可以讓您使用 JavaScript,HTML 和 CSS 創建桌面應用程式。然後這些應用程式可以打包在 macOS、Windows 和 Linux 上直接運行,或者通過 Mac App Store 或微軟商店分發。通常,您使用每個作業系統特定的本地應用程式框架為作業系統 (OS)創建一個桌面應用程式。Electron 可以在使用您已經知道的技術後寫入您的應用程式。由此看出,它是框架,而不是庫,前端開發者可以像開發 web 應用一樣開發桌面應用程式。當然在各大應用商店都可以上架,這個需要各自的認證,這個之後文章講述。
圖 3 electron圖標
其優勢如下圖:
圖 4 electron的優勢
用 Electron 來做桌面程序開發的優勢明顯,相當於是完全的網頁編程,有 Web 開發經驗的前端開發上手非常容易。Web 開發生態廣泛,開發成本低,可擴展性強,一些流行的前端框架例如 React、Angular、Vue 都可以和 electron 結合進行開發。另外它也具備和 Qt 一樣跨平臺的優良特性。對性能要求不高的桌面版程序來說,一份代碼同時得到網頁版和各個平臺的桌面版,開發的效率是其他方案無法比的。可以說,這是大部分人看好的趨勢。
四、 Electron的入門(一) 應用程式結構圖 5 electron的架構
Electron 由三個主要部分組成:
自定義 APIs 用於使用經常需要的 OS 本機函數。Electron 開發應用程式就像構建一個帶有網頁界面的 Node.js 應用程式,想一想 vscode 就瞬間明了。
主進程和渲染器進程Electron 有兩種進程 :Main 進程和Rendererer 進程。
Main 進程,又叫主進程,通常是名為 main.js 的文件,是每個 Electron 應用的入口文件。它控制著整個 App 的生命周期,從打開到關閉。它也管理著系統原生元素比如菜單、菜單欄、Dock 欄(軟體啟動後,在屏幕下方生成的一條欄)和託盤等。主進程負責創建 APP 的每個渲染進程。而且整個 Node API 都集成在裡面。每個應用程式的主進程文件都在 package.json 中的 main 屬性中指定。這就是程序知道在啟動時執行什麼文件。Rendererer 進程,又叫渲染進程。在 Chromium 中,此進程被稱為「瀏覽器進程」。它在 Electron 中重新命名,以避免與渲染器過程混淆。與主進程不同的是,它可以有多個,每個都是在一個單獨的進程中運行的。它們也可以被掩蓋。在通常的瀏覽器內,網頁通常運行在一個沙盒的環境中,並且不能夠使用原生的資源。然而 Electron 的用戶在 Node.js 的 API 支持下可以在頁面中和作業系統進行一些低級別的交互。
主進程通過創建 BrowserWindow 實例來創建網頁。每一個 BrowserWindow 實例在其渲染過程中運行網頁。當一個 BrowserWindow 實例被摧毀時,對應的渲染過程也被終止。渲染進程只能管理每個相應的網頁。在一個渲染過程中崩潰不會影響其他渲染過程。渲染進程通過 IPC 與主進程通信在網頁上執行 GUI 操作。由於安全考慮和可能的資源洩漏,直接從渲染器過程中調用與本地 GUI 有關的 API 受到限制。談到兩個進程,那必須要涉及進程間通信。可以通過進程間通信模塊進行:ipcMain 和 ipcRenderer。
ipcMain從主進程到渲染進程的異步通信。可以從主進程向渲染進程發送消息。
回復同步信息時,需要設置 event.returnValue。可以使用 event.reply(...) 將異步消息發送回發送者。ipcRenderer從渲染器進程到主進程的異步通信。下面是一個渲染進程向主進程通信的例子:
同步:
//在渲染進程中
const { ipcRenderer } = require('electron')
ipcRenderer.on('main-reply', (event, arg) => {
console.log(arg) // "main的回覆消息"
})
ipcRenderer.send('render-main-message', '來自render的消息')// 在主進程中
const { ipcMain } = require('electron')
ipcMain.on('render-main-message', (event, arg) => {
console.log(arg) // "來自render的消息"
event.reply('main-reply', 'main的回覆消息')
})異步:
//在渲染進程中
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('render-main-message', '來自render的消息')) // 來自render的消息// 在主進程中
const { ipcMain } = require('electron')
ipcMain.on('render-main-message', (event, arg) => {
console.log(arg) // 來自render的消息
event.returnValue = '來自render的消息'
})這兩段代碼很好理解,渲染進程發送消息,主進程接受到消息事件後回復消息回復渲染進程,最主要的區別在於一個是異步一個是同步。
Electron APIElectron API 是根據流程類型分配的。這意味著某些模塊可以從主程序或渲染程序中使用,有些模塊可以從兩者中使用。Electron 的 API 文檔指明了每個模塊可以使用的過程。例如,要在兩個進程中訪問 Electron API,需要它包含的模塊:
const electron = require('electron')若要創建一個窗口,則要調用 BrowserWindow 類,只能在主進程中使用:
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()若要從渲染進程往主流程中發送消息,請使用 IPC 模塊:
// 在主進程中
const { ipcMain } = require('electron')
ipcMain.on('event', (event, args) => {
console.log('接收到的數據是:', args)
})
// 在渲染進程中
const { ipcRenderer } = require('electron')
ipcRender.send('event', ...args)
Node.js API★注意:要從渲染過程中訪問 Node.js API,您需要設置 nodeIntegration 選項為 true。Electron 在主進程和渲染進程中顯示對 Node.js API及其模塊的完全訪問權限。例如,我可以從根目錄讀取所有文件:
」const fs = require('fs')
const root = fs.readdirSync('/')
console.log(root)要使用 Node.js 模塊,就需要安裝它作為依賴:
npm install --save minio然後,在 Electron 應用程式中,導入模塊:
var Minio = require('minio')官網提供的 electron 模板是 electron-quick-start,啟動命令如下:
# 克隆示例項目的倉庫
$ git clone https://github.com/electron/electron-quick-start
# 進入這個倉庫
$ cd electron-quick-start
# 安裝依賴並運行
$ npm install && npm start
圖 6 electron-quick-start模板項目
這個模板沒有集成任何前端框架,開發效率慘不忍睹。
對於 react 開發者,可以去翻閱 electron-react-boilerplate (https://github.com/electron-react-boilerplate/electron-react-boilerplate)對於 vue 開發者,可以查閱 electron-vue(https://github.com/SimulatedGREG/electron-vue),這也是我重點要講述的項目。
五、 Electron-vue基於 vue 來構造 electron 應用程式的模板代碼。
該項目的目的,是為了要避免使用 vue 手動建立起 electron 應用程式。electron-vue 充分利用 vue-cli 作為腳手架工具,加上擁有 vue-loader 的 webpack、electron-packager 或 electron-builder,以及一些最常用的插件,如 vue-router、vuex 等等。
其優勢:
基本的項目結構與單一的 package.json 設置開箱即用的 Vue 插件 (axios, vue-electron, vue-router, vuex)預裝開發工具 vue-devtools 和 devtron使用 electron-packager 或 electron-builder 輕鬆打包應用程式appveyor.yml 與 .travis.yml 配置用於 electron-builder 的自動部署使用攜帶熱更新 (Hot Module Replacement) 的 webpack 和 vue-loader在 electron 的 main 主進程修改時重啟進程支持使用 vue-loader 的 HTML/CSS/JS 預處理器ESLint (支持 standard 和 airbnb-base)端到端測試 (使用 Spectron + Mocha)(一) 起步它是 vue-cli 的一個模板,並且包含多個選項,最終的腳手架程序可以自定義。本項目需要使用 node@^7 或更高版本。electron-vue 官方推薦 yarn 作為軟體包管理器,因為它可以更好地處理依賴關係,並可以使用 yarn clean 幫助減少最後構建文件的大小。
安裝 vue-cli 腳手架:
npm install -g vue-cli
vue init simulatedgreg/electron-vue my-project安裝依賴並且運行程序:
cd my-project
yarn # or npm install
yarn run dev # or npm run dev創建項目如下:
圖 7 創建electron-vue項目
Electron-vue-case2 就使用 electron-vue 模板安裝成功了。啟動應用後:
圖 8 electron-vue模板項目
(二) 項目結構項目結構與官方的 vuejs-templates/webpack 設置不同。
單一的 package.json 設置就在不久之前,兩個 package.json 的設置是必需的,但是,感謝 @electron-userland 的努力,electron-packager 和 electron-builder 現在完全支持單一的 package.json 設置。
關於 main 進程在開發過程中,你可能會注意到 src/main/index.dev.js。該文件專門用於開發以及安裝開發工具。原則上,該文件不應該被修改,但是可以被用來擴展你的開發需求。在構建的過程中,webpack 將介入其中並創建一個的捆綁,以 src/main/index.js 作為該捆綁的入口文件。文件樹
組織架構注意: 某些文件或文件夾可能會根據在 vue-cli 腳手架中所選設置的不同而有所不同。
my-project
├─ .electron-vue
│ └─ <build/development>.js files
├─ build
│ └─ icons/
├─ dist
│ ├─ electron/
│ └─ web/
├─ node_modules/
├─ src
│ ├─ main
│ │ ├─ index.dev.js
│ │ └─ index.js
│ ├─ renderer
│ │ ├─ components/
│ │ ├─ router/
│ │ ├─ store/
│ │ ├─ App.vue
│ │ └─ main.js
│ └─ index.ejs
├─ static/
├─ test
│ ├─ e2e
│ │ ├─ specs/
│ │ ├─ index.js
│ │ └─ utils.js
│ ├─ unit
│ │ ├─ specs/
│ │ ├─ index.js
│ │ └─ karma.config.js
│ └─ .eslintrc
├─ .babelrc
├─ .eslintignore
├─ .eslintrc.js
├─ .gitignore
├─ package.json
└─ README.md產品構建
app.asar
├─ dist
│ └─ electron
│ ├─ static/
│ ├─ index.html
│ ├─ main.js
│ └─ renderer.js
├─ node_modules/
└─ package.json可以說,幾乎所有的東西都在最終的產品構建中被刪除。在分發 electron 應用程式時,這幾乎是強制性的,因為你不希望用戶下載擁有龐大文件的臃腫的軟體。
渲染進程公共且非業務的 vue 組件放進 src/renderer/components 裡。
業務的 vue 組件放進 src/renderer/views 裡面。
創建子組件時,一個常用的組織化實踐是將它們放置在一個使用其父組件名稱的新文件夾中。在協調不同的路由時,這一點特別有用。
簡而言之,vue-router 因為創建單頁應用程式 (Single Page Application) 在製作 electron 程序的時候更加實用。如果沒有,那就只能管理一堆 BrowserWindows,然後在其之間傳達信息。
路由被保存在 src/renderer/router/index.js在使用 vue-router 時,不要使用 HTML5 歷史模式。此模式嚴格用於通過 http 協議提供文件,並且不能正常使用 file 協議,但是 electron 在產品構建中使用此協議提供文件。默認的 hash 模式正是我們所需要的。
electron-vue 利用 vuex 的模塊結構創建多個數據存儲,並保存在 src/renderer/store/modules 中。
多模塊數據存儲不用考慮不相干業務數據交叉感染,多餘組織化來說非常好。但是不要擔心導入每一個數據帶來的煩惱,因為 src/renderer/store/modules/index.js 幫我們處理了這些麻煩事!這個簡單的腳本讓 src/renderer/store/index.js 一次性導入我們所有的模塊。
主進程在 Electron 中,運行 package.json 主腳本的過程稱為主進程 (main process)。在主進程中運行的腳本可以通過創建網頁來顯示其圖形化界面。由於 main 進程本質上是一個完整的 node 環境,所以除了以下兩個文件之外,並沒有什麼初始的項目結構。
src/main/index.js
這個文件是你應用程式的主文件,electron 也從這裡啟動。它也被用作 webpack 產品構建的入口文件。所有的 main 進程工作都應該從這裡開始。app/src/main/index.dev.js
這個文件專門用於開發階段,因為它會安裝 electron-debug 和 vue-devtools。一般不需要修改此文件,但它可以用於擴展你開發的需求。
由於 main 進程是使用 webpack 來綁定的,所以使用 __dirname 和 __filename 將不會在產品階段給你提供一個預期的值。在產品階段,main.js 被放在了 dist/electron 文件夾裡面。應根據此點相應地使用 __dirname 和 __filename。
electron-vue 包含三個單獨的、位於 .electron-vue/ 目錄中的 webpack 配置文件。除了可選的使用 web 輸出以外,main 和 renderer 在安裝過程中都是相似的。兩者都使用 babel-preset-env 來針對 node@7 的功能特性、使用 babili、並把所有的模塊都視為 externals。
針對 electron 的 main 進程。這種配置是相當簡單的,但確實包括一些常見的 webpack 做法。.electron-vue/webpack.renderer.config.js針對 electron 的 renderer 進程。此配置用來處理你的 Vue 應用程式,因此它包含 vue-loader 和許多其他可在官方 vuejs-templates/webpack 樣板中找到的配置。
一個關於此配置的重要的事情是,你可以將特定的模塊列入白名單,而不是把它視為 webpack 的 externals。並沒有很多情況需要這個功能,但在某些情況下,對於提供原始的 *.vue 組件的 Vue UI 庫(element-ui等),他們需要被列入白名單,以至於 vue-loader 能夠編譯它們。另一個使用情況是使用 webpack 的 alias,例如設置 vue 來導入完整的 編譯+運行環境 的構建。因此,vue 已經在白名單中了。
.electron-vue/webpack.web.config.js針對為瀏覽器構建你的 renderer 進程的原始碼。如果你需要把代碼發布到網上,此配置則是其強大的起步基礎。electron-vue 不支持更多其他的 Web 輸出。與 Web 輸出相關的 Issues 很可能會被推遲或關閉。
(三) 構建electron應用程式electron-vue 支持使用 electron-packager 和 electron-builder 來構建和分發你的產品階段的程序。兩個構建工具都由了不起的 @electron-userland 社區支持,每個都有詳盡的文檔。在 vue-cli 腳手架過程中,你會被問到你想要使用哪個構建器。electron-packager如果你剛開始製作 electron 應用程式或只需要創建簡單的可執行文件,那麼 electron-packager 就可以滿足你的需求。electron-builder如果你正在尋找完整的安裝程序、自動更新的支持、使用 Travis CI 和 AppVeyor 的 CI 構建、或本機 node 模塊的自動重建,那麼你會需要 electron-builder。具體的更新策略可以閱讀我的另一篇文章《Electron自動更新》。
六、 開發中存在的問題(一) 內存佔用越來越大,運行越來越慢背景當應用放很久後,會越來越卡,打開任務管理器發現,electron 應用佔用內存很大。
分析這一大部分原因是 electron 在犧牲內存佔用的基礎上,將 electron.js 封裝。所以,本身就比較耗內存,Windows 版一上來開 4 個線程,再加上業務代碼用到一些類庫。
解決方式Electron 官網上也有介紹(https://www.electronjs.org/docs/tutorial/performance)。
(二) electron程序顯示了文件瀏覽器背景啟動 electron-vue 項目的時候,會經常出現下圖的情況:
圖 9 文件瀏覽器
為什麼會顯示文件瀏覽器呢?我的應用程式去哪了?
分析出現上述這個錯誤,八成就是 src/renderer 包含錯誤。
如果 src/renderer 中出現錯誤,則會在首次運行時與 ESLint 產生衝突。接著,一個無效的 webpack 的 renderer.js 會被生成出來,它會打斷 HtmlWebpackPlugin 創建 index.html。由於 webpack-dev-server 沒有 index.html 可以提供服務,所以伺服器失敗,程序返回到文件瀏覽器。
解決方式在終端下檢查下爆紅的錯誤,修復錯誤,然後用 CommandOrControl+R 刷新 electron 應用,就可以看到熟悉的應用頁面。
(三) ReferenceError: process is not defined背景當你首次啟動 electron-vue 項目時會遇到 process is not defined。
具體報錯如下圖:
ReferenceError: process is not defined
- index.ejs:11 eval
[.]/[html-webpack-plugin]/lib/loader.js!./src/index.ejs:11:2
- index.ejs:16 module.exports
[.]/[html-webpack-plugin]/lib/loader.js!./src/index.ejs:16:3
- index.js:284
[electron-demo]/[html-webpack-plugin]/index.js:284:18
- runMicrotasks
- task_queues.js:93 processTicksAndRejections
internal/process/task_queues.js:93:5
原因分析暫無
解決方式網上說降低版本這種方式也可以。
我本地的 node 版本是 12.3.1,好像更新到 12 之前就一切正常。看樣子,最新版本的 node 會出現了錯誤。
除此之外,我從這個 issue(https://github.com/SimulatedGREG/electron-vue/issues/871)中得到了解決方法:就是在 webpack.web.config.js 和 webpack.renderer.config.js 中的 HtmlWebpackPlugin 中加入如下代碼即可:
// 模版需要的參數
// https://github.com/jantimon/html-webpack-plugin/blob/master/examples/template-parameters/webpack.config.js
templateParameters(compilation, assets, options) {
return {
// 編譯
compilation: compilation,
webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: options
},
process,
};
},
(四) electron 如何打開開發者工具devtools背景開發應用,如果沒有開發者工具 devtools,那麼開發效率會大大降低,用上開發者工具,無論在調試還是測試方面猶如蛟龍出海,遊刃有餘。
解決方式利用 electron 的 webContents 對象打開及關閉 devtools。下面的例子中,我基於 main.js 中的 createWindow 中的 mainWindow.webContents 進行操作的。
打開 devtools:
mainWindow.webContents.openDevTools()
默認狀態下,開發者工具的位置是上一次工具打開的位置(左邊,右邊,下邊都有可能。取決於上一次的狀態,但不會是分離狀態,也沒有處於頂部的狀態)
應用右側打開 devtools:
mainWindow.webContents.openDevTools({mode:'right'})
底部打開 devtools:
mainWindow.webContents.openDevTools({mode:'bottom'})
左側打開 devtools:
mainWindow.webContents.openDevTools({mode:'left'})
分離狀態打開 devtools:
mainWindow.webContents.openDevTools({mode:'detach'})mainWindow.webContents.openDevTools({mode:'undocked'})
這兩種情況下,devtools 都是不和主界面在一起的,都是分離狀態。但是 undocked 狀態下,這個開發者工具是可以合併到主界面中的。detach 狀態下,是永久分離的。這個就是兩者的區別。
關閉 devtools:
mainWindow.webContents.closeDevTools()
(五) 找不到electron依賴包背景我的應用明明安裝了依賴包,卻無法找到 electron 包時,報這個錯誤:
throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')
原因分析經測試發現,electron 必須要安裝在 devDependencies。
找到該代碼在源碼的位置,見 node_modules\electron\index.js:
var pathFile = path.join(__dirname, 'path.txt')
function getElectronPath () {
if (fs.existsSync(pathFile)) {
var executablePath = fs.readFileSync(pathFile, 'utf-8')
if (process.env.ELECTRON_OVERRIDE_DIST_PATH) {
return path.join(process.env.ELECTRON_OVERRIDE_DIST_PATH, executablePath)
}
return path.join(__dirname, 'dist', executablePath)
} else {
throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')
}
}
module.exports = getElectronPath()如果是安裝在 dependencies 下,就沒有 path.txt。那麼 node 就讀取不到該文件,拋出 electron 安裝失敗的問題。
解決方式重新安裝:
npm install electron --save-dev
(六) electron-vue無法改變vuex狀態背景Electron-vue 中添加 vuex 插件後,卻無法使用。組件間根本無法改變 vuex 數據狀態。
解決方案首先,vuex-electron 的文檔裡寫了:
In case if you enabled createSharedMutations() plugin you need to create an instance of store in the main process. To do it just add this line into your main process (for example src/main.js):import './path/to/your/store'
意思是如果啟用了 createSharedMutations() 的插件,需要在主進程中創建一個 store 的實例,在主進程中(例如 src/main.js)添加 store 實例。
是否啟用了 createSharedMutations 插件,見 src\renderer\store\index.js 文件:
const store = new Vuex.Store({
state,
getters,
actions,
mutations,
plugins: [
createPersistedState(),
createSharedMutations()
],
strict: process.env.NODE_ENV !== 'production'
})開啟多窗口共享後,在主進程加上這一句就行了,見 src\main\index.js 文件:
import '../renderer/store'重啟程序即可。
如果應用中,不需要多窗口共享狀態,就不需要在主進程中添加 stote 實例,將 store 實例中 createSharedMutations 方法去掉。
(七) electron-vue中無法使用Element組件背景應用需要集成第三方 ui 組件,比如 element-ui,但是導入組件後卻無法使用。
解決方案查看這個 issue(https://github.com/SimulatedGREG/electron-vue/issues/361):
Okay, I am able to reproduce this issue now. It seems element-ui falls into that category of modules that need to be white-listed. If you go into .electron-vue/webpack.renderer.config.js, around line 21, you can add element-ui to the whiteListedModules list. After making that change, tooltips will work as expected.
大概的意思是似乎 element-ui 並不屬於這一類的模塊,需要那些列入「白名單」,如果你進入 electron-vue/webpack.renderer.config.js。在大約 21 行左右找到 let whiteListedModules 將 element-ui 添加進去:
let whiteListedModules = ['vue', 'element-ui', 'vuetify']
let rendererConfig = {
devtool: '#cheap-module-eval-source-map',
entry: {
renderer: path.join(__dirname, '../src/renderer/main.js')
},
externals: [
...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
],一個關於此配置的重要的事情是,可以將特定的模塊列入白名單,而不是把它視為 webpack 的 externals。並沒有很多情況需要這個功能,但在某些情況下,對於提供原始的 *.vue 組件的 Vue UI 庫,他們需要被列入白名單,以至於 vue-loader 能夠編譯它們。另一個使用情況是使用 webpack 的 alias,例如設置 vue 來導入完整的編譯+運行環境的構建。因此,vue 已經在白名單中了。
(八) Electron無邊框窗口中自定義窗口快捷鍵背景mainWindow = new BrowserWindow({
height: 720,
minHeight: 720,
minWidth: 1080,
width: 1080,
frame: false
})設置了 frame 為 false 後,electron 就隱藏了工具欄,所有窗口都變成了無邊框窗口。因此,窗口中缺少了必要的最小化、最大化、關閉的窗口快捷鍵。
解決方案首先在 windowOperate.vue 頁面中寫入三個按鈕,並將事件綁定:
// 從渲染器進程到主進程的異步通信。
// 使用它提供的一些方法從渲染進程 (web 頁面) 發送同步或異步的消息到主進程。
const {
ipcRenderer
} = require('electron')
onMinusSm () {
ipcRenderer.send('min')
},
onRectangle () {
ipcRenderer.send('max')
},
onCross () {
ipcRenderer.send('window-close')
}上面三個方法的意思是:給主進程發送同步消息,觸發特定的事件。onMinusSm 方法中 ipcRenderer 發送 min 事件,主進程就可以監聽 min 事件。
在 src/main/index.js 中:
const {
// 從主進程到渲染進程的異步通信。
ipcMain
} = require('electron')
ipcMain.on('window-close', function () {
// close無法關閉程序
// mainWindow.close()
app.exit()
})
ipcMain.on('min', function () {
// 最小化窗口
mainWindow.minimize()
})
ipcMain.on('max', function () {
if (mainWindow.isMaximized()) {
// 將窗口從最小化狀態恢復到以前的狀態。
mainWindow.restore()
} else {
// 最大化窗口。
mainWindow.maximize()
}
})主進程監聽渲染進程的三個事件。如:主進程監聽 min ,觸發最小化窗口的方法。注意:mainWindow.close() 不能關閉程序,需要使用 app.exit() 來關閉。
(九) 監聽窗口狀態,動態改變窗口最大化圖標背景上一個問題解決了窗口最小化、最大化、關閉的窗口快捷鍵。但是,還缺少動態改變窗口最大化的快捷鍵。
解決方案在 windowOperate.vue 中監聽 main-window-max 事件,觸發展示縮小圖標;在 windowOperate.vue 中監聽 main-window-unmax 事件,觸發展示最大化圖標:
mounted () {
// 監聽窗口狀態,動態改變圖片
this.changeWin()
},
changeWin () {
ipcRenderer.on('main-window-max', () => {
this.isRectangle = false
})
ipcRenderer.on('main-window-unmax', () => {
this.isRectangle = true
})
},在 src/main/index.js 讓主進程監聽窗口 maximize 和 unmaximize 向子進程發送事件消息:
function createWindow () {}中插入
// 監聽窗口狀態,向渲染進程發送消息
// 窗口最大化時觸發
mainWindow.on('maximize', function () {
mainWindow.webContents.send('main-window-max')
})
// 當窗口從最大化狀態退出時觸發
mainWindow.on('unmaximize', function () {
mainWindow.webContents.send('main-window-unmax')
})
(十) electron Uncaught TypeError: Cannot read property 'app' of undefined背景electron-vue 這個項目有一些缺陷,啟動項目的時候會報錯:
Uncaught TypeError: Cannot read property 'app' of undefined
at new ElectronStore (E:\eleftron-autoupdate-demo\node_modules\electron-store\index.js:8:55)
at a (E:\eleftron-autoupdate-demo\node_modules\vuex-electron\dist\persisted-state.js:1:1365)
at a (E:\eleftron-autoupdate-demo\node_modules\vuex-electron\dist\persisted-state.js:1:1102)
at E:\eleftron-autoupdate-demo\node_modules\vuex-electron\dist\persisted-state.js:1:3174
at E:\eleftron-autoupdate-demo\node_modules\vuex\dist\vuex.common.js:425:46
at Array.forEach (<anonymous>)
at new Store (E:\eleftron-autoupdate-demo\node_modules\vuex\dist\vuex.common.js:425:11)
at eval (webpack-internal:///./src/renderer/store/index.js:17:64)
at Module../src/renderer/store/index.js (http://localhost:9080/renderer.js:1583:1)
at __webpack_require__ (http://localhost:9080/renderer.js:791:30)
解決方案給主窗口添加 enableRemoteModule 屬性,使用 remote 模塊:
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true
}
})
總結本文介紹了桌面應用程式的歷史、electron 的歷史和 electron-vue 的項目。
Electron 的應用程式結構分為主進程和渲染進程、electron 的 api 和 nodejs 的 api 三大塊。從介紹 electron-vue 的項目結構,到構建應用程式,上手 electron 項目,完成一個 electron 項目(進行中)。
還通過分析開發中存在的一些問題,加深了對 electron 的了解。
願你悄悄打工,然後驚豔所有人!
參考文獻
electron官網
electron-vue官網
最後,希望大家一定要點讚三連。
blog地址
一個學習編程技術的公眾號。每天推送高質量的優秀博文、開源項目、實用工具、面試技巧、編程學習資源等等。目標是做到個人技術與公眾號一起成長。歡迎大家關注,一起進步,走向全棧大佬的修煉之路