Electron的安装与使用
一、Electron的安装
环境配置:必须有Node.js和NPM包管理器
(1)使用脚手架创建
-
创建文件夹命令:
mkdir my-electron-app && cd my-electron-app
-
运行完后出现该名称的文件夹:
-
初始化:
npm init
-
初始化后文件夹中出现package.json文件:
-
package.jason文件中的内容:
- 将 electron 包安装到应用的开发依赖中:
npm install --save-dev electron
- 安装完成后出现以下内容:
-
启动electron:
"scripts": { "start": "electron"},
-
根目录下新建index.html文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>你好!</title>
</head>
<body>
<h1>你好!</h1>
我们正在使用 Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
和 Electron <span id="electron-version"></span>.
</body>
</html>
- 窗口中打开页面: 需用到两个electron模块:app、BrowserWindow,在新建的main.js文件中导入:
// 这里是CommonJS模块
const { app, BrowserWindow } = require('electron')
/* 窗口控件功能 start */
// 添加一个createWindow()方法来将index.html加载进一个新的BrowserWindow实例
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
// 调用createWindow()函数来打开您的窗口
win.loadFile('index.html')
}
// 通过app.whenReady() API来监听在 app 模块的 ready 事件是否被激发,激发后才能创建浏览器窗口即调用createWindow()
app.whenReady().then(() => {
createWindow()
// 如果没有窗口打开则打开一个窗口 (macOS)
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 关闭所有窗口时退出应用(Windows & Linux)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
/* 窗口控件功能 end */
app 模块,它控制应用程序的事件生命周期
BrowserWindow 模块,它创建和管理应用程序 窗口
- 通过终端打开electron进程:
npm start
(2)electron的使用
- 预加载: 新建preload.js文件,在该文件中添加以下代码
// 通过预加载脚本从渲染器访问Node.js (并在BrowserWindow构造器中的预加载脚本中传入webPreferences.preload选项)
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
- 在main.js文件中新增webPreferences.preload选项:
const { app, BrowserWindow } = require('electron')
// 在文件的顶部包含Node.js的'path'模块 (为预加载使用)
const path = require('path')
// 预加载时 修改现有的createWindow()函数
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
}
// ...
Node.js中的概念:
(1)__dirname:字符串指向当前正在执行脚本的路径 (在本例中,它指向你的项目的根文件夹)
(2)path.join:API将多个路径联结在一起,创建一个跨平台的路径字符串
- 新建renderer.js文件:
// 在index.html中的body标签结束前引入(将功能添加到网页内容中)
<script src="./renderer.js"></script>
- 接下来的开发过程可使用Webpack打包、使用React构建用户界面,至此Electron程序的功能就齐全了: 如下图所示
- 完整代码:
// main.js
// electron 模块可以用来控制应用的生命周期和创建原生浏览窗口
const { app, BrowserWindow } = require('electron')
const path = require('path')
const createWindow = () => {
// 创建浏览窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// 加载 index.html
mainWindow.loadFile('index.html')
// 打开开发工具
// mainWindow.webContents.openDevTools()
}
// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
// 在 macOS 系统内, 如果没有已开启的应用窗口
// 点击托盘图标时通常会重新创建一个新窗口
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 因此, 通常
// 对应用程序和它们的菜单栏来说应该时刻保持激活状态,
// 直到用户使用 Cmd + Q 明确退出
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
// 在当前文件中你可以引入所有的主进程代码
// 也可以拆分成几个文件,然后用 require 导入。
// preload.js
// 所有的 Node.js API接口 都可以在 preload 进程中被调用.
// 它拥有与Chrome扩展一样的沙盒。
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
<!--index.html-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>你好!</title>
</head>
<body>
<h1>你好!</h1>
我们正在使用 Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
和 Electron <span id="electron-version"></span>.
<!-- 您也可以此进程中运行其他文件 -->
<script src="./renderer.js"></script>
</body>
</html>
(3)总结
- 启动一个Node.js程序,并将Electron添加为依赖
- 创建了一个 main.js 脚本来运行主要进程,它控制应用程序 并且在 Node.js 环境中运行。 在此脚本中, 使用 Electron 的 app 和 BrowserWindow 模块来创建一个浏览器窗口,在一个单独的进程(渲染器)中显示网页内容
- 为了访问渲染器中的Node.js的某些功能,在 BrowserWindow 的构造函数上附加了一个预加载脚本
二、打包并分发应用程序(通过Electron Forge打包)
-
安装Electron Forge:
npm install --save-dev @electron-forge/cli
-
使用其"import"命令设置 Forge 的脚手架:
npx electron-forge import
注意:执行该命令时不要边跑项目边执行,会报错,先将项目停掉再执行该命令
该命令的作用是修改package.json的开发依赖并安装上依赖
- 执行完以上命令后,会出现以下forge.js文件:
- 使用 Forge 的 make 命令来创建可分发的应用程序:
npm run make
执行npm run make时报错,在package.json中找到main的位置发现用的是main: main.js
随后找了一圈发现是使用的npx安装的,国内的cnpm用不上,只能用npm run make,最后通过修改package.json文件打包成功
- 修改package.json文件后打包成功: 先手动设置package.json中的环境变量,再使用
npm install --save-dev @electron-forge/cli
进行安装,最后进行npm run make打包成功
// 修改后的package.json文件
{
"name": "problem-test",
"version": "1.0.0",
"author": {
"name": "canals"
},
"description": "demo-electron",
"main": "main.js",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"e-start": "electron ."
},
"devDependencies": {
"@electron-forge/cli": "^6.2.1",
"@electron-forge/maker-deb": "^6.0.0-beta.65",
"@electron-forge/maker-rpm": "^6.0.0-beta.65",
"@electron-forge/maker-squirrel": "^6.0.0-beta.65",
"@electron-forge/maker-zip": "^6.0.0-beta.65",
"electron": "^20.1.0"
},
"dependencies": {
"electron-squirrel-startup": "^1.0.0"
},
"config": {
"forge": {
"packagerConfig": {},
"makers": [
{
"name": "@electron-forge/maker-squirrel",
"config": {
"name": "electron_demo"
}
},
{
"name": "@electron-forge/maker-zip",
"platforms": [
"darwin"
]
},
{
"name": "@electron-forge/maker-deb",
"config": {}
},
{
"name": "@electron-forge/maker-rpm",
"config": {}
}
]
}
}
}
// 原package.json文件
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@electron-forge/cli": "^6.2.1",
"@electron-forge/maker-deb": "^6.2.1",
"@electron-forge/maker-rpm": "^6.2.1",
"@electron-forge/maker-squirrel": "^6.2.1",
"@electron-forge/maker-zip": "^6.2.1",
"@electron-forge/plugin-auto-unpack-natives": "^6.2.1",
"electron": "^25.1.1"
},
"dependencies": {
"electron-squirrel-startup": "^1.0.0"
}
}
- 打包后的文件: 软件包可在out文件夹中找到
三、如何在VSCode中跑Electron项目
- 使用
npm run make打包后,再使用npm run start/npm start启动程序
这样就能看到你开发后的效果了
四、使用VSCode调试
- 新建.vscode - > launch.json:
{
"version": "0.2.0",
"compounds": [
{
"name": "Main + renderer",
"configurations": ["Main", "Renderer"],
"stopAll": true
}
],
"configurations": [
{
"name": "Renderer",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}"
},
{
"name": "Main",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal"
}
]
}
- 点击侧边栏的运行和调试 -> 出现Main + renderer选项 -> 可设置断点 ->跟踪主进程和渲染器进程中的所有变量
五、进程间通信
- 预处理脚本中设置:
// 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')
// we can also expose variables, not just functions
})
- 在main.js中设置:
// main.js
// 取出ipcMain进行进程间的通信
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')
}
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
// 调用handle
ipcMain.handle('ping', () => 'pong')
createWindow()
})
- renderer.js进程:
// renderer.js
const func = async () => {
const response = await window.versions.ping()
console.log(response) // 打印 'pong'
}
func()
- 通信成功:
六、发布与更新
- 安装模块:
npm install --save-dev @electron-forge/publisher-github
- 在Forge中配置发布者:
// forge.config.js
module.exports = {
packagerConfig: {
asar: true,
},
rebuildConfig: {},
makers: [
{
name: "@electron-forge/maker-squirrel",
config: {},
},
{
name: "@electron-forge/maker-zip",
platforms: ["darwin"],
},
{
name: "@electron-forge/maker-deb",
config: {},
},
{
name: "@electron-forge/maker-rpm",
config: {},
},
],
plugins: [
{
name: "@electron-forge/plugin-auto-unpack-natives",
config: {},
},
],
publishers: [
{
name: '@electron-forge/publisher-github',
config: {
repository: {
owner: 'github-user-name',
name: 'github-repo-name'
},
prerelease: false,
draft: true
}
}
]
};
- 添加发布命令:
// package.json
{
"name": "problem-test",
"version": "1.0.0",
"author": {
"name": "canals"
},
"description": "demo-electron",
"main": "main.js",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"e-start": "electron .",
"publish": "electron-forge publish"
},
"devDependencies": {
"@electron-forge/cli": "^6.2.1",
"@electron-forge/maker-deb": "^6.0.0-beta.65",
"@electron-forge/maker-rpm": "^6.0.0-beta.65",
"@electron-forge/maker-squirrel": "^6.0.0-beta.65",
"@electron-forge/maker-zip": "^6.0.0-beta.65",
"@electron-forge/publisher-github": "^6.2.1",
"electron": "^20.1.0"
},
"dependencies": {
"electron-squirrel-startup": "^1.0.0"
},
"config": {
"forge": {
"packagerConfig": {},
"makers": [
{
"name": "@electron-forge/maker-squirrel",
"config": {
"name": "electron_demo"
}
},
{
"name": "@electron-forge/maker-zip",
"platforms": [
"darwin"
]
},
{
"name": "@electron-forge/maker-deb",
"config": {}
},
{
"name": "@electron-forge/maker-rpm",
"config": {}
}
]
}
}
}
- 运行发布命令:
npm run publish