Electron 打包实战指南
项目背景与解决的问题
这个模板的诞生,源于一个在 Web 开发中普遍存在的痛点:终端用户环境的不可控性。
我的 Web 应用需要面对用户参差不齐的电脑环境,尤其是在一些场景下,Windows 7 系统仍有不小的占有率。这意味着,应用可能会被迫运行在一些内核版本极低或小众的浏览器上,从而引发各种难以预料的兼容性问题和 bug。
与其被动地去适配无数种未知的浏览器环境,我想到,不如主动为我的应用提供一个稳定、统一的运行环境。所以我想到了Electron。因为如果可以直接给win7用户丢一个项目的桌面端应用会比直接让用户听我指挥换一个其它浏览器更容易接受 且能解决谷歌浏览器 edg 等不支持 win7 的问题。
本项目选择 Chromium 132 作为内核基座。这个选择并非随意而为。我发现最新的、能在 Windows 7 上稳定运行的 360 安全浏览器,其内核正是 Chromium 132。既然我的应用在该浏览器上表现良好,那么直接采用同款内核,就为应用的兼容性和稳定性提供了最可靠的保障。
第一部分:从零搭建一个最简 Electron 应用
在开始使用我们这个完整的模板之前,我们先来"热个身"。通过亲手搭建一个最基础的 Electron 应用,你会对它的工作原理有一个非常直观的认识。这就像学习盖房子前,先了解一下砖块和水泥是什么。
1. 创建项目目录
首先,为你的新项目创建一个文件夹,并初始化一个 package.json
文件。
bash
mkdir my-electron-app
cd my-electron-app
npm init -y
2. 安装 Electron
接下来,将 Electron 框架作为开发依赖项添加到你的项目中。
bash
npm install --save-dev electron
3. 创建主进程文件 (main.js
)
每个 Electron 应用都有一个"大脑",也就是主进程。它负责创建应用窗口,并管理所有系统级别的交互。我们把它命名为 main.js
。
javascript
// main.js
const { app, BrowserWindow } = require('electron');
function createWindow() {
// 创建一个 800x600 的窗口
const win = new BrowserWindow({
width: 800,
height: 600
});
// 让窗口加载我们的 HTML 页面
win.loadFile('index.html');
}
// 当 Electron 准备好后,就创建窗口
app.whenReady().then(createWindow);
4. 创建界面文件 (index.html
)
"大脑"需要一个"面孔"来展示给用户。这就是我们的 index.html
文件。
html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>你好,我的第一个桌面应用!</h1>
</body>
</html>
5. 启动应用
最后,我们需要告诉项目如何启动。打开 package.json
,找到 "scripts"
部分,添加一个 start
命令。
json
{
"scripts": {
"start": "electron ."
}
}
同时,确保 package.json
中有 "main": "main.js"
这一行,它告诉 Electron 哪个文件是主进程的入口。
现在,见证奇迹的时刻到了!
bash
npm start
一个桌面窗口弹了出来,对吗?恭喜你,你已经完成了你的第一个 Electron 应用!
第二部分:升级为配置驱动的完整模板
完整项目 : 如果你想直接查看或使用最终的完整项目代码,可以从这里获取: github.com/xiaoshengwp...
热身结束!现在,让我们看看这个模板的真正威力所在。你会发现,它在刚才的基础上,引入了"配置驱动"的工程化思想,帮你解决了许多实际问题。
为什么要升级?
在刚才的 "Hello World" 中,窗口大小 800x600
和要加载的文件 index.html
都是硬编码 在 main.js
里的。如果想换个 URL 或者调整窗口尺寸,你就必须去修改代码。这在需要频繁切换开发/生产环境时,会变得非常繁琐和危险。
我们的模板通过引入 config.json
,将这些易变的部分与核心逻辑分离开来,让你能安全、高效地进行定制。
升级步骤
现在,我们将以第一部分创建的项目为基础,用本模板中的文件来"升级"它。
1. 复制核心文件
将我们模板项目中的以下文件,复制到你刚才创建的 my-electron-app
文件夹中,覆盖掉同名文件:
main.js
(新的主进程)preload.js
config.json
(核心配置文件)build-config.js
(构建钩子)assets/
(整个文件夹,存放图标)
2. 更新 package.json
用我们模板中的 package.json
内容,去更新你自己的 package.json
。主要关注 "scripts"
和 "devDependencies"
部分,确保包含了 electron-builder
, cross-env
等工具。
3. 安装新依赖
由于 package.json
更新了,需要重新安装依赖。
bash
# 推荐使用 yarn
yarn
# 或者 npm
npm install
体验新流程
现在,你的项目已经脱胎换骨。使用你熟悉的 yarn
或 npm
1. 修改配置 (config.json
)
打开 config.json
,将 urls.production
改成一个你能访问的网址,比如 "https://www.bing.com"
。
2. 启动!
bash
yarn dev
应用启动了,并且直接加载了你在 config.json
中设置的网址!现在,你可以随时通过修改这个文件来切换地址、调整窗口,而无需再动 main.js
的代码。
3. 打包
bash
yarn build
打包命令现在也变得更智能了。它会自动通过 build-config.js
读取你的配置,生成带正确名称和图标的应用。
至此,你已经完整地体验了从一个最基础的 Electron 应用,到一个高度工程化的专业模板的演进过程。
Electron 核心概念解析
在深入项目架构之前,有必要先理解 Electron 的几个核心概念。
什么是 Electron?
Electron 是一个开源框架,它允许你使用纯粹的 Web 技术(HTML, CSS, JavaScript)来构建跨平台的桌面应用。它通过将 Chromium (一个开源的浏览器内核)和 Node.js(一个 JavaScript 运行时)捆绑在一起,让你能用一个代码库,创建在 Windows, macOS 和 Linux 上都能运行的程序。
简单来说,Electron 让你的 Web 应用可以作为一个独立的桌面程序运行,并赋予它访问操作系统原生功能的能力。
两大核心进程
一个 Electron 应用主要由两种进程构成:
-
主进程 (Main Process)
- 唯一性 :每个 Electron 应用有且仅有一个主进程。
- 角色 :作为应用的"大脑"或"后端"。它是应用的入口点(项目中的
main.js
就是它)。 - 能力 :它运行在一个完整的 Node.js 环境中,因此拥有所有 Node.js 的能力,比如操作文件系统 (
fs
)、创建原生窗口 (BrowserWindow
)、管理菜单、对话框等。
-
渲染进程 (Renderer Process)
- 多重性 :每个 Electron 的 web 页面(即每个
BrowserWindow
实例)都运行在自己的渲染进程中。可以有多个。 - 角色:作为应用的"眼睛"或"前端"。它负责渲染界面(HTML 和 CSS)。
- 能力 :它运行在一个标准的浏览器环境中(Chromium),拥有你所熟悉的
window
和document
对象。出于安全考虑,渲染进程默认不能直接调用 Node.js 的 API。
- 多重性 :每个 Electron 的 web 页面(即每个
进程间通信 (IPC)
既然主进程和渲染进程是相互隔离的,它们如何协作?答案是进程间通信 (IPC)。
- 场景:当你想在界面上点击一个按钮来读取本地文件时,渲染进程无法直接做。它必须发送一个消息给主进程,请求主进程去读取文件,然后主进程再把文件内容通过另一条消息发回给渲染进程进行显示。
- 工具 :Electron 提供了
ipcMain
(在主进程使用)和ipcRenderer
(在渲染进程使用)模块来处理这种异步通信。
理解了这几个基本概念,你就能更好地看懂 main.js
和 preload.js
在我们项目架构中的作用和设计意图。
架构解析
了解内部机制,能让你更好地进行二次开发。
-
main.js
(主进程) 应用的入口文件。它的职责很单一:读取config.json
,根据当前环境 (NODE_ENV
) 选择合适的 URL,然后创建一个浏览器窗口加载它。所有环境判断、窗口管理、系统菜单等原生交互都在这里处理,目的是让渲染进程(你的 Web 应用)可以保持与 Electron 的解耦。 -
config.json
(配置文件) 项目的"单一数据源",也是 DX (Developer Experience) 的核心。通过将配置抽离,我们避免了在代码中硬编码 URL、窗口尺寸等变量,使得维护和部署变得非常高效。 -
build-config.js
(构建钩子) 一个pre-build
钩子脚本。electron-builder
的很多配置(如productName
,icon
)都定义在package.json
中。为了避免手动同步config.json
和package.json
的配置,这个脚本会在yarn build
执行前,自动读取config.json
的值并更新package.json
,确保打包信息永远是最新且一致的。 -
preload.js
(预加载脚本) 一个在渲染进程(你的网页)加载前执行的脚本,它可以访问 Node.js API。它像一座桥梁,用于在主进程和渲染进程之间安全地通信。目前它的主要作用是在开发环境下,过滤掉一些 Electron 自身产生的、无伤大雅的控制台警告,让你的 console 保持干净。
附录:依赖项解析
package.json
中的 devDependencies
是项目开发和构建的基石。
electron
: 核心框架。提供了将 Web 技术栈封装成桌面应用所需的全部 API。electron-builder
: 专业打包工具。负责将项目构建成各平台的安装包,处理图标、签名、更新等一系列工程化问题。cross-env
: 跨平台环境变量设置工具。Windows 下设置环境变量用set VAR=...
,macOS/Linux 用export VAR=...
。cross-env
抹平了这个差异,让package.json
的scripts
能在所有平台正常工作。concurrently
/wait-on
: 流程控制工具 (为复杂场景预留) 。 在当前配置中,我们直接加载一个已有的 URL,因此并未启用这两个工具。但它们是为更复杂的开发流程预置的:例如,当你需要用一个命令,先启动本地的 Web 开发服务器(如react-scripts start
),并等待其成功运行后,再自动启动 Electron 应用去加载它。concurrently
负责并行执行多个命令,wait-on
则负责精准地等待时机。这两个工具组合起来能有效解决开发流程中的竞态问题。
进阶玩法
1. 平台专属打包
如果只想构建特定平台的包,可以指定参数:
bash
yarn build --win
yarn build --mac
yarn build --linux
2. 功能开关
在 config.json
的 features
中,可以控制一些内置功能:
json
"features": {
"contextMenu": true,
"webSecurity": false
}
contextMenu
: 是否启用一个包含"刷新"、"开发者工具"等常用操作的右键菜单。webSecurity
: Web 安全策略。为了方便开发时进行跨域请求,dev
模式下会根据配置禁用它。但在production
环境下,出于安全考虑,它会被强制开启。
总结
这个模板的核心设计哲学是 "配置优于编码" (Configuration over Code)。
通过将所有可变因素(URL、窗口、图标等)抽离到 config.json
,实现了一套代码在多个环境(开发、生产,甚至测试)中无缝部署,这极大地降低了多环境管理的复杂度和维护成本。
总之,这套工作流为你解决了打包的后顾之忧,让你能安心地聚焦于 Web 应用本身的创造。