一文搞懂Electron?+?Vue的開發(fā)

electron-vue不要再用了画髓,版本太老作者也不更新宦赠,而且electron11.0才開始支持Apple Silicon(m1)機型。

近期我自己也在開發(fā)一些electron + vue的跨平臺項目,本文主要記錄一下新起一個項目的時候需要安裝哪些工具與步驟

安裝系統(tǒng)全局組件Vue CLI用于創(chuàng)建vue項目

npm install -g @vue/cli

創(chuàng)建標準化Vue項目

vue create vueapp

然后根據Vue CLI提示選擇自己的常用工具并建立一個vue網站項目
具體步驟


添加electron插件

首先進入剛才建好的vueapp文件夾樟遣,安裝以下插件

vue add electron-builder

然后選擇最新的版本雕憔,等待安裝完成即可姿骏。

這里可能會非常慢,最終導致超時失敗斤彼。這是因為需要根據系統(tǒng)來下載electron的基礎庫分瘦,由于網絡原因,建議此處使用設置npm proxy來進行下載琉苇。不建議使用其他鏡像源下載嘲玫,可能會導致最終打包失敗,遇到過好幾次問題了并扇。

npm config set proxy http://127.0.0.1:58592
npm config set https-proxy http://127.0.0.1:58592

還有一種方式是把electron的源換成淘寶的:

npm config set registry https://registry.npmmirror.com
npm config set ELECTRON_MIRROR https://npmmirror.com/mirrors/electron/

啟動項目查看是否正常

此時項目src文件夾下就多了一個background.js去团,這里就是electron主進程相關代碼,負責和我們的vue頁面(渲染進程)進行交互穷蛹。
執(zhí)行以下代碼啟動項目

npm run electron:serve

此時應當能彈出一個應用程序界面土陪,并且還有我們熟悉的Vue:

應用啟動成功

可喜可賀!你可以正常開發(fā)了俩莽,添加npm插件就正常使用npm install xxx即可旺坠。

如果此時出現electron安裝錯誤請重新安裝的提示,那么就按以下步驟操作issue

  1. 在node_modules\electron文件夾下新建一個path.txt
  2. txt中寫入:electron.exe
  3. 前往https://npmmirror.com/mirrors/electron/根據自己的版本下載對應平臺的zip包
  4. 將zip包解壓到node_modules\electron\dist 這樣即可修復安裝錯誤問題扮超。

進行一些必要配置

  1. electron升級
    由于剛才安裝的electron版本已經過低取刃,我們需要先進行升級蹋肮。
    在命令行中卸載當前electron:
npm uninstall electron

然后安裝最新的electron和remote模塊:

npm install -S electron
npm install -S @electron/remote

【可選步驟】由于vue-cli-plugin-electron-builder已經長年不更新了,在electron20+璧疗、mac系統(tǒng)上具有大量兼容性bug坯辩,因此需要升級到3.0.1(這個庫可能對element兼容不太好,會丟字體):
@matthijsburgh/vue-cli-plugin-electron-builder

npm install -D @matthijsburgh/vue-cli-plugin-electron-builder

另外需要注意崩侠,background.js中引用createProtocol也要更改為這個包:

import { createProtocol } from '@matthijsburgh/vue-cli-plugin-electron-builder/lib'

然后進行electron配置漆魔,background.js:

//background.js
//文件頭部,引用增加ipcMain用于通信
import { app, protocol, BrowserWindow, ipcMain } from 'electron'
import { createProtocol } from '@matthijsburgh/vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
//窗口啟動增加選項
const win = new BrowserWindow({
    width: 800, //窗口默認寬度
    height: 600, //窗口默認高度
    useContentSize: false, 
    frame: true, //取消window自帶的關閉最小化等
    resizable: false, //禁止改變主窗口尺寸
    transparent: false, //透明
    hasShadow: true, //窗口陰影
    maximizable: true,  //是否允許最大化
    webPreferences: {
      enableRemoteModule:true, //在渲染進程啟用remote模塊
      nodeIntegration: true, //在渲染進程啟用Node.js
      contextIsolation:false,
      webSecurity: false,
      backgroundThrottling: false, //程序在最小化時渲染進程不凍結
    }
  })
  //由于渲染進程中electron.remote已廢棄却音,需要手動引入改抡,并在每一個browserwindow中啟用remote
  require('@electron/remote/main').initialize()
  require("@electron/remote/main").enable(win.webContents);
  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
  }
  1. Vue相關配置,這樣就可以在使用electron的API系瓢,main.js:
//main.js
const electron = window.require('electron') //引用electron
const fs = window.require('fs') //引用Node模塊fs
const remote = window.require('@electron/remote') //引用remote模塊用于通信阿纤、打開文件彈框等
Vue.prototype.$electron = electron
Vue.prototype.$fs = fs
Vue.prototype.$remote = remote

具體頁面中,xxx.vue:

//在頁面中使用相關API
this.$electron.ipcRenderer.sendSync('testMsg',data); //與主進程通信
this.$remote.getCurrentWindow().minimize(); //最小化窗口
this.$fs.existsSync("C:/test.js"); //調用nodejs方法查找文件是否存在

3.添加必要文件

  • gitignore忽略輸出文件夾build夷陋、dist_electron

// .gitignore
/build
/dist_electron

  • 新建vue.config.js欠拾,添加打包相關配置項,具體配置的作用在electron-builder官網有詳細說明骗绕,下文請自行替換appid藐窄、name之類的字段
module.exports = {
  pluginOptions: {
    electronBuilder: {
      "customFileProtocol": "./", //增加此項讓css中相對引用的文件能正常訪問,否則一些css庫中的字體會無法顯示
      "builderOptions": {
        "extraResources": [
          "./extraResources/**", //這里指定外部資源文件夾酬土,你可以把一些外部程序放在./extraResources中荆忍,比如ffmpeg等,打包時electron將直接原樣拷貝
          "./node_modules/@electron/remote/**"诺凡,//必須添加這一行否則remote會引用不到
        ],
        "productName": "your app name",
        "appId": "your.app.appId",
        "copyright":"Copyright ? your name 2021",// 版權信息
        "directories": {
          "output": "./build" //輸出文件夾
        },
        "afterSign": "./notarize.js", //簽名文件
        "dmg": { //輸出mac的dmg時圖標位置
          "contents": [
            {
              "x": 410,
              "y": 150,
              "type": "link",
              "path": "/Applications"
            },
            {
              "x": 130,
              "y": 150,
              "type": "file"
            }
          ]
        },
        "mac": {
          "icon": "./icons/icon512.icns",//mac圖標东揣,必須至少包含512*512尺寸的圖標
          "target":[{
            "target": "dmg", //設置輸出dmg安裝包
            "arch": ["arm64", "x64"], //arm64是apple silicon機器專用的包;x64是intel版的包腹泌,兩種電腦都能用嘶卧,不過x64運行啟動會慢一點;這里你可以填universal凉袱,這樣會生成一個arm64+x64打出來然后裝一起的一個包(體積也是兩種應用之和)芥吟,運行時會自動選擇版本
          }],
          "identity": "your name",
          "entitlements": "./entitlements.mac.plist", //簽名必須
          "entitlementsInherit": "./entitlements.mac.inherit.plist",//簽名必須
          "entitlementsLoginHelper": "./entitlements.mas.loginhelper.plist"专甩,//如果需要mac的mas版打包钟鸵,則需要此項
        },
        "win": {
          "icon": "./icons/icon256.ico",//win打包圖標
          "target": [{
            "target": "nsis",// 利用 nsis 制作安裝程序
            "arch": [
              "x64",//64 位
            ]
          }]
        },
        "nsis": {
          "oneClick": false, // 是否一鍵安裝
          "allowElevation": true, // 允許請求提升. 如果為 false, 則用戶必須使用提升的權限重新啟動安裝程序.
          "allowToChangeInstallationDirectory": true, // 允許修改安裝目錄
          "installerIcon": "./icons/icon256.ico",// 安裝圖標
          "uninstallerIcon": "./icons/icon256.ico",// 卸載圖標
          "installerHeaderIcon": "./icons/icon256.ico", // 安裝時頭部圖標
          "createDesktopShortcut": true, // 創(chuàng)建桌面圖標
          "createStartMenuShortcut": true,// 創(chuàng)建開始菜單圖標
          "shortcutName": "DNG自動轉換工具", // 圖標名稱
          "perMachine": true
        },
      }
    }
  },
  configureWebpack: config => {
    return {}//webpack相關配置
  }
}
  • 項目下新建icons文件夾用于存放圖標,內部放置至少2個圖標,分別為mac的icon512.icns和用于win的icon256.ico,打包時要用到漫玄。從普通圖片創(chuàng)建圖標可以使用IconWorkshop荆萤。
icons文件夾
  • 項目下新建extraResources文件夾,里面存放需要使用的外部程序澡罚,比如ffmpeg等顶瞒。electron在打包時將不會編碼該文件夾下的文件血筑,直接原樣拷貝害幅,安裝時也會直接放置于安裝目錄中消恍。
  1. 接下來,如果你是mac以现,需要打包成dmg安裝包狠怨,則需要安裝這個@electron/notarize (electron-notarize已廢棄)
//安裝公證組件
npm install @electron/notarize --save-dev

項目下新建.env文件,這里存放在mac開發(fā)者中心成為開發(fā)者時你的appleID及蘋果提供相關密碼邑遏,注意這個密碼不要寫你的appleID密碼佣赖,可以在蘋果賬號中心中手動添加一個app專用密碼,填寫在這里记盒。teamId是你apple開發(fā)者賬號下找到茵汰。也可以使用鑰匙串,具體參見此文mac下electron簽名及公證教程

//.env
appleId=youraccount@test.com
appleIdPassword=xxxx-xxxx-xxxx-xxxx
teamId=xxxxx

項目下新建entitlements.mac.plist文件孽鸡,固定寫死,直接拷(編譯arm64的應用時栏豺,務必添加com.apple.security.cs.allow-jit權限彬碱,否則程序很可能崩潰)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
        <true/>
        <key>com.apple.security.cs.allow-jit</key>
        <true/>
    </dict>
</plist>

項目下新建notarize.js文件,固定寫死奥洼,直接拷

require('dotenv').config()
const {notarize} = require('@electron/notarize')
 
exports.default = async function packageTask (context) {
  const appName = context.packager.appInfo.productFilename
  const {electronPlatformName, appOutDir} = context
  if (electronPlatformName !== 'darwin') {
    return
  }
 
  let appPath = `${appOutDir}/${appName}.app`
  let {appleId, appleIdPassword, teamId} = process.env
  console.log("notarize")
  console.dir({appleId, appleIdPassword, teamId})
  return await notarize({
    appPath,
    appleId,
    appleIdPassword,
    teamId,
  })
}

@electron/notarize使用的是notarytool巷疼,舊版altool的公證將會在2023年11月停止訪問。新版工具將會訪問aws的地址灵奖,很可能連不上嚼沿,需要自行準備魔法


打包你的App

按上面的操作一步步來的話應該已經可以打包成exe或者dmg了

npm run electron:build

打包這一步也會非常慢,同樣是墻的問題瓷患,請不要使用cnpm骡尽,而是用本文一開始的set proxy方式

npm config set proxy http://127.0.0.1:58592
npm config set https-proxy http://127.0.0.1:58592

如果還是出現這種網絡原因導致的報錯: Get "https://github.com/electron-userland/electron-builder-binaries/releases/download/winCodeSign.7z" A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
可以手動進入提示上的網址將文件下載下來并解壓

  • nsis和nsis-rescources放置到 C:\Users\username\AppData\Local\electron-builder\Cache\nsis中;
  • winSodeSign放置到 C:\Users\username\AppData\Local\electron-builder\Cache\winSodeSign中
  • electron-vx.x.x-win32-x64.zip放置到 C:\Users\username\AppData\Local\electron\Cache中

開發(fā)相關坑點解讀 Electron 常見問題

1. 無法使用require引用

當你在項目中使用require引用一些模塊(比如jQuery)擅编,會導致Uncaught TypeError: $ is not a function

這個問題是的直接原因是require無法引用攀细,根本原因node中的require覆蓋了webpack的require,這就導致了打包失敗

  • 解決方案一:
    在渲染進程中禁用Node.js爱态。在主進程background.js中谭贪,將nodeIntegration選項設置為false
//background.js
const win = new BrowserWindow(
  webPreferences: {
    nodeIntegration: false //該選項在渲染進程中禁用Node.js
  }
})

這樣就可以正常使用require了。副作用是無法訪問一些底層的參數比如__dirname锦担,當引用的組件使用這些參數時會報錯俭识。

  • 解決方案二:
    當不可避免的想要使用Node.js時,比如想引用fs來讀取某個文件洞渔,那么在主進程background.js中套媚,將nodeIntegration選項設置為true
//background.js
const win = new BrowserWindow(
  webPreferences: {
    nodeIntegration: true //該選項在渲染進程中啟用Node.js
  }
})

在require組件時缚态,必須在main.js中引用,并且必須使用window.require

//main.js
const electron = window.require('electron')
Vue.prototype.$electron = electron

這樣就可以在頁面中通過this.$electron訪問到electron的API了

  • 解決方案三
    將require重命名凑阶。在index.html中添加以下代碼猿规,放置在所有script標簽之前
<!-- index.html -->
<script>
  window.nodeRequire = require;
  delete window.require;
  delete window.exports;
  delete window.module;
</script>

然后就可以在main.js中使用nodeRequire 引用模塊了(不能在頁面中使用)

//main.js
const fs = nodeRequire('fs')
Vue.prototype.$fs = fs
//App.vue
this.$fs.existsSync("C:/test.js")

2. 在mac下,啟動項目時會報一個fsevents的錯誤:

ERROR  Failed to compile with 1 errors                                         
error  in ./node_modules/fsevents/fsevents.node
Module parse failed: Unexpected character '?' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process his file. See https://webpack.js.org/concepts#loaders

(Source code omitted for this binary file)
@ ./node_modules/fsevents/fsevents.js 13:15-41
@ ./node_modules/chokidar/lib/fsevents-handler.js
@ ./node_modules/chokidar/index.js
@ ./src/background.js
@ multi ./src/background.j

fsevents是mac系統(tǒng)的一個必須要有的二進制模塊宙橱,如果你想開發(fā)跨平臺程序姨俩,一定繞不開他。
這個報錯的原因是fsevents.js中使用了require师郑,導致項目無法啟動环葵。
需要點擊./node_modules/fsevents/fsevents.js 13:15,找到該文件13行代碼宝冕,按照下文修改即可

// ./node_modules/fsevents/fsevents.js
const Native = require("./fsevents.node")
//更改為
const Native = window.require("./fsevents.node")

3. 在mac下张遭,electron-builder打包項目時會報一個ENOENT的錯誤:

spawn /usr/bin/python ENOENT

產生原因是macos ventura中移除了python2,因此electron-builder在打包dmg時將無法讀取這個地址地梨。
解決方案:卸載默認的vue-cli-plugin-electron-builder2.0.0菊卷,安裝 @matthijsburgh/vue-cli-plugin-electron-builder 即可。


我們也采用手動安裝的方式解決宝剖。
打開終端洁闰,使用conda創(chuàng)建一個python2.7的環(huán)境

conda create -c 'https://repo.continuum.io/pkgs/free/osx-64' -n py2 python=2.7

這里沒有直接conda create -ns是因為新版anaconda已無法搜索到py2.7,因此需要手動指定channel万细,否則會提示“ackagesNotFoundError: The following packages are not available from current channels python=2.7”

創(chuàng)建完成后進入anaconda圖形界面扑眉,找到py27的環(huán)境,打開terminal赖钞,運行以下代碼找到你的python2.7執(zhí)行文件的地址

which python
# /Users/mordom/anaconda3/envs/py2/bin/python

記下這個地址腰素,稍后將會用到

回到我們的electron項目的地址,定位到以下兩個文件
/node_modules/vue-cli-plugin-electron-builder/node_modules/dmg-builder/out/dmg.js
/node_modules/dmg-builder/out/dmg.js
前者找到261行:

    await builder_util_1.exec(process.env.PYTHON_PATH || "/usr/bin/python", [path.join(dmgUtil_1.getDmgVendorPath(), "dmgbuild/core.py")], {
        cwd: dmgUtil_1.getDmgVendorPath(),
        env,
    });

將這里的"/usr/bin/python"替換為我們剛才記錄下的地址"/Users/mordom/anaconda3/envs/py2/bin/python"雪营,這樣在打包時electron-builder將調用我們手動下載的python2.7了弓千。
后者同樣搜索“/usr/bin/python”,并替換為我們的地址即可卓缰。
至此問題解決计呈。


4.打包后在部分windows系統(tǒng)上出現白屏閃退問題

該問題由chromium的沙盒機制造成,詳細見進程沙盒化
解決方案

//background.js
import { app } from 'electron'
app.commandLine.appendSwitch('--no-sandbox'); //該行應在app.on('ready')前面執(zhí)行
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末征唬,一起剝皮案震驚了整個濱河市捌显,隨后出現的幾起案子,更是在濱河造成了極大的恐慌总寒,老刑警劉巖扶歪,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡善镰,警方通過查閱死者的電腦和手機妹萨,發(fā)現死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炫欺,“玉大人乎完,你說我怎么就攤上這事∑仿澹” “怎么了树姨?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長桥状。 經常有香客問我帽揪,道長,這世上最難降的妖魔是什么辅斟? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任转晰,我火速辦了婚禮,結果婚禮上士飒,老公的妹妹穿的比我還像新娘查邢。我一直安慰自己,他們只是感情好酵幕,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布侠坎。 她就那樣靜靜地躺著,像睡著了一般裙盾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上他嫡,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天番官,我揣著相機與錄音,去河邊找鬼钢属。 笑死徘熔,一個胖子當著我的面吹牛,可吹牛的內容都是我干的淆党。 我是一名探鬼主播酷师,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼染乌!你這毒婦竟也來了山孔?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤荷憋,失蹤者是張志新(化名)和其女友劉穎台颠,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體勒庄,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡串前,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年瘫里,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荡碾。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡谨读,死狀恐怖,靈堂內的尸體忽然破棺而出坛吁,到底是詐尸還是另有隱情劳殖,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布阶冈,位于F島的核電站闷尿,受9級特大地震影響,放射性物質發(fā)生泄漏女坑。R本人自食惡果不足惜填具,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望匆骗。 院中可真熱鬧劳景,春花似錦、人聲如沸碉就。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓮钥。三九已至筋量,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碉熄,已是汗流浹背桨武。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锈津,地道東北人呀酸。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像琼梆,于是被迫代替她去往敵國和親性誉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容