Electron 桌面开发 - 笔记 📒

Siona

传统桌面端应用开发

  • 原生开发
    • 直接将语言编译成可执行文件
    • 直接调用系统 API,完成 UI 绘制
    • 运行效率高
    • 对技术要求高,导致开发速度慢
    • 例如:开发 Windows 应用,需要使用 C++、MFC、QT 等;开发 MacOs 应用,需要使用 Swift 语言
  • 托管平台
    • 一次编译后,得到中间文件,通过平台或者虚拟机完成二次加载编译或解释运行
    • C#、.Net、Framework 开发 Windows 应用
    • Java、Swing

Electron 桌面开发

Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到二进制的 Electron 允许您保持一个 JavaScript 代码代码库 并创建在 Windows 上运行的跨平台应用 macOS 和 Linux —— 不需要本地开发经验。

  • GitHub 开源的框架
  • 构建扩平台桌面应用程序
  • 最初是和 Atom 编辑器 于 2014 开源
  • 使用 Electron 开发的应用:postman、语雀等
  • 适用场景
    • 特定的领域软件(POS 机、财务软件、开发者工具、打印场景等,用到系统能力)
    • 同时开发 Web + 桌面应用

Electron 核心技术

img_1.png
img_1.png
Electron 核心技术.png
Electron 核心技术.png
  • Electron 等于

    • chromium(Chrome 实验版)
    • NodeJS(操作系统底层 API 能力 —— path、fs)
    • Native API(调用原生应用程序接口)
  • Electron 优势

    • 兼容性:可以使用最新的 API 和语法;不需要考虑浏览器的样式和代码兼容性
    • NodeJS:使用 npm 模块,可直接调用系统 API 操作文件
    • 跨域:使用 request 模块发起网络请求
  • Electron 劣势

    • 应用体积过大:使用 NodeJS 开发、electron-builder 打包等导致应用体积较大
    • 支持度:某些功能受限(例如,无法获取系统文件中选中的文件状态,必须调用相应接口才能实现)
    • 性能:CPU 密集型应用性能较差

Electron 基本原理

Chromium 浏览器原理.png
Chromium 浏览器原理.png
Electron 架构.png
Electron 架构.png

可参考文章:

electron 应用开发优秀实践open in new window

Electron 生命周期

Electron 生命周期.png
Electron 生命周期.png

Electron + Vite + Vue 实战

Electron 依赖安装

 npm install electron --save-dev
 npm install electron-builder --save-dev
 npm install @electron/remote --save-dev

npm 安装 Electron 报错

npm 安装 Electron 报错.png
npm 安装 Electron 报错.png

报错原因:镜像问题

  • npm 的镜像,不要使用淘宝镜像;
  • electron 的镜像,官方文档未提及 🥲
# ① 打开 npm 的配置文件
npm config edit

# ② 配置镜像
registry=https://registry.npmmirror.com
electron_mirror=https://cdn.npmmirror.com/binaries/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/

# ③ 关闭该窗口,重启命令行,删除 node_modules 文件夹,并执行下面命令清除缓存,再重新安装依赖
npm cache clean --force

# OK 啦~
siona@Sionas-MacBook-Pro electron-study % npm install electron --save-dev

added 120 packages in 21s

npm 配置文件.png
npm 配置文件.png

📢 或者,不修改 npm 配置文件,而是在项目中创建 .npmrc 文件进行设置 electron 镜像地址。 .npmrc 文件配置镜像地址.png

Electron 启动报错

Electron 启动报错.png
Electron 启动报错.png
/Users/siona/.nvm/versions/node/v20.10.0/bin/npm run start

> electron-study@0.0.0 start
> electron .

2024-03-24 17:36:15.481 Electron[17602:951417] WARNING: Secure coding is automatically enabled for restorable state! However, not on all supported macOS versions of this application. Opt-in to secure coding explicitly by implementing NSApplicationDelegate.applicationSupportsSecureRestorableState:.

解决方法: package.json 文件中需配置 main.png

# 报错
ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and '/Users/siona/Documents/WorkSpaces/WebstormProjects/electron-study/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.

# 解决方法:去掉 package.json 中的参数 "type": "module" 即可。

Electron 启动成功效果

图中效果是由于设置了 win.webContents.openDevTools(); 开启控制台(便于调试)。 Electron 启动成功.png

nodemon

监控 js 文件变更,不需要修改 main.js 等文件之后,重新启动项目。

nodemon 官网open in new window

npm 全局安装 nodemon.png
npm 全局安装 nodemon.png
// ① 创建 nodemon.json 文件
// 简单使用:监控 js 文件变化
{
  "options": {
    "extensions": ["js"]
  }
}

// ② 修改 package.json 启动脚本
"scripts": {
  "start": "nodemon --exec electron .",
}
# 控制台:nodemon 实际效果,修改了 main.js 中 electron browser window 的 width
> electron-study@0.0.0 start
> nodemon --exec electron .

[nodemon] 3.1.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `electron .`
[nodemon] restarting due to changes...
[nodemon] starting `electron .`

preload 预加载

主进程可以通过 NodeJS 访问系统 API,但是不能读取 DOM。

  • preload 能够在渲染器进程加载之前加载,并且能够有权访问两个渲染器全局(window、document)node 环境。
// ① 创建 preload.js 文件


// ② 在 main.js 主进程中引入 preload.js 文件
// 此处,只贴出关键代码,请注意!
const path = require("path");
win = new BrowserWindow({
  width: 900,
  height: 600,
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
  }
});

小 demo

界面中显示 node 版本、chromium 版本、electron 版本。

// index.html
<body>
  chrome 版本:<span id="chrome-version"></span><br/>
  node 版本:<span id="node-version"></span><br/>
  electron 版本:<span id="electron-version"></span>
  <script src="./renderer.js"></script>
</body>

// main.js 主进程
const {app, BrowserWindow} = require("electron");
const path = require("path");

let win;
const createWindow = () => {
  win = new BrowserWindow({
    width: 800,
    heigth: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js');
    },
  });

  win.loadFile('index.html');
  win.webContents.openDevTools();  // 开启控制台,便于调试

  // 导航完成时触发
  win.webContents.on('did-finish-load', () => {
    win.webContents.send('msg', '消息来自主进程');
  });

};

app.whenReady().then(createWindow);


// preload.js 预加载文件
window.addEventListener('DOMContentLoaded', () => {
  const replaceText = (selector, text) => {
    const element = document.getElementById(selector);
    if (element) {
      element.innerText = text;
    }
  };
  console.log('versions', process.versions);
  for (const dependency of ['chrome', 'node', 'electron']) {
    replaceText(`${dependency}-version`, process.versions[dependency]);
  }
});

效果图:

进程间通信.png
进程间通信.png

进程间通信

主进程(main.js)主动向渲染进程(renderer.js)发送消息 win.webContents.send()

// main.js 主进程
const {app, BrowserWindow} = require("electron");
const path = require("path");

let win;
const createWindow = () => {
  win = new BrowserWindow({
    width: 800,
    heigth: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      // 配置 node 能力
      nodeIntegration: true,
      contextIsolation: false,
    },
  });

  win.loadFile('index.html');
  win.webContents.openDevTools();  // 开启控制台,便于调试

  // 导航完成时触发
  win.webContents.on('did-finish-load', () => {
    win.webContents.send('msg', '消息来自主进程');
  });

};

app.whenReady().then(createWindow);



// renderer.js 渲染进程
// 通过 ipcRenderer 来监听消息
const {ipcRenderer} = require("electron");

ipcRenderer.on('msg', (event, message) => {
  alert(message);
});

渲染进程主动向主进程发送消息


扩展

Electron 不支持 Windows XP,NW 支持。

Last Updated 3/31/2024, 6:49:24 AM