Electron - 今晚我想来点 Electron 加 Vue.js

前几篇介绍了 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 的熟悉度而已~


<<:  [Golang]同步工具-sync包的原子操作(上)-心智图总结

>>:  如何在Windows 10中从磁碟机中删除锁定图标

Day 17-实务上如何写出 terraform module,以 AKS 为例

本章介绍实务上如何写出自己的 terraform module 课程内容与代码会放在 Github ...

Day4# 变数宣告

知道了有哪些资料型态後,就可以开始变数宣告了! 那麽话不多说,那我们就开始吧 ─=≡Σ(((っ゚∀゚...

Linux 建立目录的捷径

如果要在 Linux 里面建立捷径,可使用已下语法: ln -s /usr/local/openlo...

Day 8:506. Relative Ranks

今日题目 题目连结:506. Relative Ranks 题目主题:Array, Sorting,...

Fluentd Bit

在 Fluentd Bit 中可以使用 read 或 socket 方式处理日志 read 用於读容...