/(ㄒoㄒ)/~~报名了两个新星计划,工作之余写博客……
另外一个是uniapp的属于个人兴趣,这个桌面应用正好符合工作需要。
活动地址:https://marketing.csdn.net/p/1738cda78d47b2ebb920916aab7c3584
教程地址:
2023新星导师活动【electron+vue3】方向,开营知识点提纲(1)_中二少年学编程的博客-CSDN博客
快速入门 | Electron
之前用uniapp做h5,再用Electron做确实编译出一个exe文件,但之后领导并没有把这个需求让我实现,嗯……所以并没有深入研究,这回也是简单学习下。
vue2文档地址:Vue.js
electron文档地址:简介 | Electron
vue2有点基础,所以跳过。
Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架,嵌入Chromium和Node.js。
开发时,本地必须安装Node.js。
Electron 将 Node.js 嵌入到其二进制文件中,应用运行时的 Node.js 版本与系统中运行的 Node.js 版本无关。
//创建应用
npm init
npm install --save-dev electron
//或者 npm install -g electron 全局安装
//运行
npm start
//编译 百度后的结果 试过之后确实编译成功 并可正常运行编译结果
electron-packager .
应用名
--platform=win32
--electron-version=10.0.0
--arch=x64
--download.mirrorOptions.mirror=https://npm.taobao.org/mirrors/electron/
--asar
--app-version=0.0.0
--build-version=0.0.0
--out=输出文件名字
--overwrite
--no-package-manager
--ignore="(.git)"
--icon=ico图标文件
编译设置
https://npm.taobao.org/mirrors/electron/
是为了加快编译速度,electron-version要和上述网址中的内容对应,不然报错。
第一次编译的时候写成:electron-version=1.0.0,大概是报错这个版本找不到。
官方给的样例为:GitHub - electron/electron-quick-start: Clone to try a simple Electron app
用过vue的大概都知道,vue的脚手架的使用方法,electron有个类似的electron forge。
Electron Forge 官网:Getting Started - Electron Forge
//安装 未安装的情况
cd 项目
npm install --save-dev @electron-forge/cli
npx electron-forge import
//安装依赖
npm install --save-dev @electron-forge/cli
@electron-forge/maker-squirrel
@electron-forge/maker-deb
@electron-forge/maker-zip
//创建项目
npm init electron-app@lastest myapp
//使用模板
npm init electron-app@lastest myapp2
--
--template=webpack//可选 webpack 和 webpack-typescript
//启动
cd 项目名
npm start
//编译
npm run make
另外说一句,Node.js新版npm操作后直接写入package.json,--save这种写法貌似是针对旧版不写入package.json中。
官方建议做windows app的时候,建议安装electron-squirrel-startup。
//安装
cd my-app
npm install electron-squirrel-startup
//使用 mian.js中处理
if (require('electron-squirrel-startup'))
app.quit();
官网上有其配置和cli的详细解说,都是纯英文的,/(ㄒoㄒ)/~~ 能力有限就不翻译了。
看官网教程,还贴心的具体指出nodejs的官方文档 :Introduction to Node.js
Electron 的主进程是一个拥有着完全操作系统访问权限的 Node.js 环境,渲染进程跑在网页中,
为了将 Electron 的不同类型的进程桥接在一起,需要使用被称为 预加载 的特殊脚本。
preload.js为预加载脚本。
BrowserWindow 的预加载脚本运行在具有 HTML DOM 和 Node.js、Electron API 的有限子集访问权限的环境中。
从 Electron 20 开始,预加载脚本默认 沙盒化 ,不再拥有完整 Node.js 环境的访问权,意味着只拥有一个 polyfilled 的 require
函数,这个函数只能访问一组有限的 API。
//preload.js 内容
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron,
// 能暴露的不仅仅是函数,我们还可以暴露变量
})
//加载 main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
_dirname字符串指向当前正在执行的脚本的路径,上面应该是根路径。
path.join是Node.js提供的api:Path | Node.js v20.2.0 Documentation
既然是多进程嘛,就涉及进程之间通信问题。
IPC指进程之间通信,可以使用 Electron 的 ipcMain
模块和 ipcRenderer
模块来进行进程间通信
为了从网页向主进程发送消息,使用 ipcMain.handle
设置一个主进程处理程序(handler),然后在预处理脚本中暴露一个被称为 ipcRenderer.invoke
的函数来触发该处理程序(handler)。
//preload.js 暴露函数
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron,
ping: () => ipcRenderer.invoke('ping'),
// 能暴露的不仅仅是函数,我们还可以暴露变量
})
//main.js 函数定义
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
ipcMain.handle('ping', () => 'pong')
win.loadFile('index.html')
}
app.whenReady().then(createWindow)
//index.html
来自 Electron 渲染器的问好!
来自 Electron 渲染器的问好!
//renderer.js 使用函数 index.html里包含并运行这个文件
const func = async () => {
const response = await window.versions.ping()
console.log(response) // 打印 'pong'
}
func()
根据上面例子,运行起来的话控制台应该打印pong。总体来讲,就是监听、注册、运行。
根据官网,暴露的时候使用ipcRenderer.invoke('ping'),而不直接暴露ipcRenderer,因为ipcRenderer直接暴露会导致渲染器能够直接向主进程发送任意的 IPC 信息,会使得其成为恶意代码最强有力的攻击媒介。
在主进程中设置监听器在主进程中需要保证加载完后运行。
官网专门讲进程通信:进程间通信 | Electron
根据上一行官网内容,发现还有其他方法做交互。
语境隔离(Context Isolation)意味着预加载脚本与渲染器的主要运行环境是隔离开来的,以避免泄漏任何具特权的 API 到您的网页内容代码中。我们將使用 contextBridge 模块来安全地实现交互。
//preload.js
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
desktop: true,
})
//renderer.js
const func = async () => {
console.log(window.myAPI)//打印{ desktop: true }
}
func()
官网解释utilityProcess为效率进程,用于主进程调用子进程,也有一套子进程通讯的api。
官网地址:
utilityProcess | Electron
MessagePortMain | Electron
// 主进程
const { port1, port2 } = new MessageChannelMain()
//utilityProcess.fork(子进程入口)
const child = utilityProcess.fork(path.join(__dirname, 'test.js'))
//postmessage 参数: 1、数据 2、MessagePortMain[] 数据可选 数据大概是端口
//根据文档第二个参数用于权限转移 数据大概是端口
//child大概是个MessagePortMain对象
child.postMessage({ message: 'hello' }, [port1])
// Child process
process.parentPort.once('message', (e) => {
const [port] = e.ports
})