electron開發採坑小記

前言

原文地址: electron開發採坑小記-SegmentFault 思否

前前前前段時間作了個桌面端的項目(這篇文章拖了挺久了),功能大概是這樣的:javascript

  • 項目左右兩欄結構
  • 左側feed流信息展現
  • 右側webview打開一個網站
  • 將左側信息注入右側網站中

需求很簡單,提升運營效率的輔助工具,可是由於一些緣由須要作成一個桌面端。
從前端一會兒跨到PC桌面端開發,聽起來跨度有點大,但在實際的開發中由於有了electron的加持,這一切都變的很是便利,絲毫沒有跨度的痕跡,徹底變成了web開發那一套,讓人不由感嘆js生態的完善,就像有句話說的:html

能用JavaScript書寫的終將會用JavaScript書寫。

實際上我並不是直接採用electron,而是使用了更加懶人的electron-vue。經過這一工具將web開發那一套又轉移到vue開發上,再輔以iview作UI,開發起來一會兒高效了很多。前端

咱們知道electron,可是electron-vue是個什麼東西呢,咱們還須要瞭解一下。這東西的官方介紹是這樣的。vue

An Electron & Vue.js quick start boilerplate with vue-cli scaffolding, common Vue plugins, electron-packager/electron-builder, unit/e2e testing, vue-devtools, and webpack.

從這個介紹大體能夠看出來這是個基於vue-cli的使用vue開發electron應用的腳手架。能夠幫助咱們作很多的vueelectron之間結合的基礎工做,讓咱們的開發更加便捷。那麼咱們就來看看使用electron-vue怎麼作開發。咱們先從基礎的安裝開始。java

安裝

我以爲這個步驟叫安裝並非很嚴謹,由於electron-vue並非一個單獨的npm包,而是vue-cli的一個模板配置。因此使用起來沒有難度,能夠按照官方文檔的說明便可完成,只有兩行命令。webpack

# 安裝 vue-cli 和 腳手架樣板代碼
npm install -g vue-cli
vue init simulatedgreg/electron-vue my-project

如此,咱們便獲得了一個初始化的electron項目,安裝完依賴包就能開發了。初始化過程很簡單,可是須要提示一些vue cli使用過程當中須要注意的問題:git

  • Vue CLI的包名稱由vue-cli改爲了@vue/cli,致使最新版的vue cli使用vue init命令會報錯,而electron-vue的安裝文檔比較老舊,須要用vue init這個命令,咱們能夠用一個命令來作橋接github

    npm install -g @vue/cli-init
  • windowsGit bash上初始化選擇插件時候沒法用上下鍵交互的問題能夠換用powershell

開發

項目初始化、安裝依賴後咱們就能夠開發了。這時候能夠跑一下項目,他會有個默認的界面。web

npm run dev

clipboard.png

對應的目錄是這樣的(目錄會根據安裝插件的不一樣而存在差別)。ajax

├── appveyor.yml
├── build
│   └── icons
│       ├── 256x256.png
│       ├── icon.icns
│       └── icon.ico
├── dist
│   ├── electron
│   └── web
├── package.json
├── README.md
├── src
│   ├── index.ejs
│   ├── main
│   │   ├── index.dev.js
│   │   └── index.js
│   └── renderer
│       ├── App.vue
│       ├── assets
│       ├── components
│       ├── main.js
│       ├── router
│       └── store
└── static

大體的套路跟vue開發同樣,不一樣的是src下有個兩個目錄:mainrenderer。咱們大體能夠理解爲:

  • main目錄存放與electron相關的內容,是主進程
  • renderer目錄存放與咱們頁面相關的內容,是渲染進程

這個經過這個demo頁面能夠驗證。搞清楚這個後開發就很簡單了,不須要解釋太多。更多的介紹能夠看文檔

調試

開發過程當中調試是不可避免的,根據個人經驗這裏主要介紹兩種調試:

普通頁面調試

這種調試就像咱們平時在vue開發web應用中使用devtool同樣。這個在初始化的代碼中已經寫好了,在dev模式下默認是開啓的。
/src/main/index.dev.js能夠找到這段代碼,咱們不用太關心。

require('electron-debug')({ showDevTools: true })

內嵌webview頁面調試

這個是由於我這個項目須要才涉及到的,須要本身代碼實現。 在個人邏輯中大體這樣處理的:

<webview ref="webview" src="xxx" ></webview>
this.$refs.webview.addEventListener('dom-ready', res => {
    if (process.env.NODE_ENV === 'development') {
      this.$refs.webview.openDevTools();
    }
});

打包

開發完以後咱們須要把代碼打包成一個exe的可執行文件,這個操做也很簡單,已經在package.json上被安排好了,咱們直接用就好了。

npm run build

而後,build目錄下有會有你想要的exe文件了。拷走安裝就能夠用了。
若是你須要自定義一些圖標啥的能夠改package.jsonbuild的相關配置,操做簡單,不用多提。

一些須要關注的核心點

由於此次項目功能很簡單,涉及到的點不多,因此這裏只介紹項目用到的一些核心點,沒用過的沒有發言權,就不提了。

webview代碼注入

electron提供了webview標籤可以讓咱們嵌入本身的網頁。想要往裏面注入代碼可使用webview上提供的executeJavaScript方法。具體的參數和使用方法這些都是文檔層面的內容,不用多提,須要注意的是這個方法的第三個參數是個callback,文檔上是這樣描述的

callback Function (可選) - 在腳本被執行後被調用。

文檔只是描述了這個回調被觸發的時機,而沒有描述回調觸發時候傳的參數。
關於觸發時機和參數,更具體的描述是這樣的。

  • 若是你注入的是同步代碼,像querySelector這樣的,callback會在注入代碼執行完以後觸發,而且把你最後querySelector得到的值傳入callback
  • 若是你注入的是異步代碼,像ajax請求這樣的,callback是不會等這個請求有了響應才執行的,而是執行完ajax請求就執行,固然,這種狀況下callback是沒有傳參的。咱們後面會介紹怎麼拿到注入ajax的返回值

主進程和渲染進程通訊

主進程和渲染進程通訊是electron中很重要的概念,介紹這塊內容的文章也有不少,因此這裏就不過多贅述,簡單介紹一下大概狀況。
通訊主要靠兩個工具完成:ipcRendereripcMain

在主進程裏這樣使用ipcMain

const { ipcMain } = require('electron');

ipcMain.on('exit_app', res => {
  app.exit();
})

在渲染進程中這樣使用ipcRenderer

const { ipcRenderer } = require('electron');

ipcRenderer.send('exit_app', true);

須要注意的是:消息只能是由渲染進程主動發起,主進程被動監聽,而後主進程做響應,不存在由主進程主動向渲染進程通訊的方式。代碼實現以下:

// 在主進程中
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
  console.log(arg) // prints "ping"
  event.reply('asynchronous-reply', 'pong')
})

ipcMain.on('synchronous-message', (event, arg) => {
  console.log(arg) // prints "ping"
  event.returnValue = 'pong'
})
//在渲染器進程 (網頁) 中
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"

ipcRenderer.on('asynchronous-reply', (event, arg) => {
  console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')

electron窗體關閉事件攔截

窗體關閉事件攔截利用的是BrowserWindowclose事件來作處理的。須要注意的是BrowserWindow實例還有個closed事件,區別在於:

  • close在窗口要關閉的時候觸發
  • closed窗口已經關閉時觸發

這個兩個事件一個字母的差距,可是觸發時機卻大有差距,千萬分清楚,當時我就是沒看清,浪費了很多時間。

窗體關閉事件攔截的代碼實現大體以下:

mainWindow = new BrowserWindow({
    height: 563,
    useContentSize: true,
    width: 1000
  })

  mainWindow.on('close', event => {
      return event.preventDefault();
  })

遇到的一些問題

webviewbeforeunload彈窗問題

若是內嵌的webview中對beforeunload事件有監聽,並有彈窗操做,那麼這個事件觸發的時候,electron是沒有彈窗提示的。用戶是沒有感知的,這個問題尚未解決辦法,是個坑。

clipboard.png
clipboard.png
(electronwebview是不會顯示這些彈窗)

監聽webview中注入請求的響應

個人項目裏有一個需求是要向webview中注入ajax請求,而且要拿到請求的響應結果。可是electron中比較早的版本中只有對發起的請求有監聽,並不支持監聽請求的響應,因此要拿到請求的響應結果就是個問題。
可是也不是沒辦法解決。我這裏是藉助webviewconsole-message事件來處理。監聽webviewconsole-message事件,當拿到請求的響應的時候把響應的內容按照約定的格式打出來,這樣就間接的實現了對注入請求的監聽。

electron低版本webview中不能跳轉

這是一個在electron低版本中存在的問題,在一些新的版本中已經解決了。
這個問題的具體表現就是:
內嵌webview的頁面中若是發生302301跳轉的話頁面會卡在發生跳轉的請求那裏再也不向下進行,查看webviewnetwork能夠看到這個問題。
這個問題的解決很簡單,升級到最新的electron就能解決這個問題。我這裏升級到4.1.4解決了這個問題。
由於electron-vue長時間沒更新,裏面使用的electron版本仍是2.0.4,比較老舊,因此你要是遇到一些奇奇怪怪的問題不妨升級electron來嘗試解決。

ctrl+c以後仍有electron進程駐守

調試時候發現的這個問題,雖然是在electron中開發,可是由於仍是vue那一套,因此咱們改完代碼就不用重啓就能在electron中看到效果,就是熱更新嘛,可是有時候我仍是會手動的ctrl + c,這麼手動的次數多了以後我發現個人電腦會變的很是卡。排查後我發現ctrl + c並不能徹底關閉整個electron應用,每次這麼作都會遺留2個electron進程保持活躍,屢次以後會遺留不少electron進程,電腦就會變的很是卡,每次都須要手動殺一下進程。這個問題在把模板中自帶的

app.on('window-all-closed', event => {
  app.quit();
});

替換爲

app.on('window-all-closed', event => {
  app.exit();
});

以後解決(在寫文章的時候發現這個問題並沒獲得復現,不知道是否是新的版本修復了這個問題),其中差別感興趣的能夠深刻研究一下

沒法捕獲信號量的問題

解決上面問題的時候發現electron沒法捕獲來自命令行的信號量。若是有這個需求的話仍是要留意的。

一些不錯的博客

在開發過程當中也是一邊學一邊作,發現了一些不錯的文章和博客,從裏面也得到了很多的幫助,貼出來分享一下。

相關文章
相關標籤/搜索