Electron基础

本文最后更新于:2023年10月10日 晚上

环境配置

安装node

首先安装node
官方下载最新版本:https://nodejs.org/en/download
官方下载历史版本:https://nodejs.org/en/download/releases
根据系统下载相应系统的 node 文件,选择 LTS 版本
Windows 下载 64 位 Windows Installer (.msi),MAC 下载 node-v18.18.0.pkg

安装好了执行以下命令查看 node 版本和 npm 版本

1
2
3
4
5
➜  electron_demo node -v
v16.13.2 #我的node版本
➜ electron_demo npm -v
8.1.2 #我的npm版本
➜ electron_demo

安装electron

新建一个文件夹electron_demo,进入文件夹npm init -y

1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "electron_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

安装electron

1
2
3
4
# npm安装
npm install --save-dev electron
# yarn安装
yarn add --dev electron

增加运行命令

1
2
3
4
}
"scripts": {
"dev": "electron ."
}

新建主进程 index.js
任何 Electron 应用程序的入口都是 main 文件。
这个文件控制了主进程,它运行在一个完整的 Node.js 环境中,负责控制您应用的生命周期,显示原生界面,执行特殊操作并管理渲染器进程

新建 index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>hello world</title>
</head>
<body>
<h1>hello world</h1>
<h2>首次加载</h2>
<script src="./renderer.js"></script>
</body>
</html>

新建 index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// main.js

// Modules to control application life and create native browser window
const { app, BrowserWindow } = require("electron");
const path = require("node:path");

const createWindow = () => {
// Create the browser window.
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 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]);
}
});

自动重启

1
npm install -D nodemon

并修改 package.json 文件

1
2
3
4
5
6
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon --exec electron ."
},
...

然后添加 nodemon.json 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
{
"ignore": [
"node_modules",
"dist"
],
"colours": true,
"verbose": true,
"watch": [
"*.*"
],
"ext": "html,js,css"
}

主进程设置窗口的位置,并且让窗口置顶,这样不会遮挡vscode编辑器和位置

1
2
3
4
5
6
7
8
9
10
11
12
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
//一直置顶
alwaysOnTop: true,
//启动后的位置
x: 1200,
y: 100,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
});

安全策略

因为 Electron 项目可以执行javascript代码,也可以访问用户电脑的文件系统,所以访问任何不受信任的内容都可能带来安全隐患。

错误报告

image-20231009211059373

CSP

内容安全策略(CSP) 是应对跨站脚本攻击和数据注入攻击的又一层保护措施。 我们建议任何载入到Electron的站点都要开启。

1
2
3
4
<!-- 访问内容均来自项目资源 -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
<!-- 允许访问 *.pythl.com 和 tanghailong.com 源内容-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self' *.tanghailong.com; script-src '*.pythl.com'" />

打包分发应用程序

最快捷的打包方式是使用 Electron Forge

1
2
3
4
5
6
7
8
9
10
11
12
13
npm install --save-dev @electron-forge/cli

➜ electron_demo npx electron-forge import
✔ Checking your system
✔ Locating importable project
✔ Processing configuration and dependencies
✔ Installing dependencies
✔ Copying base template Forge configuration
✔ Fixing .gitignore
✔ Finalizing import

› We have attempted to convert your app to be in a format that Electron Forge understands.
Thanks for using Electron Forge!

使用 Forge 的 make 命令来创建可分发的应用程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
➜  electron_demo git:(master) ✗ npm run make

> electron_demo@1.0.0 make
> electron-forge make

✔ Checking your system
✔ Loading configuration
✔ Resolving make targets
› Making for the following targets: zip
✔ Running package command
✔ Preparing to package application
✔ Running packaging hooks
✔ Running generateAssets hook
✔ Running prePackage hook
✔ Packaging application
✔ Packaging for arm64 on darwin [2s]
✔ Running postPackage hook
✔ Running preMake hook
✔ Making distributables
✔ Making a zip distributable for darwin/arm64 [8s]
✔ Running postMake hook
› Artifacts available at: /Users/wslh/electron_demo/out/make
➜ electron_demo git:(master) ✗ npm run make

> electron_demo@1.0.0 make
> electron-forge make

✔ Checking your system
✔ Loading configuration
✔ Resolving make targets
› Making for the following targets: zip
✔ Running package command
✔ Preparing to package application
✔ Running packaging hooks
✔ Running generateAssets hook
✔ Running prePackage hook
✔ Packaging application
✔ Packaging for arm64 on darwin [2s]
✔ Running postPackage hook
✔ Running preMake hook
✔ Making distributables
✔ Making a zip distributable for darwin/arm64 [7s]
✔ Running postMake hook
› Artifacts available at: /Users/wslh/electron_demo/out/make

最后 package.json 内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"name": "electron_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@electron-forge/cli": "^6.4.2",
"@electron-forge/maker-deb": "^6.4.2",
"@electron-forge/maker-rpm": "^6.4.2",
"@electron-forge/maker-squirrel": "^6.4.2",
"@electron-forge/maker-zip": "^6.4.2",
"@electron-forge/plugin-auto-unpack-natives": "^6.4.2",
"electron": "26.3.0"
},
"dependencies": {
"electron-squirrel-startup": "^1.0.0"
}
}

项目目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
➜  electron_demo git:(master) ✗ tree -L 3 -I "node_modules"
.
├── forge.config.js
├── index.html
├── index.js
├── out
│ ├── electron_demo-darwin-arm64
│ │ ├── LICENSE
│ │ ├── LICENSES.chromium.html
│ │ ├── electron_demo.app
│ │ └── version
│ └── make
│ └── zip
├── package-lock.json
├── package.json
└── preload.js

打开打包的软件

image-20231008221614338

调试配置

下面介绍在vscode中调试electron项目,微软有一个仓库 vscode-recipes提供了vscode的 launch.json 常用开发语言的配置。

首先在 vscode 中创建 launch.json 文件,Mac(commad+shift+d),windows(ctrl+shift+d),选择 node

image-20231009210017549

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Electron: Main",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"runtimeArgs": [
"--remote-debugging-port=9223",
"."
],
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
}
},
{
"name": "Electron: Renderer",
"type": "chrome",
"request": "attach",
"port": 9223,
"webRoot": "${workspaceFolder}",
"timeout": 30000
}
],
"compounds": [
{
"name": "Electron: All",
"configurations": [
"Electron: Main",
"Electron: Renderer"
]
}
]
}

image-20231009210104093

image-20231009210206574

多进程模型

Electron 将使用两种类型的进程:主进程ipcMain渲染器进程ipcRenderer

主进程

每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有使用 Node.js API 的能力。

主进程的主要目的是使用 BrowserWindow模块创建和管理应用程序窗口。

渲染器进程

每个 Electron 应用都会为使用 BrowserWindow 打开的窗口生成一个单独的渲染器进程。

默认情况下渲染进程与主进程使用 preload.js预加载做为通信桥梁。

预加载脚本

预加载(preload)脚本包含了那些执行于渲染进程中,且先于网页内容开始加载的代码 。这些脚本虽运行于渲染器的环境中,却因能访问有限的 Node.js、Electron高级权限。

因为Electron项目与其他桌面应用是有区别的,他具有浏览器的特性,所以开放主进程的node.js给渲染进程,是有安全隐患的。默认electron是不会开放高级权限给渲染进程,而是要求开发者自行决定渲染进程可以使用哪些主进程任务,这块功能就要在预加载脚本中完成。

预加载脚本像一个桥接器,用于渲染脚本renderer.js与main.js脚本的连接。

d


Electron基础
https://pythl.com/archives/9b837f62.html
作者
晚生隆海
发布于
2023年10月8日
更新于
2023年10月10日
许可协议