初探 Electron
教程将介绍 Electron 打包应用的全过程,从本地测试,打包,到 GitHub 自动化。讲解 Electron Forge 和 Electron Builder 的用法,以及如何在 GitHub Actions 中自动化生成和发布应用。
官方资源
- Electron Documentation
- Electron-builder 官方文档
- Electron-Forge 文档
- Electron-Forge 打包教程
Electron 通过 JavaScript、HTML 和 CSS 来构建跨平台的桌面应用。它通过将 Chromium 和 Node.js 集成到同一个运行时环境中,使开发者能够维护一个单一的代码库,并在 Windows、macOS 和 Linux 上运行。Electron 的设计消除了需要针对每个平台进行原生应用开发的复杂性。
类似工具
Tauri 是一个较新的框架,提供了更现代的技术栈和更高的安全性。Electron 由于其历史悠久和强大的社区支持,仍然保持着广泛的使用。以下是对两种工具的简要比较:
-
Electron:
- 优点: 社区庞大,支持广泛,文档丰富。
- 缺点: 性能开销较大,应用体积较大。
-
Tauri:
- 优点: 更小的资源占用,增强的安全性,允许更紧密地与系统原生功能集成。
- 缺点: 相对较新,社区和资源较少。
快速示例
以下是一个简单的 Electron 应用开发示例,包含创建过程和基础命令。
开发环境准备
系统版本信息:
❯ npm -v
6.14.18
❯ node -v
v20.11.0
npm
使用低版本,避免一些卡顿问题。
创建应用
示例使用 Vue 和 JavaScript:
npm create vite@latest electron-demo
项目的目录结构如下所示:
.
├── index.html
├── package.json
├── public
│ └── vite.svg
├── README.md
├── src
│ ├── App.vue
│ ├── assets
│ │ └── vue.svg
│ ├── components
│ │ └── HelloWorld.vue
│ ├── main.js
│ └── style.css
└── vite.config.js
4 directories, 10 files
最初考虑用 pnpm
来实践,但由发现 pnpm
对 Electron 的支持存在问题,暂时弃用,详情参阅:知乎文章。
安装与启动
建议配置 npm 镜像以加速下载过程:
# npm config set registry https://r.cnpmjs.org
npm install
npm run dev
安装 Electron 过程中的下载可能需要较长时间:
npm install electron
添加和修改 Electron 配置
这份代码可以参考官网给的 examples。
为了确保 Electron 应用能够正确地引用资源文件(如 CSS 和 JavaScript),需要对 vite.config.js
文件进行适当的修改。这包括设置资源的加载路径为相对路径,以预防文件找不到的问题。
修改 vite.config.js
如下:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 配置基本路径为相对路径
export default defineConfig({
base: './', // 确保打包后的资源可以正确加载
plugins: [vue()],
})
接下来,我们需要添加一个 main.js
文件,这个文件是 Electron 应用的入口,负责控制应用生命周期和创建原生浏览器窗口。
// main.js
// 控制应用生命周期和创建原生浏览器窗口的模组
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow () {
// 创建浏览器窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// 加载 index.html
mainWindow.loadFile('dist/index.html') // 此处跟electron官网路径不同,需要注意
// 打开开发工具
// mainWindow.webContents.openDevTools()
}
// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// 通常在 macOS 上,当点击 dock 中的应用程序图标时,如果没有其他
// 打开的窗口,那么程序会重新创建一个窗口。
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 因此,通常对程序和它们在
// 任务栏上的图标来说,应当保持活跃状态,直到用户使用 Cmd + Q 退出。
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// 在这个文件中,你可以包含应用程序剩余的所有部分的代码,
// 也可以拆分成几个文件,然后用 require 导入。
添加 preload.js
文件以在渲染进程中安全地使用 Node.js 模块:
// preload.js
// 所有Node.js API都可以在预加载过程中使用。
// 它拥有与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])
}
})
最后,更新 package.json
文件以包括新的启动脚本,使 Electron 能够运行。
{
"name": "electron-demo",
"private": true,
"version": "0.0.0",
"main": "main.js", // 新增
//"type": "module", 创建项目自带的这个要删除,否则会有问题
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"electron:serve": "electron ." //新增 electron运行命令
},
"dependencies": {
"electron": "^27.0.0",
"vue": "^3.3.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.3",
"vite": "^4.4.5"
}
}
打包和运行 Vue 项目
为了部署 Electron 应用,首先需要对 Vue 项目进行打包。这可以通过以下命令实现:
npm run build
打包完成后,通过下列命令启动 Electron 应用:
npm run electron:serve
应用运行效果如图所示:
热更新开发
为了提升开发效率,可以设置热更新,使得在开发过程中对代码的修改能够即时反映在 Electron 应用中。首先需要修改 main.js
文件中的内容加载方式,从加载本地文件改为加载开发服务器地址:
mainWindow.loadURL("http://localhost:5173") // 更改为开发服务器的 URL
为了确保 Electron 能够在 Vite 开发服务器启动后运行,需引入 concurrently
和 wait-on
两个 npm 包。concurrently
允许同时运行多个命令,而 wait-on
确保 Electron 在服务器可访问后再启动。
首先,安装这两个工具:
npm install -D concurrently wait-on
然后,更新 package.json
中的 scripts
部分,添加用于启动开发环境的命令:
"electron": "wait-on tcp:5173 && electron .", // 新增,等待端口5173
"electron:serve": "concurrently -k \"npm run dev\" \"npm run electron\"" // 新增,同时运行 Vite 和 Electron
现在,通过执行 npm run electron:serve
,Electron 应用将自动启动并加载 Vite 的开发服务器,实现实时的热更新功能。
环境分离和打包配置
在开发和生产环境中运行 Electron 应用通常需要不同的配置。特别是在涉及到资源加载方式时,比如开发环境中可能从本地服务器加载,而生产环境则从文件系统加载打包后的资源。
环境变量设置
为了在不同环境下切换配置,我们使用 NODE_ENV
环境变量来区分生产环境 (production
) 和开发环境 (development
)。您也可以根据需要配置额外的环境,如 release
。
首先,我们组织 Electron 相关的文件到一个单独的目录以便管理:
# 在项目根目录下操作
mkdir -p electron
mv main.js electron/
mv preload.js electron/
修改 main.js
文件以使用环境变量来决定加载的资源类型:
const { app, BrowserWindow } = require('electron')
const path = require('path')
const NODE_ENV = process.env.NODE_ENV // 获取环境变量
// const NODE_ENV = 'development' // 判断开发或生产模式(建议写成这种,开发模式就可以用,等即将打包了再把这个变量换成打包模式)
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// 根据环境变量决定加载的内容
mainWindow.loadURL(
NODE_ENV === 'development'
? 'http://localhost:5173'
: `file://${path.join(__dirname, '../dist/index.html')}`
)
// 在开发环境中自动打开开发者工具
if (NODE_ENV === "development") {
mainWindow.webContents.openDevTools()
}
}
更新 package.json
更新 package.json
来适应新的文件结构,并确保 NODE_ENV
在启动时正确设置:
{
"name": "electron-demo",
"private": true,
"version": "0.0.0",
"main": "electron/main.js", // 更新入口文件路径
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"electron": "wait-on tcp:5173 && electron .",
"electron:serve": "concurrently -k \"npm run dev\" \"npm run electron\""
},
"devDependencies": {
"electron": "^30.0.2",
"vue": "^3.4.21",
"@vitejs/plugin-vue": "^5.0.4",
"concurrently": "^8.2.2",
"vite": "^5.2.0",
"wait-on": "^7.2.0"
}
}
当设置环境变量 const NODE_ENV = 'development'
时,热更新效果:
应用打包
打包 Electron 应用之前,需确保已经安装了必要的库,以简化环境设置并支持跨平台打包:
- cross-env: 用于统一不同操作系统之间的环境变量设置。
- electron-builder: 助力将 Electron 应用打包成可分发的格式。
安装这些工具的命令如下:
npm install -D cross-env electron-builder
打包配置
接下来,在 package.json
中配置打包相关的参数,以确保应用按预期构建。
在 scripts
部分,添加用于一键打包的命令:
"electron:build": "vite build && electron-builder"
针对打包过程的详细配置如下所示:
"build": {
"appId": "com.dweb.electron-demo",
"productName": "ElectronDemo",
"copyright": "Copyright © 2024 Rex Wang",
"mac": {
"category": "public.app-category.utilities"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true
},
"files": [
"dist/**/*",
"electron/**/*"
],
"directories": {
"buildResources": "assets",
"output": "dist_electron"
}
}
配置详解:
- appId: 应用的全局唯一标识符,常用反向域名格式。
- productName: 应用的名称。
- copyright: 版权信息。
- mac/nsis: 平台特定的配置项,如 macOS 应用类别、Windows 安装程序配置等。
- files: 指定包含在最终应用包中的文件和目录。
- directories: 定义资源目录和输出目录,便于管理打包资源。
多平台打包
根据需要打包的平台,可以在 package.json
中设置特定的构建目标和体系结构:
- Mac: 支持 ARM 和 Intel 架构。
- Windows: 支持常见体系结构,可打包成安装程序或便携式应用。
- Linux: 支持
.deb
和.AppImage
格式。
例如,Mac 平台的配置示例:
"mac": {
"category": "public.app-category.utilities",
"target": [
{"target": "dmg", "arch": ["x64", "arm64"]},
{"target": "dir", "arch": ["x64", "arm64"]}
]
}
执行打包
通过下列命令启动打包过程:
npm run electron:build
打包工具会根据当前操作系统和设置的配置自动选择合适的打包方式。例如,ARM 架构的 Mac 输出如下:
• building target=macOS zip arch=arm64 file=dist_electron/ElectronDemo-0.0.0-arm64-mac.zip
• Detected arm64 process, HFS+ is unavailable. Creating dmg with APFS - supports Mac OSX 10.12+
完成打包后,dist_electron
目录下将包含所有生成的文件,例如 Mac 平台的输出结构如下所示:
dist_electron
├── ElectronDemo-0.0.0-arm64.dmg
├── ElectronDemo-0.0.0.dmg
├── mac
│ └── ElectronDemo.app
└── mac-arm64
└── ElectronDemo.app
.app
文件可直接运行,而 .dmg
文件提供了标准的安装流程。类似地,Linux 平台会生成 .AppImage
和其他分发格式。由于 Electron 应用内嵌了浏览器,打包文件的体积通常较大,例如 Linux 和 Mac 平台的 .AppImage/.dmg
文件大小通常在 100MB 左右。
小结
本例使用 Electron 框架将一个 Vue.js 项目转换成一个跨平台的桌面应用。
关键步骤回顾:
- 初始化:创建项目,打包运行,并用 Electron 运行
- 热更新开发:设置热更新,利用环境变量和配置文件适配开发和生产环境
- 打包与分发:使用
electron-builder
和相关工具,将应用打包成可分发的格式,支持多平台发布。
简单来说,在原项目基础上,安装 Electron 依赖,并添加配置文件 main.js, preload.js
然后打包构建。
接下来部分是介绍 Electron Forge,一个更常用的打包利器。