文章主要記錄了使用electron
日常開發中所遇到的一些坑以及怎樣填坑,幫助其他開發的小夥伴少踩一些坑。建議關注收藏,以便遇到時候方便查閱!
electron
這個框架我就不過多介紹了,是使用node
和Chromium
架構的一個桌面端框架,如果有了解使用web技術開發桌面端,這個框架多少會聽說過或者正在使用。
下面就記錄一下自己在閱讀文檔的一些疑問以及開發過程中踩過的坑!
electron?
-
Spectron
和Devtron
的作用?Spectron
可以和其他的mocha
等測試框架進行結合,測試electron
Devtron
是Electron DevTools的擴展,可以幫助你檢查,監控和調試應用程序。默認是關閉狀態
-
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
的作用?- 設置 HTTP 的 Content-Security-Policy 頭部字段
- 爲了防止XSS攻擊,安全考慮可以在
content
中設置允許加載的腳本的源
-
electron-forge
的作用?- 是一個快速構建electron的構建工具,裏面包含打包、自動更新等
- 內部書寫
html
和js
爲原生寫法,未集成第三方框架
-
在
electron
中使用iframe
和webview
的的區別?- 官方建議使用
iframe
代替webview
,webview
標籤可以加載一個訪客模式的URL頁面,由於這個標籤是基於Chromium webview
,目前架構變化較快,不夠穩定。但是webview
所提供的功能較多,比如控制訪客能否前進後退等
- 官方建議使用
-
window.open()
使用native和chrome的區別是什麼?- 在
electron
中使用window.open()
打開一個URL使用,會創建一個BrowserWindow
實例,使用的是native
的窗口,可以通過設置nativeWindowOpen: true
來使用chrome
內置的window.open()
,同步打開窗口
- 在
-
electron-packager
和electron-builder
的打包區別?爲什麼推薦使用electron-builder
?electron-packager
和electron-builder
都是用於electron應用打包的模塊, 相比較electron-builder
有更豐富的功能,支持更多的平臺,打包的文件更加輕量,支持非electron
內置的自動更新(內置的自動更新需上傳到git等支持平臺)
-
在
electron
中使用node
原生模塊的時候,electron-rebuild
能夠簡化原生的重編譯?- 由於
electron
內置的node
版本和你電腦本機的版本不一致,則在使用node
原生模塊的時候可能會報錯,Error: The module '/path/to/native/module.node'
- 有3中方式可以解決該問題(下面會詳細介紹兩種使用方法,其他方式參考官方文檔)
- 由於
electron進程之間通訊
-
主進程向渲染進程通訊
- 主進程使用
win.webContents.send
發送消息 - 渲染進程使用
ipcRenderer.on
接收消息
- 主進程使用
-
渲染進程向主進程通信
- 渲染進程使用
ipcRenderer.send
或者ipcRenderer.invoke
發送消息 - 主進程使用
ipcMain.on
或者ipcMain.handle
接收消息
- 渲染進程使用
-
渲染進程向渲染進程通信
- 通知事件
- 通過主進程轉發(Electron 5之前)
ipcRenderer.sendTo
(Electron 5之後)
- 數據共享
- web技術(localStorage、sessionStorage、indexedDB、可嵌入型數據庫等)
- 使用remote(儘量少用,容易影響性能)
由於公司使用的技術棧是vue
,所以需要將electron
和vue
結合起來,當然結合的方式也不麻煩,這裏我們選用了electron-vue
這個開源框架。它已經將兩者結合起來,並且能夠獨立打包成web
,但在使用過程中還是有些疑問和坑的,記錄一下
electron-vue 的坑與填坑?
-
這個框架使用
vue-electron
模塊,它的作用是什麼?- 將 electron API 附加到 Vue 對象,不需要顯式的在vue中引入electron(
require('electron')
) vue-electron
源碼很簡單,將$electron
掛載到vue的原型上
const electron = require('electron') module.exports = { install: function (Vue) { Object.defineProperties(Vue.prototype, { $electron: { get () { return electron }, }, }) }, }
- 將 electron API 附加到 Vue 對象,不需要顯式的在vue中引入electron(
-
這個框架使用
vuex-electron
模塊,它的作用是什麼?- 可以在多個進程中間可以共享狀態,比如在
electron
的主進程和渲染進程中公用一個狀態,並將數據存放在磁盤中
- 可以在多個進程中間可以共享狀態,比如在
-
在主進程中使用
__dirname
與__filename
打包後,並不能得到我們預期的路徑?- 在調用native的dll的時候也遇到這個問題了,打包之前能夠獲得正確路徑,打包後文件會被放在app.asar這個虛擬文件中,路徑就會錯誤
- 解決方法:
electron-vue
中提供了__static
全局變量解決了這個問題,只需要將靜態文件放入到__static
文件夾即可(path.join(__static, '/xxx.dll')
) - 如果只使用
electron
本身這個框架,你需要自己設置開發時路徑和打包後的訪問路徑
-
初始化完成項目後會報一個錯誤:
ReferenceError: process is not defined
- 可以在
index.ejs
中將<% if (!process.browser) { %>
修改成<% if (!require('process').browser) { %>
(如果需要打包成web,請不要使用該方法) - 或者在
webpack.renderer.config.js
修改以下代碼(實際上是配置頁面中使用的process
參數,如果需要打包成web,可以使用該方法,但不要在webpack.web.config.js
中添加該代碼)
new HtmlWebpackPlugin({ filename: 'index.html', template: path.resolve(__dirname, '../src/index.ejs'), + templateParameters(compilation, assets, options) { + return { + compilation: compilation, + webpack: compilation.getStats().toJson(), + webpackConfig: compilation.options, + htmlWebpackPlugin: { + files: assets, + options: options + }, + process, + }; + }, minify: { collapseWhitespace: true, removeAttributeQuotes: true, removeComments: true }, nodeModules: process.env.NODE_ENV !== 'production' ? path.resolve(__dirname, '../node_modules') : false }),
- 可以在
-
構建完項目後
electron
版本默認是2.x, 升級版本後會報錯module is not defined
- 原因新版本
electron
默認不開啓node
集成,在main/index.js
創建窗口的時候加上以下代碼
mainWindow = new BrowserWindow({ height: 563, useContentSize: true, width: 1000, + webPreferences: { + nodeIntegration: true + } })
- 原因新版本
-
報錯
Unable to install vue-devtools
- 原因是
vue-devtools
需要外網下載,科學上網即可
- 原因是
-
在該項目中調用
vuex
的mutations
時,會報錯Please, don't use direct commit's, use dispatch instead of this.
- 這裏提示不能使用同步的方法修改,應該通過調用
actions
去觸發mutations
- 原因是
vuex-electron
裏面加載了多進程之間共享mutations
插件 - 解決方法:1.在
store/index.js
中將createSharedMutations
插件註釋即可 - 2.通過調用
actions
去觸發mutations
,並且在主進程main/index.js
加入該代碼import '../renderer/store'
- 3.查詢
vuex-electron
github,按照文檔設置whitelist
,這裏不贅述
- 這裏提示不能使用同步的方法修改,應該通過調用
-
在
vuex
中存儲的數據,即使刷新和重啓項目,該數據依然存在(這裏功能可以設置用戶長期存儲的數據)vuex-electron
是將數據存儲在磁盤中,默認路徑可以通過app.getPath('userData')
找到存儲路徑下面的一個vuex.json
的文件,安裝不同的electron
應用,文件目錄下面都會生成一個vuex.json
文件vuex-electron
內部使用了electron-store
這個模塊,這個模塊可以set
數據,但是vuex-electron
並沒有將暴露出來- 解決辦法: 如果你想和在web中一樣,刷新或者關閉後,數據重置,直接在下面第9個問題這,將
plugins
加載的模塊刪除即可
-
使用npm run build:web
打包時候,報錯Error: Can't resolve 'fs' in xxxx
- 修改
renderer/store/index.js
,在web中去除vuex-electron
並刪除顯示引入vuex-electron
import Vue from 'vue' import Vuex from 'vuex' - import { createPersistedState, createSharedMutations } from 'vuex-electron' import modules from './modules' Vue.use(Vuex) export default new Vuex.Store({ modules, + plugins: process.env.IS_WEB ? [] : [ + require('vuex-electron').createPersistedState(), + require('vuex-electron').createSharedMutations() ], strict: process.env.NODE_ENV !== 'production' })
- 修改
-
打包報錯
- 這裏最容易報錯的就是
downloading parts=8 size=63 MB url=https://github.com/electron/electron/releases/download/vx.x/electron-vx.x-win32-x64.zip
失敗 - 解決辦法:手動去
https://npm.taobao.org/mirrors/electron
找到對應electron版本下載 - 將下載好文件手動放在
C:\Users\用戶名\AppData\Local\electron\Cache
文件夾中即可(AppData是隱藏文件夾)
- 這裏最容易報錯的就是
electron調用native方法
安裝環境(mac環境無需安裝第1步)
- 管理員權限執行
npm install --global windows-build-tools
安裝python和C++環境
如果無法安裝可以單獨安裝
- python(v2.7 ,3.x不支持)
- visual C++ Build Tools,或者vs2015及以上
npm install -g node-gyp
編譯原生node模塊(electron使用node原生模塊需要編譯)node-gyp list
查看是否缺少node.lib 庫,並按照提示安裝node-gyp install
- 在
src/main/index.js
中啓用渲染層node集成
通過 node-ffi 模塊調用C/C++ dll
-
npm install ffi-napi --save
安裝調用C/C++ dll的模塊- 如果找不到python路徑,設置python環境變量或者
npm config set python你的python路徑
- 如果還不行嘗試使用yarn安裝
- 如果找不到python路徑,設置python環境變量或者
-
npm install electron-rebuild ---save-dev
安裝自動編譯原生node模塊- 如果不安裝的話可以進行手動編譯,方法如下
- 進入
node_module/ffi-napi文件夾
執行node-gyp rebuild --target='當前electron的版本' --arch=x64 --dist-url=https://atom.io/download/atom-shell
編譯node原生模塊 - arch : 計算機的架構(x64或者ia32),如果node環境是32位,那麼這裏就是ia32,如果是node環境是64位,那麼這裏就是x64。
- 如果路徑錯誤,換成國內鏡像路徑 --dist-url=https://npm.taobao.org/mirrors/atom-shell
- 再進入
node_module/ref-napi文件夾
執行node-gyp rebuild --target='當前electron的版本' --arch=x64 --dist-url=https://atom.io/download/atom-shell
編譯node原生模塊
-
如果自動編譯的話執行
npx electron-rebuild
,上步手動編譯則不需要這一步了 -
剩下的就是在主進程裏面調用
native
方法即可,渲染進程調用通過ipcRenderer
和ipcMain
通信調用即可,舉個小例子// 主進程 // 調用示例 const ffi = require('ffi-napi') const CTEST = ffi.Library('dll文件路徑', { // 文件內的方法和參數類型 'Add': ['float', ['float', 'float']], 'Hello': ['string', []], 'StrLength': ['int', ['string']] }) // 同步調用 CTEST.Hello() // 異步調用 CTEST.StrLength.async('1234', (error, res) => { console.log(error, res) })
這裏有兩點需要注意一下
- 如果沒有使用
electron-vue
這個框架(electron-vue
已經處理好靜態文件路徑),需要注意打包後的靜態文件路徑會有些問題,可以在在package.json
文件中配置build後dll的文件存放"extraFiles": [ { "from": "", "to": "" } ]
- 64位的dll不能再32位機器上調用,會報錯
通過 electron-edge-js 模塊調用C# dll
npm install electron-edge-js --save
安裝調用C# dll的模塊- 這裏
electron
的版本不能爲8.x,版本7.x的頁面刷新有bug,目前這個模塊支持情況* Electron 1.6.x - Node.js v7.4.0. * Electron 1.7.x - Node.js v7.9.0. * Electron 1.8.x - Node.js v8.2.1. * Electron 2.x - Node.js v8.9.3. * Electron 3.x - Node.js v10.2.0. * Electron 4.0.4+ - Node.js v10.11.0. * Electron 5.x - Node.js v12.0.0. * Electron 6.x - Node.js v12.4.0. * Electron 7.x - Node.js v12.8.1
// 主進程
// 調用示例
const edge = require('electron-edge-js')
const edgeDll = edge.func({
assemblyFile: 'dll文件路徑',
typeName: "Edge_test.Class1",
methodName: "Concat"
})
edgeDll({ first: 'aaa', second: 'bb' }, function (error, result) {
if (error) throw error
console.log('C# DLL:',result)
})
通過robotjs控制鼠標鍵盤、node-serialport進行串口通訊等
- 使用方法這裏不再贅述,文檔查詢即可。這些模塊也是node原生模塊,因此需要編譯
- 自動編譯同上
npx electron-build
,有時候自動編譯不好使,就需要手動編譯 - 手動編譯
npm rebuild --runtime=electron --disturl=https://atom.io/download/atom-shell --target=<electron版本> --abi=<對應node版本的abi>
或者直接進入模塊文件夾中通過node-gyp編譯:node-gyp rebuild
- abi查詢網址:https://github.com/mapbox/node-pre-gyp/blob/master/lib/util/abi_crosswalk.json
自動更新
由於項目代碼是放在自己服務並且不會進行簽名,所以放棄electron
內置的自動更新。項目使用的打包方式是electron-builder
,最終決定使用electron-updater
模塊進行自動更新,它不依賴任何服務器並且可以從S3, GitHub或者任何其它靜態文件存儲更新,避開了 Electron 內置的更新機制
mac上代碼必須要進行簽名
這裏給個簡版示例
npm install electron-updater --save
安裝自動更新模塊- 主進程中寫入更新代碼
// 每次開啓應用時候會去自動到文件服務器檢查是否有更新,並自動更新重啓 import { autoUpdater } from 'electron-updater' autoUpdater.on('update-downloaded', () => { autoUpdater.quitAndInstall() }) app.on('ready', () => { if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates() })
- 配置打包更新服務器地址(這裏配置從自己文件服務器獲取更新)
"build": { "publish": { "provider": "generic", "url": "http://127.0.0.1:8080" // 服務器地址 } }
- 打包後安裝,如果需要更新修改
package.json
的版本,重新打包,將.exe
latest.yml
.exe.blockmap
3個文件直接扔在文件服務器地址即可。下次用戶打開應用便會自動更新
在electron中起個node服務
- 這裏代碼比較簡單,提供個思路:在主進程中創建個子進程執行node服務(child_process.fork),子進程和主進程通過進程之間進行通信,在主進程拿到數據之後通過
ipcMain
和ipcRenderer
進行主進程和渲染層通信即可。
以上就是個人在閱讀文檔以及項目中遇到的部分問題和坑,記錄分享一下,幫助其他小夥伴少走一些坑,感謝閱讀!
如果文章讓你有收穫,歡迎關注公衆號,不定時推送優質文章!!!