在Electron中使用Vue
系列文章
- 什么是Electron
- 如何使用Electron
- Electron的基础知识
- 在Electron中使用Vue【当前文章】
- 关于Electron性能的讨论
- 在Electron中使用C++扩展
四、在Electron中使用Vue
4.1 安装与使用Vue
安装Vue是非常简单的,一条命令即可。
npm install -g @vue/cli
注意:这儿vue是全局包。也就是说vue会是全局一个命令。
创建一个vue的demo也容易,也是一个命令即可搞定。
vue create demo4
选择几个基本问题即可,通常一路回车即可。如果懒得按回车,也可以直接使用-d
参数,全部采用默认值。
vue create -d demo4
这一次的文件就有点多了。不过都是Vue框架的,我们就不做解释了。到这一步,咱们已经使用vue的脚手架把一个最简单的demo创建好了。它是可以正常运行的,只需执行命令:
npm run serve
然后,在浏览器中打开对应的网址即可。默认一般是http://localhost:8080/
。
4.2 添加Electron支持
与之前的electron工程不同,我们不再使用npm install electron --save-dev
这个命令了。而是改用vue的插件:
vue add electron-builder
不是不能使用原来的命令,而是使用electron-builder
更有性价比。正如其名electron-builder
是一个electron的构建工具包。使用它可以很容易的把一个electron打包成一个安装程序或者运行程序。关于electron-builder的具体使用方法,可以参考其官网文档。
如果你使用的是Linux系统,执行完上面的命令以后,需要修改src/background.js
,把其中的await installExtension(VUEJS3_DEVTOOLS)
这一行中的await
删掉即可。估计是一个兼容性BUG,这个指令会导致程序一直等待在此处。于是,无法弹出Electron的窗口。
接下来,只需执行命令:
npm run electron:serve
就可以将vue在electron窗口中运行起来了。如下图所示:
4.3 使用Electron
按照常规想法,如果想在vue工程中使用Electron,首先想到应该是,在App.vue
文件的script
中新增相关的代码。例如:
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<span id="msg"></span>!
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
let {ipcRenderer} = require("electron");
ipcRenderer.send("msg2main", "this is a message from render");
ipcRenderer.on("msg2render", (event, msg)=>{
console.log("Received a msg in render: ", msg)
document.querySelector("#msg").innerText += "\n"+ msg;
})
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
其中,第11~16行就是我们在demo3
中写的一段代码。结果你就会发现,无法编译通过,报错如下:
这是因为vue的编译器并不知道Electron的存在。事实上它也不需要知道。但是,我们怎么解决这个问题呢?如果你接下来尝试把这段代码放到其他地方,包括独立的js文件中,就会发现无论如何都无法正确运行。除非放到index.html
里面。我们知道,在vue的index.html
里面都是全局的。显然,我们不应该把代码写在这个文件中。话说回来,即使写在这儿,在vue里面还是无法使用。难道这个就无解了吗?当然不是。这就需要用到Electron的一个非常重要的特性——上下文隔离。
这是Electron提供的一个安全机制。它允许你在预加载脚本中使用node.js和Electron的功能模块,但是,无法在网页中直接使用。比如,我们前面的尝试在App.vue中试图访问node.js和electron的尝试都是不允许的。同时,它有可以开放一部分功能给到网页中使用。我们可以在预加载 脚本中定义一些函数或者变量。然后,就可以在页面上面使用它们了。所以,页面中使用的功能,一定是开发者允许页面使用的功能。而不是一股脑的把所有的能力都暴露给网页。
所以,接下来,我们定义一个名为preload.js
的脚本文件。内容如下:
import { contextBridge, ipcRenderer } from "electron";
contextBridge.exposeInMainWorld("electron", {
sendMsg: (msg) => {
ipcRenderer.send("send_msg", msg);
}
});
ipcRenderer.on("send_msg_ack", (event, value) => {
let txt = document.querySelector("#text");
console.log("value:", value, txt.innerHTML);
txt.innerHTML += value + "\n";
})
在这个脚本中,我们做了两件事件。
- 给网页提供了一个名为
sendMsg
的函数。它的功能很简单,就是使用ipcRenderer
发送一个消息给主进程。 - 定义了一个消息处理函数,当收到消息
send_msg_ack
后,把收到的数据显示到text
这个文本框中。
接下来,修改App.vue
的代码:
<template>
<div class="content">
<button @click="sendMsg">发送消息</button>
<br>
<textarea id="text" style="width: 99%;height: 600px;"></textarea>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
sendMsg(){
window.electron.sendMsg("this is a message");
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
注意:在vue中,我们可以使用window.electron.xxx
来访问预加载脚本中导出的变量或者函数。
最后,修改background.js
的内容为:
'use strict'
import { app, protocol, BrowserWindow, ipcMain } from 'electron'
... ...
let path = require('path');
... ...
async function createWindow() {
// Create the browser window.
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, "preload.js")
}
})
... ...
var index = 0;
ipcMain.on("send_msg", (event, msg)=>{
console.log("recv msg: ", msg);
index+=1;
event.reply("send_msg_ack", "this is a ack" + index);
})
留意,第21~23行,我们关闭了nodeIntegration
,开启了contextIsolation
,同时,给窗口提供了一个预加载脚本preload.js
。其他的代码就比较简单了,不再做解释说明。
接下来,运行命令npm run electron:serve
,就可以得到下面的画面了:
4.4 打包
要想把写好的程序发布出去,以便用户可以下载安装。那就必须对程序进行打包。打包是个系统相关的事情。在不同的系统中,打包的格式、方式和方法完全不同。
在Windows下,主要支持nsis
, nsis-web
(Web installer), portable
(portable app without installation), appx
, msi
, msi-wrapped
, squirrel
, 7z
, zip
, tar.xz
, tar.lz
, tar.gz
, tar.bz2
, dir
等各种安装包格式。其中,msi是微软自家提供的安装包格式,全称Microsoft Windows Installer。nsis是一款开源的安装包格式,portable是基于nsis制作的绿色自解压的双击即可运行的程序。appx
是Windows10以上版本系统应用商店支持的安装包格式,这种格式需要申请开发者账号并签名才可以。squirrel
也是一种开源的安装包格式,它不仅仅是一个安装包,还包含了一组工具和库,可以很方便的在VS中制作安装包,不过这种安装包已经很久没有更新了。其他的都是一些压缩包,解压后双击运行即可。
在Linux下主要支持AppImage
, flatpak
, snap
, deb
, rpm
, freebsd
, pacman
, p5p
, apk
, 7z
, zip
, tar.xz
, tar.lz
, tar.gz
, tar.bz2
, dir
等各种安装包格式。其中,deb
是Debian系发行版使用的安装包格式,rpm
是Redhat系发行版所使用的安装包格式。pacman
是Arch系使用的安装包格式。对于freebsd
、p5p
和apk
不甚了解,可能是FreeBSD、Solaris和安卓系统的安装包格式。AppImage
是一种应用程序镜像文件,它使用了容器技术,把程序及其运行时需要的库打包成一个镜像,这样在用户设备上运行时就不会再出现缺少依赖库的问题了。 flatpak
和 snap
跟AppImage
相似,都是为了解决包依赖问题而设计的,设计细节上略有不同而已。最大的不同是二者一个是redhat
设计的,另一个是ubuntu
设计的。不过,二者都需要安装运行时库才能运行。相较而言AppImage
更加通用,推荐使用。其余几种是压缩文件,跟Windows下一样,正常解压后即可双击运行。
在MacOS下主要支持default
, dmg
, mas
, mas-dev
, pkg
, 7z
, zip
, tar.xz
, tar.lz
, tar.gz
, tar.bz2
, dir
等各种安装包格式。default
是开源项目Squirrel.Mac
提供的一种开源的安装包格式。dmg
和pkg
是比较常见的MacOS下的安装包格式。mas
和 mas-dev
是苹果应用商店使用的安装包格式。其余都是压缩文件,跟Windows、Linux下一样,解压后双击运行即可。需要留意的是,MacOS下的安装文件是需要签名的,不签名无法进行分发。
默认情况下,不需要做任何改动,简单执行下面的命令即可完成打包:
npm run electron:build
打包好的文件默认会放到dist_electron
目录下面。如果你仅仅是写了一个最简单的demo程序,这样打包后是可以可以正常使用的。但是,我们不可能仅仅使用最近简单的demo。通常,我们会新增一些自己的文件,比如资源文件、依赖库等等。这就需要我们设置一些打包的参数。
例如,在demo4.1中,我们有一个名为preload.js
的脚本文件。Electron-builder
是不知道这个文件的存在的。如果我们不调整配置文件,打包后的安装包中就不包含这个文件。
打包程序的配置文件是vue.config.js
。注意,这个配置文件是Vue CLI Plugin Electron Builder
这个插件提供的,详细的信息说明见官方文档。但是,其官方文档没有介绍具体的配置项。这个部分又在Electron-builder
的官方当中。也就是说,配置的使用需要按照Vue CLI Plugin Electron Builder
的格式,配置Electron-builder
。
vue.config.js
的范例如下:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
pluginOptions: {
electronBuilder: {
preload: ["src/preload.js"],
builderOptions: {
asar: false,
extraResources: [{
from: "./src/logo.png",
to: "./app"
}],
linux: {
target: ["AppImage", "deb", "tar.gz"]
},
win: {
target: ["portable", "zip"]
},
macos: {
target: ["dmg"]
}
}
},
}
})
其中,
-
preload是用来告诉
Electron-Builder
预加载脚本是哪个,注意,预加载脚本可以有多个。 -
builderOptions是用来配置编译参数的。
-
asar:打包后的文件是否使用
asar
进行安全加固。 -
extraResources:是一些额外的资源文件或目录。
-
linux
、win
、macos
则是三个桌面系统专有的各种配置。需要注意,在不同的系统中,还有各种更加细节的配置项,细节太多了,此处不再一一展开讨论。建议仔细阅读官方的文档。
-
系列文章
- 什么是Electron
- 如何使用Electron
- Electron的基础知识
- 在Electron中使用Vue【当前文章】
- 关于Electron性能的讨论
- 在Electron中使用C++扩展