iT邦幫忙

3

Electron - 今晚我想來點 Electron 加 Vue.js

Ares 2020-11-25 15:45:3211033 瀏覽

前幾篇介紹了 Electron 如何操作,既然 Electron 是將網頁包起來,那當然可以使用 Vue.js 來做啊!今天就讓我們一起看看該怎麼實作

Electron - 用網頁技術做一個桌面應用程式吧!
Electron - 常用 API 解析

建立專案

首先我們先使用 Vue CLI 建立一個全新的專案,要使用的套件就選自己需要的

$ npm install -g @vue/cli
$ vue create vue-electron
$ cd vue-electron

再來我們會使用 vue-cli-plugin-electron-builder 這個套件來安裝 Electron,安裝時他會問你安裝版本,沒意外就選最新版本,另外官方這邊推薦使用 yarn 作為套件管理工具

$ vue add electron-builder

這樣就安裝完成了,可以發現 package.json 多了一些指令,而且 src 資料夾內多了一個 background.js,我們來看看多了什麼東西吧!

// package.json

{
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    // 編譯 Electron
    "electron:build": "vue-cli-service electron:build",
    // Electron 開發模式
    "electron:serve": "vue-cli-service electron:serve",
    // 下載 app 依賴,我們用不到
    "postinstall": "electron-builder install-app-deps",
    "postuninstall": "electron-builder install-app-deps"
  },
  // Electron 的進入點
  "main": "background.js"
}
// src/background.js

'use strict'

import { app, protocol, BrowserWindow } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'

// 自定義協議
protocol.registerSchemesAsPrivileged([
  { scheme: 'app', privileges: { secure: true, standard: true } }
])

async function createWindow () {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION
    }
  })

  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // 開發者模式載入設定
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    // 正式載入設定
    createProtocol('app')
    win.loadURL('app://./index.html')
  }
}

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) createWindow()
})

app.on('ready', async () => {
  // 開發者模式時載入 Vue 的開發工具
  if (isDevelopment && !process.env.IS_TEST) {
    try {
      await installExtension(VUEJS_DEVTOOLS)
    } catch (e) {
      console.error('Vue Devtools failed to install:', e.toString())
    }
  }
  createWindow()
})

// 開發者模式對應父層事件退出應用程式
if (isDevelopment) {
  if (process.platform === 'win32') {
    process.on('message', (data) => {
      if (data === 'graceful-exit') {
        app.quit()
      }
    })
  } else {
    process.on('SIGTERM', () => {
      app.quit()
    })
  }
}

這邊的 background.js 就是之前的 main.js,也就是 Electron 的進入點

Vue.js 設定

安裝完成之後還有一些相關的設定需要做,以下一起來看吧~

Router

我們用 router 通常會使用 history 模式,但是在正式環境會導致黑屏,所以官方這邊提供了解決方法如下

// src/router/index.js

const router = new VueRouter({
  mode: process.env.IS_ELECTRON ? 'hash' : 'history',
})

preload

建立專案後發現預設沒有 preload.js,所以這邊我們要自己設定,官方教學在這

// vue.config.js

module.exports = {
  pluginOptions: {
    electronBuilder: {
      preload: 'src/preload.js'
      // preload: { preload: 'src/preload.js', preload2: 'src/preload2.js' }
    }
  }
}
// src/background.js

import path from 'path'

const win = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
    preload: path.join(__dirname, 'preload.js')
  }
})

最後在 src 資料夾下創建 preload.js 就完成囉!

icon - 視窗工具列

官方有提到,如果要替換應用程式的 icon,可先將 icon 放到 public 內,然後加入以下設定

// src/background.js

/* global __static */
import path from 'path'

const win = new BrowserWindow({
  width: 800,
  height: 600,
  icon: path.join(__static, 'icon.png'), // 開啟後工具列的 icon
  webPreferences: {
    nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
    preload: path.join(__dirname, 'preload.js')
  }
})

icon - 安裝檔

如果想修改安裝檔的圖片可以使用 electron-icon-builder

$ yarn add --dev electron-icon-builder
// package.json

{
  "scripts": {
    // --input=圖片位址
    "electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten"
  }
}
$ yarn electron:generate-icons

執行後就會看到 build/icons 內有各種類型的 icon,之後執行 yarn electron:build 就會看到安裝檔的 icon 換成我們自己的圖示囉!另外也可以直接用下介紹的 vue.config.js 方式做設定

編譯設定

跟編譯相關的幾乎都可以在 vue.config.js 內設定,特別提一下,icon 的部分建議放在 public 資料夾內,並且使用 256*256 以上大小的 ico 檔案,否則會跳錯誤唷

// vue.config.js

module.exports = {
  pluginOptions: {
    electronBuilder: {
      mainProcessFile: 'src/myBackgroundFile.js', // 主進程進入點
      rendererProcessFile: 'src/myMainRenderFile.js', // 渲染進程進入點
      outputDir: 'electron-builder-output-dir', // 編譯資料夾
      preload: 'src/preload.js', // preload 檔案位置
      builderOptions: {
        asar: false, // 是否使用 asar 壓縮檔案
        appId: 'your.id', // 認證的 appId
        productName: 'productName', // 專案名稱
        artifactName: '${name}.${ext}', // 檔案名稱樣板,有 ESLint 記得關掉
        copyright: 'Copyright©ares', // 版權
        // Windows 相關設定
        win: {
          legalTrademarks: 'legalTrademarks', // 商標
          icon: 'public/icon.ico', // 安裝檔圖示
          target: [{
            target: 'nsis', // 檔案類型
            arch: ['x64', 'ia32'] // 檔案位元,越多類型檔案越大
          }]
        },
        // DMG 相關設定
        dmg: {
          icon: 'public/icon.icns' // 安裝檔圖示
        },
        // Linux 相關設定
        linux: {
          icon: 'public/icon.png' // 安裝檔圖示
        },
        // macOS 相關設定
        mac: {
          icon: 'public/icon.icns' // 安裝檔圖示
        },
        nsis: {
          oneClick: false, // 是否一鍵安裝
          perMachine: true, // 是否為每一台機器安裝
          installerIcon: 'public/icon.ico', // 安裝圖示
          uninstallerIcon: 'public/icon.ico', // 卸載圖示
          installerHeaderIcon: 'public/icon.ico', // 安裝頂部圖示
          allowToChangeInstallationDirectory: true, // 是否可更改安裝目錄
          createDesktopShortcut: true, // 是否建立桌面捷徑
          createStartMenuShortcut: true // 是否建立開始捷徑
        }
      }
    }
  }
}

詳細可參考以下文件
Vue CLI Plugin Electron Builder
electron-builder
檔案名稱樣板

修改安裝路徑

當設定 allowToChangeInstallationDirectorytrue 時,預設目錄為 C:\Program Files\專案名,如果想要修該預設路徑則須在根目錄新增 installer.nsh,並於 vue.config.js 加上設定

// installer.nsh

!macro preInit
    SetRegView 64
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\path"
    WriteRegExpandStr HkCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\path"
    SetRegView 32
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\path"
    WriteRegExpandStr HkCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\path"
!macroend
// vue.config.js

module.exports = {
  pluginOptions: {
    electronBuilder: {
      builderOptions: {
        nsis: {
          allowToChangeInstallationDirectory: true,
          include: 'installer.nsh' // 設定檔路徑
        }
      }
    }
  }
}

正式版與測試版

如果同一個專案環境參數不同,想編譯兩個版本的話,Electron 主要是依照 appId 區分應用程式,而我們可以依照環境變數修改設定來達到目的

{
  "scripts": {
    "electron:build": "vue-cli-service electron:build", // 正式版
    "electron:build:dev": "vue-cli-service electron:build --mode development" // 測試版
  }
}
// vue.config.js

// 測試版時為 test 字串,正式版則為空
const env = process.env.NODE_ENV === 'development' ? 'test' : ''
module.exports = {
  pluginOptions: {
    electronBuilder: {
      preload: 'src/preload.js',
      builderOptions: {
        appId: 'your.id' + env, // 測試版時加入字串
        productName: 'productName' + env, // 測試版時加入字串
      }
    }
  }
}

自動更新

這邊使用 electron-updater 來實作更新的功能,他提供使用 Github 、url 或其他的上傳方式,這邊示範一般 url 的寫法

  1. 安裝套件
$ yarn add --dev electron-updater
  1. vue.config.js 內加入 publish 的設定
module.exports = {
  pluginOptions: {
    electronBuilder: {
      builderOptions: {
        publish: [
          {
            provider: 'generic',
            url: ''
          }
        ]
      }
    }
  }
}

加入後打包會產生出一個 latest.yml,該檔案紀錄了版本資訊,檢查更新會比對這個檔案的版本做更新,將檔案放到伺服器的時候須連同該檔案一起丟上去

  1. 加入自動更新的程式碼就完成囉
// background.js

// 設定更新檔路徑
autoUpdater.setFeedURL({
  provider: 'generic', // 亦可使用 Github
  url: 'your url'
})
autoUpdater.autoDownload = false // 不自動下載更新檔

// 有更新檔可下載
autoUpdater.on('update-available', info => {
  // do something...
})
// 沒有更新檔可下載
autoUpdater.on('update-not-available', info => {
  // do something...
})
// 下載進度,開始下載後會持續觸發此事件
autoUpdater.on('download-progress', info => {
  console.log(info.percent)
})
// 下載完成
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) => {
  autoUpdater.quitAndInstall()
})
// 錯誤
autoUpdater.on('error', function () {
  // do something...
})

// 開始下載更新
autoUpdater.checkForUpdates()

結語

因為現在各種套件都整合好了,在 Electron 裡面使用 Vue.js 可說是非常簡單,幾個指令就搞定了,設定也非常的簡單,剩下就是對 Electron 的熟悉度而已~


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Tree
iT邦新手 3 級 ‧ 2020-12-23 11:08:04

本魯比對 bradtraversy 的設定檔 跟您的設定檔

有下面 2 處不同

  • linux 系統的圖示用 .png
  • mac 系統的圖示用 .icns

請問您的 .ico 圖示有在 mac 與 linux 環境下打包 & 執行過嗎 ?


之前朋友有跟在下反應過使用 .ico 圖示 打包會有問題 ,
不過本魯沒有 macbook 無法測試 /images/emoticon/emoticon20.gif


下方分享在下使用的 圖示轉換器

圖示轉換器 ( online version )

Ares iT邦研究生 3 級 ‧ 2020-12-23 14:18:37 檢舉

的確在文件裡有寫到要使用 .icns.png,這邊我真的沒注意到~感謝提醒

(P.S.我也沒有 mac 所以無法測試XD)

我要留言

立即登入留言