📦 归档笔记 — 原创建于 WizNote,仅作归档展示;观点以当年为准,非最新。

electron-vue-cli3

创建时间2021-07-27最后修改2021-07-27原位置/程序员成长之旅/electron/字数6587
目录:程序员成长之旅/electron
# electron-vue-cli3

- 使用 [Vue CLI Plugin Electron Builder](https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/#installation) 进行构建

- 本文档基于 **vue-cli3** 和 **vue-cli-plugin-electron-builder v1.0.0**

## 安装

- 使用vue-cli3创建一个项目

- **vue add electron-builder** 安装插件

- **npm run electron:serve** 或者 **yarn electron:serve** 开启开发服务器

- **npm run electron:build** 或者 **yarn electron:build** 进行生产构建

## 本地模块

- 本地模块是自动支持的,且不需要任何配置即可运行

- 如果报错,首先需要确认 vue-cli-plugin-electron-builder 的版本是 1.0.0-rc.1 及以上

- 如果依旧报错,则需要使用 **vue invoke electron-builder** 再次调用生成器,生成器会自动检测缺失的代码(如本地模块支持)并添加,不会干扰其他代码

- 如果以上都试过之后,需要将本地依赖项设置为webpack外部依赖项

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

// List native deps here if they don't work

externals: ['my-native-dep'],

// If you are using Yarn Workspaces, you may have multiple node_modules folders

// List them all here so that VCP Electron Builder can find them

nodeModulesPath: ['../../node_modules', './node_modules']

}

}

}

```

- 如果在代码中不使用本地依赖项,可以从package.json中删除 **postinstall** script

- 本地模块可能无法工作,但依赖项安装时间会更快

## 渲染进程

- **__static** 全局变量:在生产和开发环境下,它都提供了到公共目录的路径, 使用它来读取/写入应用程序的公共目录中的文件

- 常规构建和服务中,该变量不可用,它应该只在 electron 中用于读取/写入磁盘上的文件

- import文件时,为了不让webpack编译,可以使用 **process.env.BASE_URL** (绝对路径webpack不会编译)

- 在生产环境,**process.env.BASE_URL** 被替换为应用程序文件的路径

## 主线程(background.js)

- 主进程无法访问**process.env.BASE_URL**或**src/assets**。但是,仍然可以在开发和生产中使用**__static**来获取到您的公共目录的路径

```js

// Both renderer and main process

// This will read the contents of public/myText.txt

// Expects myText.txt to be placed in public folder

const fileLocation = path.join(__static, 'myText.txt')

```

## 生产构建文件结构

```shell

├── dist_electron/

│ ├── bundled/..  # where webpack outputs compiled files

│ ├── [target platform]-unpacked/..  # unpacked Electron app (main app and supporting files)

│ ├── [application name] setup [version].[target binary (exe|dmg|rpm...)]  # installer for Electron app

│ ├── index.js  # compiled background file used for electron:serve

│ └── ...

├── public/  # Files placed here will be available through __static or process.env.BASE_URL

├── src/

│ ├── background.[js|ts]  # electron entry file (for Electron's main process)

│ ├── [main|index].[js|ts]  # your app's entry file (for Electron's render process)

│ └── ...

├── package.json  # your app's package.json file

├── ...

```

## 环境变量

- 所有以 **VUE_APP_** 前缀的env变量都将在主进程和渲染程序进程中可用(从1.0.0-rc.4开始仅在主进程中可用)

## Build 命令工作原理

- 包括三大阶段:render build,main build,electron-builder build

- Render build:调用一些自定义的配置运行 **vue-cli-service build** 以便可以正确地和 electron 进行工作(这个渲染进程就是指应用程序)

- Main build:在这个阶段 vue-cli-plugin-electron-builder 为主进程打包 **src/background.js** 背景文件

- Electron-builder build:这个阶段通过 **electron-builder** 把 web app 代码转成由 electron 运行的桌面应用程序代码

## Serve 命令工作原理

- 包括三大阶段:main build, dev server launch, and electron launch

- Dev server launch:此阶段将启动内建的dev服务器,对其进行一些修改,以便正确地使用electronic

- Main build:与build类似,打包了应用程序的主进程,但是处于开发环境

- Electron launch:此阶段启动 electron 并让它加载以上开发服务器的URL

## 配置 Electron Builder

- [Electron Builder Configuration Options](https://www.electron.build/configuration/configuration)

- 所有传递给electron:build的CLI参数都将被转发给electron-builder

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

builderOptions: {

// options placed here will be merged with default configuration and passed to electron-builder

}

}

}

}

```

## webpack 配置

```js

// vue.config.js

module.exports = {

configureWebpack: {

// 应用于所有构建的配置

},

pluginOptions: {

electronBuilder: {

chainWebpackMainProcess: config => {

// 只对主进程生效

},

chainWebpackRendererProcess: config => {

// 只对渲染进程生效

// 例如设置 IS_ELECTRON 为 true

config.plugin('define').tap(args => {

args[0]['IS_ELECTRON'] = true

return args

})

},

// 设置主进程入口文件

mainProcessFile: 'src/myBackgroundFile.js',

// 设置一个文件数组,位于其中的文件如果被修改,则重编译主进程并重启electron

// 主进程文件将被默认添加

mainProcessWatch: ['src/myFile1', 'src/myFile2'],

// [1.0.0-rc.4+] 提供了一份参数数组,electron将在 "electron:serve" 期间访问,可以在主进程(src/background.js)访问这些参数

// 注意当 --debug 与 "electron:serve" 一起使用时,这些参数将被忽略,因为你必须自己启动 electron

// 命令行参数(不包括--debug、--dashboard和--headless)也会传递给 electron

mainProcessArgs: ['--arg-name', 'arg-value']

}

}

}

```

## 改变输出目录

- 为了不适用 "dist_electron" 默认输出目录,可以在 **vue-cli-plugin-electron-builder** 的插件选项中自定义

- 如果使用的 **vue-cli-plugin-electron-builder** 是 **v1.0.0-rc.4** 及以上版本,则也可以用 **--dest** 参数修改输出目录

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

outputDir: 'electron-builder-output-dir'

}

}

}

```

- 如果使用的 **vue-cli-plugin-electron-builder** 是 **v1.0.0-rc.3** 及以下版本,更新完输出目录后必须更新 **package.json** 文件中的 **main** 字段为新的主程序文件([new dir]/bundled/background.js),同时建议把新的输出目录添加进 **.gitignore** 文件

## TypeScript Options

- ts支持是自动的,不需要任何配置,只需要 "vue add @vue/typescript"

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

disableMainProcessTypescript: false, // 手动关闭在主进程使用的ts插件,之后可以在主进程(src/background.js)使用常规的js

mainProcessTypeChecking: false // 手动关闭主进程的类型检查

}

}

}

```

- 在**1.0.0-rc.1+**,如果决定稍后再添加 "@vue/typescript" 插件,则要使用 **vue invoke electron-builder** 再次调用插件生成器,这会自动将缺失的类型定义插入到 **background.ts** 文件

## 改变文件加载协议

- 默认使用 vue-cli的现代模式下的 **type="module"** 方式去加载文件,如果想自定义不同的加载协议,需要使用 **customFileProtocol** 并修改 **background.js** 文件

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

customFileProtocol: 'myCustomProtocol://./' // 协议的末尾一定要加上 "./"

customFileProtocol: 'file://./' // 也可以回到默认的文件协议 "file://"

}

}

}

// src/background.js

// ...

win.loadURL('myCustomProtocol://./index.html') // 同时要改变此处的协议

// ...

```

## 打包选项

- 默认的,应用程序使用现代模式构建,如果要禁止这种模式,可以在 "electron:build" 命令上传递 **--legacy** 这个参数

- 如果你的应用程序已经打包好了,且只需要使用 **electron-builder** 构建,那么可以传递 **--skipBundle** 这个参数

## electron 的终端上的垃圾输出

- electron 有时会生成一串垃圾输出(例如提示chrome的未捕获错误),**vue-cli-plugin-electron-builder** 默认关闭了这些输出

- 如果需要开启这些垃圾输出,那么需要设置 **electronJunkOutput** 属性

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

removeElectronJunk: false // True by default

}

}

}

```

## 自定义启动程序和托盘的Icon

- 安装 **electron-icon-builder** 为开发依赖

- yarn add --dev electron-icon-builder

- npm install -D electron-icon-builder

- 设置Icon图片 **public/icon.png**

- **package.json** 添加生成script

- "electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten"

- 生成icon

- yarn electron:generate-icons

- npm run electron:generate-icon

- 以上只会生成各种大小的icon,一般不这样生成

- 设置托盘icon

- 编辑 src/background.(js|ts)

```js

'use-strict';

import path from 'path'

win = new BrowserWindow({

width: 800,

height: 600,

// 添加这一行

// 如果 __static 报错 not defined,则需要在imports代码上面添加 /* global __static */ 字段(试过发现好像没用,可以设置 declare const __static: any;)

icon: path.join(__static, 'icon.png')

})

```

## 为每个页面创建多个electron窗口

- 根据 [pages属性](https://cli.vuejs.org/config/#pages) 添加pages

- [案例](https://github.com/nklayman/electron-multipage-example)

- 为第二个页面创建变量

- 在背景文件(默认是src/background.(js|ts))中添加 **secondWin** 和 **createdAppProtocol** 变量

```js

// Already in file

let win

// Add these below

let secondWin

let createdAppProtocol = false

```

- 在背景文件更新 createWindow 方法

```js

protocol.registerStandardSchemes(['reolink'], { secure: true })

// 给 createWindow 设置需要新增传入参数 winVar, devPath, prodPath

function createWindow(winVar, devPath, prodPath) {

// Create the browser window.

winVar = new BrowserWindow({ width: 800, height: 600 })

if (process.env.WEBPACK_DEV_SERVER_URL) {

// Load the url of the dev server if in development mode

// loadURL 需要新增加上 devPath

winVar.loadURL(process.env.WEBPACK_DEV_SERVER_URL + devPath)

if (!process.env.IS_TEST) winVar.webContents.openDevTools()

} else {

if (!createdAppProtocol) {

createProtocol('app')

createdAppProtocol = true

}

// Load the index.html when not in development

winVar.loadURL(`app://./${prodPath}`)

}

winVar.on('closed', () => {

winVar = null

})

}

```

- 在应用程序启动时创建两个窗口

```js

app.on('ready', async () => {

if (isDevelopment && !process.env.IS_TEST) {

// Install Vue Devtools

try {

await installVueDevtools()

} catch (e) {

console.error('Vue Devtools failed to install:', e.toString())

}

}

// Replace

createWindow()

// With

createWindow(win, '', 'index.html')

createWindow(secondWin, 'subpage', 'subpage.html')

})

```

- 点击 Dock Icon 时再次创建两个窗口

```js

app.on('activate', () => {

// On macOS it's common to re-create a window in the app when the

// dock icon is clicked and there are no other windows open.

if (win === null) {

createWindow(win, '', 'index.html')

}

if (secondWin === null) {

createWindow(secondWin, 'subpage', 'subpage.html')

}

```

## 使用 vscode 调试

- 开启 sourcemaps

- 在 **.vscode/tasks.json** 添加 electron-debug 任务,该任务会以 debug 模式开启 Electron dev server

```json

{

// See https://go.microsoft.com/fwlink/?LinkId=733558

// for the documentation about the tasks.json format

"version": "2.0.0",

"tasks": [

{

"label": "electron-debug",

"type": "process",

"command": "./node_modules/.bin/vue-cli-service",

"windows": {

"command": "./node_modules/.bin/vue-cli-service.cmd"

},

"isBackground": true,

"args": ["electron:serve", "--debug"],

"problemMatcher": {

"owner": "custom",

"pattern": {

"regexp": ""

},

"background": {

"beginsPattern": "Starting development server\\.\\.\\.",

"endsPattern": "Not launching electron as debug argument was passed\\."

}

}

}

]

}

```

- 在 **.vscode/launch.json** 给各环境添加debug配置

```json

{

"version": "0.2.0",

"configurations": [

{

"name": "Electron: Main",

"type": "node",

"request": "launch",

"protocol": "inspector",

"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",

"windows": {

"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"

},

"preLaunchTask": "electron-debug",

"args": ["--remote-debugging-port=9223", "./dist_electron"],

"outFiles": ["${workspaceFolder}/dist_electron/**/*.js"]

},

{

"name": "Electron: Renderer",

"type": "chrome",

"request": "attach",

"port": 9223,

"urlFilter": "http://localhost:*",

"timeout": 30000,

"webRoot": "${workspaceFolder}/src",

"sourceMapPathOverrides": {

"webpack:///./src/*": "${webRoot}/*"

}

}

],

"compounds": [

{

"name": "Electron: All",

"configurations": ["Electron: Main", "Electron: Renderer"]

}

]

}

```

- 配置好后,即可在vue app 或者 background 文件上打上断点

- 在vscode中选择 **Electron: All** 配置运行

- 在刚刚启动electron程序时,无法检测到断点,重新加载窗口可以生效

## 测试

- [Spectron](https://electronjs.org/spectron)

- 当使用 Spectron 时,要确保设置了 process.env.IS_TEST 为 true,否则会加载dev tools 而 Spectron 会因此报错

- vue-cli-plugin-electron-builder 可以导出 testWithSpectron 方法,它会运行 **electron:serve**,但不会启动 electron,而是创建一个新的 Spectron app 附加到开发服务器

- 也能用在 e2e 测试

```js

// This example uses Jest, but any testing framework will work as well

const { testWithSpectron } = require('vue-cli-plugin-electron-builder')

test('a window is created', async () => {

const { stdout, url, stopServe, app } = await testWithSpectron()

// stdout electron:serve 的日志

console.log(`electron:serve returned: ${stdout}`)

// url 是由 electron:serve 创建的开发服务器的地址 is the url for the dev server created with electron:serve

console.log(`the dev server url is: ${url}`)

// app 是一个 spectron 实例,它被附加到开发服务器,然后被启动并等待加载

expect(await app.client.getWindowCount()).toBe(1)

// 在测试结束前,确保停止服务器和spectron

await stopServe()

})

```

```js

// testWithSpectron 配置参数

const { testWithSpectron } = require('vue-cli-plugin-electron-builder')

testWithSpectron({

noSpectron: false // 不启动Spectron. 如果想自己启动 spectron,就设置为true

noStart: false // 不启动Spectron app 或等待它加载. 在运行任何测试之前,必须调用app.start()和app.client.waitUntilWindowLoaded()

forceDev: false // 以开发 mode 运行 dev server. 默认以 production mode 运行

mode: 'test', // 设置自定义 Vue env mode

spectronOptions: {} // 设置自定义的配置传递给 Spectron. Spectron 自己已经有默认值

})

```

## FAQs

### builds 时白屏,但在 serve 时正常工作

- 当 **vue-router** 在 history 模式下运行时,可能会导致此问题

- 解决办法:在 Vue 组件根目录下添加 **mounted** 钩子

- 这个方法不会影响 web builds

```js

// src/main.js

new Vue({

router,

render: h => h(App),

mounted() {

// Prevent blank screen in Electron builds

this.$router.push('/')

}

}).$mount('#app')

```

### **electron:serve** 卡在了 **Launching Electron...**

- 通常这个问题是在 **Vue Devtools** 无法安装时引起的,最有可能的是因为无法在你所在的地区访问Vue Devtools(例如中国)

- 解决办法:在 **src/background.(js|ts)** 文件中删除 Vue Devtools 的安装步骤

```js

if (isDevelopment && !process.env.IS_TEST) {

// Install Vue Devtools

await installVueDevtools()

}

```

- 用electron来集成vue-devtools过于麻烦,一个简单的方法是使用远程调试

- yarn global add @vue/devtools安装,然后运行vue-devtools,在模板index.html中引入脚本就可以开始调试了

### 异步函数中的异常没有记录到控制台

- 在 Vue App 入口文件 src/main.js 中添加以下代码

```js

process.on('unhandledRejection', error => {

console.error(error)

})

```

### Electron 在 Node v11 上打开

- Electron 要使用 v2.0.14+ or v3.0.10+,Node使用 v11.2.0+

### 修改滚动条样式

```less

@gak-no-visible: rgba(0, 0, 0, 0);

html, body {

overflow: hidden;

height: 100%;

}

.gak-bg-no-visible {

background-color: @gak-no-visible;

}

.gak-scroll {

height: 100%;

-webkit-overflow-scrolling: touch;

overflow-y: auto;

/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/

&::-webkit-scrollbar {

width: 8px;

height: 4px;

cursor: pointer;

.gak-bg-no-visible;

}

/*定义滚动条轨道 内阴影+圆角*/

&::-webkit-scrollbar-track {

border: none;

.gak-bg-no-visible;

}

/*定义滑块 内阴影+圆角*/

&::-webkit-scrollbar-thumb{

border-radius: 10px;

background-color: rgba(110, 110, 110, 0.2);

}

}

```

### 实时聊天组件

- 使用[vue-socket.io-extended](https://github.com/probil/vue-socket.io-extended)

- Vue-Socket.io不再支持vuex

- 采用[外部文件扩展的方式](https://github.com/probil/vue-socket.io-extended/issues/91#issuecomment-397232621),可以在action里调用

### 其他问题

- 大部分的问题都能通过重新调用 Vue CLI Plugin Electron Builder 生成器解决,这允许它更新代码到项目

- 一般在升级插件后需要这样做

```shell

# In the root dir of your project

vue invoke electron-builder

```

请输入需要翻译的文本。

{"mode":"full","isActive":false}

来源:


# electron-vue-cli3

- 使用 [Vue CLI Plugin Electron Builder](https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/#installation) 进行构建

- 本文档基于 **vue-cli3** 和 **vue-cli-plugin-electron-builder v1.0.0**

## 安装

- 使用vue-cli3创建一个项目

- **vue add electron-builder** 安装插件

- **npm run electron:serve** 或者 **yarn electron:serve** 开启开发服务器

- **npm run electron:build** 或者 **yarn electron:build** 进行生产构建

## 本地模块

- 本地模块是自动支持的,且不需要任何配置即可运行

- 如果报错,首先需要确认 vue-cli-plugin-electron-builder 的版本是 1.0.0-rc.1 及以上

- 如果依旧报错,则需要使用 **vue invoke electron-builder** 再次调用生成器,生成器会自动检测缺失的代码(如本地模块支持)并添加,不会干扰其他代码

- 如果以上都试过之后,需要将本地依赖项设置为webpack外部依赖项

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

// List native deps here if they don't work

externals: ['my-native-dep'],

// If you are using Yarn Workspaces, you may have multiple node_modules folders

// List them all here so that VCP Electron Builder can find them

nodeModulesPath: ['../../node_modules', './node_modules']

}

}

}

```

- 如果在代码中不使用本地依赖项,可以从package.json中删除 **postinstall** script

- 本地模块可能无法工作,但依赖项安装时间会更快

## 渲染进程

- **__static** 全局变量:在生产和开发环境下,它都提供了到公共目录的路径, 使用它来读取/写入应用程序的公共目录中的文件

- 常规构建和服务中,该变量不可用,它应该只在 electron 中用于读取/写入磁盘上的文件

- import文件时,为了不让webpack编译,可以使用 **process.env.BASE_URL** (绝对路径webpack不会编译)

- 在生产环境,**process.env.BASE_URL** 被替换为应用程序文件的路径

## 主线程(background.js)

- 主进程无法访问**process.env.BASE_URL**或**src/assets**。但是,仍然可以在开发和生产中使用**__static**来获取到您的公共目录的路径

```js

// Both renderer and main process

// This will read the contents of public/myText.txt

// Expects myText.txt to be placed in public folder

const fileLocation = path.join(__static, 'myText.txt')

```

## 生产构建文件结构

```shell

├── dist_electron/

│ ├── bundled/..  # where webpack outputs compiled files

│ ├── [target platform]-unpacked/..  # unpacked Electron app (main app and supporting files)

│ ├── [application name] setup [version].[target binary (exe|dmg|rpm...)]  # installer for Electron app

│ ├── index.js  # compiled background file used for electron:serve

│ └── ...

├── public/  # Files placed here will be available through __static or process.env.BASE_URL

├── src/

│ ├── background.[js|ts]  # electron entry file (for Electron's main process)

│ ├── [main|index].[js|ts]  # your app's entry file (for Electron's render process)

│ └── ...

├── package.json  # your app's package.json file

├── ...

```

## 环境变量

- 所有以 **VUE_APP_** 前缀的env变量都将在主进程和渲染程序进程中可用(从1.0.0-rc.4开始仅在主进程中可用)

## Build 命令工作原理

- 包括三大阶段:render build,main build,electron-builder build

- Render build:调用一些自定义的配置运行 **vue-cli-service build** 以便可以正确地和 electron 进行工作(这个渲染进程就是指应用程序)

- Main build:在这个阶段 vue-cli-plugin-electron-builder 为主进程打包 **src/background.js** 背景文件

- Electron-builder build:这个阶段通过 **electron-builder** 把 web app 代码转成由 electron 运行的桌面应用程序代码

## Serve 命令工作原理

- 包括三大阶段:main build, dev server launch, and electron launch

- Dev server launch:此阶段将启动内建的dev服务器,对其进行一些修改,以便正确地使用electronic

- Main build:与build类似,打包了应用程序的主进程,但是处于开发环境

- Electron launch:此阶段启动 electron 并让它加载以上开发服务器的URL

## 配置 Electron Builder

- [Electron Builder Configuration Options](https://www.electron.build/configuration/configuration)

- 所有传递给electron:build的CLI参数都将被转发给electron-builder

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

builderOptions: {

// options placed here will be merged with default configuration and passed to electron-builder

}

}

}

}

```

## webpack 配置

```js

// vue.config.js

module.exports = {

configureWebpack: {

// 应用于所有构建的配置

},

pluginOptions: {

electronBuilder: {

chainWebpackMainProcess: config => {

// 只对主进程生效

},

chainWebpackRendererProcess: config => {

// 只对渲染进程生效

// 例如设置 IS_ELECTRON 为 true

config.plugin('define').tap(args => {

args[0]['IS_ELECTRON'] = true

return args

})

},

// 设置主进程入口文件

mainProcessFile: 'src/myBackgroundFile.js',

// 设置一个文件数组,位于其中的文件如果被修改,则重编译主进程并重启electron

// 主进程文件将被默认添加

mainProcessWatch: ['src/myFile1', 'src/myFile2'],

// [1.0.0-rc.4+] 提供了一份参数数组,electron将在 "electron:serve" 期间访问,可以在主进程(src/background.js)访问这些参数

// 注意当 --debug 与 "electron:serve" 一起使用时,这些参数将被忽略,因为你必须自己启动 electron

// 命令行参数(不包括--debug、--dashboard和--headless)也会传递给 electron

mainProcessArgs: ['--arg-name', 'arg-value']

}

}

}

```

## 改变输出目录

- 为了不适用 "dist_electron" 默认输出目录,可以在 **vue-cli-plugin-electron-builder** 的插件选项中自定义

- 如果使用的 **vue-cli-plugin-electron-builder** 是 **v1.0.0-rc.4** 及以上版本,则也可以用 **--dest** 参数修改输出目录

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

outputDir: 'electron-builder-output-dir'

}

}

}

```

- 如果使用的 **vue-cli-plugin-electron-builder** 是 **v1.0.0-rc.3** 及以下版本,更新完输出目录后必须更新 **package.json** 文件中的 **main** 字段为新的主程序文件([new dir]/bundled/background.js),同时建议把新的输出目录添加进 **.gitignore** 文件

## TypeScript Options

- ts支持是自动的,不需要任何配置,只需要 "vue add @vue/typescript"

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

disableMainProcessTypescript: false, // 手动关闭在主进程使用的ts插件,之后可以在主进程(src/background.js)使用常规的js

mainProcessTypeChecking: false // 手动关闭主进程的类型检查

}

}

}

```

- 在**1.0.0-rc.1+**,如果决定稍后再添加 "@vue/typescript" 插件,则要使用 **vue invoke electron-builder** 再次调用插件生成器,这会自动将缺失的类型定义插入到 **background.ts** 文件

## 改变文件加载协议

- 默认使用 vue-cli的现代模式下的 **type="module"** 方式去加载文件,如果想自定义不同的加载协议,需要使用 **customFileProtocol** 并修改 **background.js** 文件

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

customFileProtocol: 'myCustomProtocol://./' // 协议的末尾一定要加上 "./"

customFileProtocol: 'file://./' // 也可以回到默认的文件协议 "file://"

}

}

}

// src/background.js

// ...

win.loadURL('myCustomProtocol://./index.html') // 同时要改变此处的协议

// ...

```

## 打包选项

- 默认的,应用程序使用现代模式构建,如果要禁止这种模式,可以在 "electron:build" 命令上传递 **--legacy** 这个参数

- 如果你的应用程序已经打包好了,且只需要使用 **electron-builder** 构建,那么可以传递 **--skipBundle** 这个参数

## electron 的终端上的垃圾输出

- electron 有时会生成一串垃圾输出(例如提示chrome的未捕获错误),**vue-cli-plugin-electron-builder** 默认关闭了这些输出

- 如果需要开启这些垃圾输出,那么需要设置 **electronJunkOutput** 属性

```js

// vue.config.js

module.exports = {

pluginOptions: {

electronBuilder: {

removeElectronJunk: false // True by default

}

}

}

```

## 自定义启动程序和托盘的Icon

- 安装 **electron-icon-builder** 为开发依赖

- yarn add --dev electron-icon-builder

- npm install -D electron-icon-builder

- 设置Icon图片 **public/icon.png**

- **package.json** 添加生成script

- "electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten"

- 生成icon

- yarn electron:generate-icons

- npm run electron:generate-icon

- 以上只会生成各种大小的icon,一般不这样生成

- 设置托盘icon

- 编辑 src/background.(js|ts)

```js

'use-strict';

import path from 'path'

win = new BrowserWindow({

width: 800,

height: 600,

// 添加这一行

// 如果 __static 报错 not defined,则需要在imports代码上面添加 /* global __static */ 字段(试过发现好像没用,可以设置 declare const __static: any;)

icon: path.join(__static, 'icon.png')

})

```

## 为每个页面创建多个electron窗口

- 根据 [pages属性](https://cli.vuejs.org/config/#pages) 添加pages

- [案例](https://github.com/nklayman/electron-multipage-example)

- 为第二个页面创建变量

- 在背景文件(默认是src/background.(js|ts))中添加 **secondWin** 和 **createdAppProtocol** 变量

```js

// Already in file

let win

// Add these below

let secondWin

let createdAppProtocol = false

```

- 在背景文件更新 createWindow 方法

```js

protocol.registerStandardSchemes(['reolink'], { secure: true })

// 给 createWindow 设置需要新增传入参数 winVar, devPath, prodPath

function createWindow(winVar, devPath, prodPath) {

// Create the browser window.

winVar = new BrowserWindow({ width: 800, height: 600 })

if (process.env.WEBPACK_DEV_SERVER_URL) {

// Load the url of the dev server if in development mode

// loadURL 需要新增加上 devPath

winVar.loadURL(process.env.WEBPACK_DEV_SERVER_URL + devPath)

if (!process.env.IS_TEST) winVar.webContents.openDevTools()

} else {

if (!createdAppProtocol) {

createProtocol('app')

createdAppProtocol = true

}

// Load the index.html when not in development

winVar.loadURL(`app://./${prodPath}`)

}

winVar.on('closed', () => {

winVar = null

})

}

```

- 在应用程序启动时创建两个窗口

```js

app.on('ready', async () => {

if (isDevelopment && !process.env.IS_TEST) {

// Install Vue Devtools

try {

await installVueDevtools()

} catch (e) {

console.error('Vue Devtools failed to install:', e.toString())

}

}

// Replace

createWindow()

// With

createWindow(win, '', 'index.html')

createWindow(secondWin, 'subpage', 'subpage.html')

})

```

- 点击 Dock Icon 时再次创建两个窗口

```js

app.on('activate', () => {

// On macOS it's common to re-create a window in the app when the

// dock icon is clicked and there are no other windows open.

if (win === null) {

createWindow(win, '', 'index.html')

}

if (secondWin === null) {

createWindow(secondWin, 'subpage', 'subpage.html')

}

```

## 使用 vscode 调试

- 开启 sourcemaps

- 在 **.vscode/tasks.json** 添加 electron-debug 任务,该任务会以 debug 模式开启 Electron dev server

```json

{

// See https://go.microsoft.com/fwlink/?LinkId=733558

// for the documentation about the tasks.json format

"version": "2.0.0",

"tasks": [

{

"label": "electron-debug",

"type": "process",

"command": "./node_modules/.bin/vue-cli-service",

"windows": {

"command": "./node_modules/.bin/vue-cli-service.cmd"

},

"isBackground": true,

"args": ["electron:serve", "--debug"],

"problemMatcher": {

"owner": "custom",

"pattern": {

"regexp": ""

},

"background": {

"beginsPattern": "Starting development server\\.\\.\\.",

"endsPattern": "Not launching electron as debug argument was passed\\."

}

}

}

]

}

```

- 在 **.vscode/launch.json** 给各环境添加debug配置

```json

{

"version": "0.2.0",

"configurations": [

{

"name": "Electron: Main",

"type": "node",

"request": "launch",

"protocol": "inspector",

"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",

"windows": {

"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"

},

"preLaunchTask": "electron-debug",

"args": ["--remote-debugging-port=9223", "./dist_electron"],

"outFiles": ["${workspaceFolder}/dist_electron/**/*.js"]

},

{

"name": "Electron: Renderer",

"type": "chrome",

"request": "attach",

"port": 9223,

"urlFilter": "http://localhost:*",

"timeout": 30000,

"webRoot": "${workspaceFolder}/src",

"sourceMapPathOverrides": {

"webpack:///./src/*": "${webRoot}/*"

}

}

],

"compounds": [

{

"name": "Electron: All",

"configurations": ["Electron: Main", "Electron: Renderer"]

}

]

}

```

- 配置好后,即可在vue app 或者 background 文件上打上断点

- 在vscode中选择 **Electron: All** 配置运行

- 在刚刚启动electron程序时,无法检测到断点,重新加载窗口可以生效

## 测试

- [Spectron](https://electronjs.org/spectron)

- 当使用 Spectron 时,要确保设置了 process.env.IS_TEST 为 true,否则会加载dev tools 而 Spectron 会因此报错

- vue-cli-plugin-electron-builder 可以导出 testWithSpectron 方法,它会运行 **electron:serve**,但不会启动 electron,而是创建一个新的 Spectron app 附加到开发服务器

- 也能用在 e2e 测试

```js

// This example uses Jest, but any testing framework will work as well

const { testWithSpectron } = require('vue-cli-plugin-electron-builder')

test('a window is created', async () => {

const { stdout, url, stopServe, app } = await testWithSpectron()

// stdout electron:serve 的日志

console.log(`electron:serve returned: ${stdout}`)

// url 是由 electron:serve 创建的开发服务器的地址 is the url for the dev server created with electron:serve

console.log(`the dev server url is: ${url}`)

// app 是一个 spectron 实例,它被附加到开发服务器,然后被启动并等待加载

expect(await app.client.getWindowCount()).toBe(1)

// 在测试结束前,确保停止服务器和spectron

await stopServe()

})

```

```js

// testWithSpectron 配置参数

const { testWithSpectron } = require('vue-cli-plugin-electron-builder')

testWithSpectron({

noSpectron: false // 不启动Spectron. 如果想自己启动 spectron,就设置为true

noStart: false // 不启动Spectron app 或等待它加载. 在运行任何测试之前,必须调用app.start()和app.client.waitUntilWindowLoaded()

forceDev: false // 以开发 mode 运行 dev server. 默认以 production mode 运行

mode: 'test', // 设置自定义 Vue env mode

spectronOptions: {} // 设置自定义的配置传递给 Spectron. Spectron 自己已经有默认值

})

```

## FAQs

### builds 时白屏,但在 serve 时正常工作

- 当 **vue-router** 在 history 模式下运行时,可能会导致此问题

- 解决办法:在 Vue 组件根目录下添加 **mounted** 钩子

- 这个方法不会影响 web builds

```js

// src/main.js

new Vue({

router,

render: h => h(App),

mounted() {

// Prevent blank screen in Electron builds

this.$router.push('/')

}

}).$mount('#app')

```

### **electron:serve** 卡在了 **Launching Electron...**

- 通常这个问题是在 **Vue Devtools** 无法安装时引起的,最有可能的是因为无法在你所在的地区访问Vue Devtools(例如中国)

- 解决办法:在 **src/background.(js|ts)** 文件中删除 Vue Devtools 的安装步骤

```js

if (isDevelopment && !process.env.IS_TEST) {

// Install Vue Devtools

await installVueDevtools()

}

```

- 用electron来集成vue-devtools过于麻烦,一个简单的方法是使用远程调试

- yarn global add @vue/devtools安装,然后运行vue-devtools,在模板index.html中引入脚本就可以开始调试了

### 异步函数中的异常没有记录到控制台

- 在 Vue App 入口文件 src/main.js 中添加以下代码

```js

process.on('unhandledRejection', error => {

console.error(error)

})

```

### Electron 在 Node v11 上打开

- Electron 要使用 v2.0.14+ or v3.0.10+,Node使用 v11.2.0+

### 修改滚动条样式

```less

@gak-no-visible: rgba(0, 0, 0, 0);

html, body {

overflow: hidden;

height: 100%;

}

.gak-bg-no-visible {

background-color: @gak-no-visible;

}

.gak-scroll {

height: 100%;

-webkit-overflow-scrolling: touch;

overflow-y: auto;

/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/

&::-webkit-scrollbar {

width: 8px;

height: 4px;

cursor: pointer;

.gak-bg-no-visible;

}

/*定义滚动条轨道 内阴影+圆角*/

&::-webkit-scrollbar-track {

border: none;

.gak-bg-no-visible;

}

/*定义滑块 内阴影+圆角*/

&::-webkit-scrollbar-thumb{

border-radius: 10px;

background-color: rgba(110, 110, 110, 0.2);

}

}

```

### 实时聊天组件

- 使用[vue-socket.io-extended](https://github.com/probil/vue-socket.io-extended)

- Vue-Socket.io不再支持vuex

- 采用[外部文件扩展的方式](https://github.com/probil/vue-socket.io-extended/issues/91#issuecomment-397232621),可以在action里调用

### 其他问题

- 大部分的问题都能通过重新调用 Vue CLI Plugin Electron Builder 生成器解决,这允许它更新代码到项目

- 一般在升级插件后需要这样做

```shell

# In the root dir of your project

vue invoke electron-builder

```

来源:notes/electron-vue-cli3.md at fc073b5b9d312bf282fd839c6c32b12f993b2477 · zwwsun/notes (github.com)