问题:最近项目上有桌面端开发得需求,根据官方文档和CSDN中一步一步进行学习,打算记录下来学习的过程。
一、node环境
注意:node版本尽量在20以上,如果自己的版本过低,可以通过NVM去切换node版本,可以参考nvm安装
node:v24.0.1
npm:11.3.0
nvm:1.2.2

二、electron入门
想细致了解的码友们可以参考官网的内容,讲的很细致。官方文档
2.1 初始化package.json文件
mkdir my-electron-app && cd my-electron-app
npm init
2.2 安装electron
npm install electron –save-dev
2.3 项目文件格式(仅供参考)

2.4 修改package.json内容
# package.json 字段说明
{
"name": "my-electron-app", // 项目名称(必须小写,不能有空格)
"version": "1.0.0", // 项目版本号(遵循语义化版本规范:主版本.次版本.修订号)
"description": "Hello World!",// 项目描述(简要说明项目功能)
"main": "main.js", // Electron 主进程入口文件(程序启动时首先执行的文件)
"scripts": { // 脚本命令配置(通过 npm run 执行)
"test": "echo \\"Error: no test specified\\" && exit 1" // 测试脚本(这里是默认提示,无实际测试逻辑)
},
"author": "Jane Doe", // 项目作者
"license": "MIT", // 开源许可证类型(MIT 是宽松的开源协议)
"devDependencies": { // 开发依赖(仅开发环境需要的包,打包时不会包含)
"electron": "23.1.3" // Electron 框架依赖(版本 23.1.3)
}
}
2.5 创建 main.js(electron主进程)文件
// 从 electron 模块中解构导入核心模块:
// app:控制应用程序的生命周期
// BrowserWindow:创建和管理应用窗口
const { app, BrowserWindow} = require('electron')
/**
* 创建应用窗口的核心函数
* 封装窗口创建逻辑,便于复用和维护
*/
const createWindow = () => {
// 实例化一个浏览器窗口对象,传入窗口配置项
const win = new BrowserWindow({
width: 800, // 窗口宽度(像素)
height: 600, // 窗口高度(像素)
// 可扩展其他配置:比如 icon(窗口图标)、webPreferences(网页偏好设置)等
})
// 加载本地的 HTML 文件作为窗口的内容(指定相对路径)
win.loadFile('src/index.html')
// 自动打开开发者工具(调试用,生产环境建议注释掉)
win.webContents.openDevTools()
}
/**
* 应用程序生命周期:当应用完成初始化并准备就绪时执行
* Electron 应用启动后需要等待 app 就绪才能创建窗口
*/
app.whenReady().then(() => {
// 调用窗口创建函数,生成主窗口
createWindow()
// 补充:macOS 特有逻辑 – 当应用就绪但无窗口时,点击 dock 图标重新创建窗口
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
/**
* 应用程序生命周期:监听所有窗口关闭事件
* 处理不同操作系统的窗口关闭逻辑差异
*/
app.on('window-all-closed', () => {
// process.platform:获取当前操作系统类型
// darwin 是 macOS 的标识,其他系统(Windows/Linux)直接退出应用
// macOS 特性:关闭所有窗口后应用仍驻留 dock,需手动右键退出
if (process.platform !== 'darwin') {
app.quit() // 退出整个应用程序
}
})
2.6 预加载脚本(中间层)
Electron 的主进程是一个拥有着完全操作系统访问权限的 Node.js 环境。 另一方面,出于安全原因,渲染进程默认跑在网页页面上,而并非 Node.js里。为了将 Electron 的不同类型的进程桥接在一起,我们需要使用被称为 预加载 的特殊脚本。
2.6.1 主线程导入代码:preload: path.join(__dirname, 'src/preload/index.js')
// 从 electron 模块解构导入核心模块:
// app:控制应用程序的生命周期
// BrowserWindow:创建和管理应用窗口
// ipcMain:主进程侧的 IPC 通信模块,用于接收渲染进程的消息并响应
const { app, BrowserWindow, ipcMain } = require('electron')
// 导入 Node.js 内置的 path 模块,用于处理文件/目录路径(解决跨平台路径兼容问题)
const path = require('node:path')
/**
* 创建应用窗口的核心函数
* 封装窗口创建逻辑,便于复用和维护
*/
const createWindow = () => {
// 实例化浏览器窗口对象,传入窗口配置项
const win = new BrowserWindow({
width: 800, // 窗口宽度(像素)
height: 600, // 窗口高度(像素)
webPreferences: { // 网页相关的配置项(Electron 安全和通信的核心配置)
// preload(预加载脚本):在渲染进程加载前执行,拥有 Node.js 权限但与渲染进程隔离
// path.join(__dirname, 'src/preload/index.js'):拼接预加载脚本的绝对路径
// __dirname:当前文件(main.js)所在的目录路径,保证路径跨平台有效
preload: path.join(__dirname, 'src/preload/index.js')
}
})
// 加载本地的 HTML 文件作为窗口的内容(渲染进程的入口)
win.loadFile('src/index.html')
// 自动打开开发者工具(调试用,生产环境建议注释/删除)
win.webContents.openDevTools()
}
/**
* 应用程序生命周期:当应用完成初始化并准备就绪时执行
* Electron 应用启动后必须等待 app 就绪才能创建窗口/注册 IPC 监听
*/
app.whenReady().then(() => {
// 注册 IPC 处理函数:监听渲染进程发送的 'ping' 消息
// ipcMain.handle 是异步通信方式,支持返回值/Promise,渲染进程通过 ipcRenderer.invoke 调用
// 当收到 'ping' 消息时,返回 'pong' 给渲染进程
ipcMain.handle('ping', () => 'pong')
// 调用窗口创建函数,生成主窗口
createWindow()
// macOS 特有逻辑:当应用就绪但无窗口时,点击 dock 图标重新创建窗口
app.on('activate', () => {
// 检查当前是否有已打开的窗口,若无则创建新窗口
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
/**
* 应用程序生命周期:监听所有窗口关闭事件
* 处理不同操作系统的窗口关闭逻辑差异
*/
app.on('window-all-closed', () => {
// process.platform:获取当前操作系统类型
// darwin 是 macOS 的标识,其他系统(Windows/Linux)关闭所有窗口后直接退出应用
// macOS 特性:关闭所有窗口后应用仍驻留 dock,需手动右键退出
if (process.platform !== 'darwin') {
app.quit() // 退出整个应用程序
}
})
2.6.2 预加载文件(/src/preload/index.js)
// 从 electron 模块解构导入预加载脚本核心 API:
// contextBridge:安全地向渲染进程暴露 API 的桥梁(Electron 推荐的安全方式)
// ipcRenderer:渲染进程侧的 IPC 通信模块,用于向主进程发送/接收消息
const { contextBridge, ipcRenderer } = require('electron')
/**
* 使用 contextBridge 向渲染进程的全局作用域(window)暴露 API
* 核心作用:在主进程(高权限)和渲染进程(低权限)之间建立安全的通信通道
* 避免直接暴露 ipcRenderer 等敏感 API,防止安全漏洞
*/
contextBridge.exposeInMainWorld(
// 暴露到 window 上的全局对象名称:window.versions
'versions',
// 要暴露的具体方法/属性(仅暴露需要的功能,最小权限原则)
{
// 暴露获取 Node.js 版本的方法(封装为函数,避免直接暴露 process 对象)
node: () => process.versions.node,
// 暴露获取 Chrome 内核版本的方法
chrome: () => process.versions.chrome,
// 暴露获取 Electron 版本的方法
electron: () => process.versions.electron,
// 暴露调用主进程 'ping' 接口的方法
// ipcRenderer.invoke:异步调用主进程通过 ipcMain.handle 注册的接口
// 对应主进程中的 ipcMain.handle('ping', () => 'pong')
ping: () => ipcRenderer.invoke('ping'),
// 注释说明:除了函数,也可以暴露静态变量,例如:
// appName: 'my-electron-app',
// appVersion: '1.0.0'
}
)
2.7 创建渲染进程(src/render/index.js)
const information = document.getElementById('info')
information.innerText = `本应用正在使用 Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), 和 Electron (v${versions.electron()})`
const func = async () => {
const res = await window.versions.ping()
console.log(res)
}
func()
2.8 主页面(html文件,渲染进程在这个文件中导入)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</p>
<div id="info">
</div>
<script src="./render/index.js"></script>
</body>
</html>
2.9 .添加 .gitignore 文件
.gitignore 文件可以指定哪些文件和目录应该在Git中不被跟踪。 建议您复制一份 GitHub 的 Node.js gitignore 模板 到您项目的根目录,以避免将 node_modules 文件夹提交到版本控制系统中。
2.10 启动项目
2.10.1 在终端中输入:
npm run start

2.10.2 热更新项目
npm install –save-dev nodemon
// package.json 文件中
"scripts": {
"start": "nodemon –exec electron .", // 开发启动:nodemon 监听文件自动重启
"test": "echo \\"Error: no test specified\\" && exit 1", // 测试脚本(占位)
"build": "electron-builder" // 打包脚本:调用 electron-builder
}
2.11 打包程序
2.11.1 下载打包指令
# 推荐安装 24.x 稳定版(兼容性更好,避免高版本报错)
npm install electron-builder@24.6.4 –save-dev
2.11.2 配置内容,注意其中的icon图标可以用下面两个工具剪切网站(有些需要梯子),并且放入public目录下
https://convertio.co/zh/png-ico/转换格式工具
图片剪切工具
IOS的ICNS格式转换器

# package.json 字段说明
{
"name": "my-electron-app", // 项目名称(小写,无空格)
"version": "1.0.0", // 语义化版本号
"description": "test my first electron", // 项目描述
"main": "main.js", // Electron 主进程入口文件
"author": "Justin", // 作者
"license": "MIT", // 开源许可证
"scripts": {
"start": "nodemon –exec electron .", // 开发启动:nodemon 监听文件自动重启
"test": "echo \\"Error: no test specified\\" && exit 1", // 测试脚本(占位)
"build": "electron-builder" // 打包脚本:调用 electron-builder
},
// 打包配置
"build": {
"appId": "com.xxx.xxxx", // 应用唯一标识(反向域名)
"productName": "xxxx", // 应用显示名称
"electronLanguages": ["en"], // 支持的语言:仅英文
"files": [ // 打包文件过滤(! 表示排除)
"!node_modules/**/*.md", // 排除 node_modules 下的 md 文件
"!src/**/*.map", // 排除 src 下的 map 文件
"!*.log", // 排除日志文件
"!*.yml" // 排除 yml 配置文件
],
"win": { // Windows 打包配置
"target": [{
"target": "portable", // 输出便携版 exe
"arch": ["x64"] // 64位架构
}],
"icon": "public/favicon1.ico" // Windows 应用图标(ico)
},
"mac": { // macOS 打包配置
"target": "dmg", // 输出 dmg 镜像
"icon": "public/favicon.icns" // macOS 图标(icns)
},
"linux": { // Linux 打包配置
"target": "deb", // 输出 deb 安装包
"icon": "public/favicon2.png" // Linux 图标(png)
},
"nsis": { // Windows 安装包(NSIS)配置
"oneClick": true, // 一键安装
"perMachine": false, // 仅当前用户安装
"deleteAppDataOnUninstall": true, // 卸载删除应用数据
"createDesktopShortcut": true, // 创建桌面快捷方式
"createStartMenuShortcut": true // 创建开始菜单快捷方式
}
},
"devDependencies": {
"@electron-forge/cli": "^7.11.1", // Electron 脚手架(备用)
"electron": "^40.0.0", // Electron 核心框架
"electron-builder": "^24.6.4", // 核心打包工具
"nodemon": "^3.1.11" // 开发时文件监听自动重启
}
}
2.11.3 执行打包
npm run build


三、electron + vue项目
3.1 electron-vite 框架安装。参考:官方文档
1. 按照官方文档安装会有些慢,可以直接输入下面指令快速构建:
npm create @quick-start/electron@latest
yarn create @quick-start/electron
pnpm create @quick-start/electron
2. 我这里用到的是cnpm,之前的镜像失效了,使用了新的镜像地址
npm install -g cnpm –registry=https://registry.npmmirror.com
3. 执行npm create @quick-start/electron@latest

4. 生成的目录结构

3.2 使用项目
1. 安装依赖包
cnpm install
2. 运行程序,执行完毕后会弹出桌面程序
npm run dev

3. 可以在src源代码中写入自己的vue业务代码
3.3 打包程序
1. 执行打包指令
由于我是windows电脑,我目前打包成windows桌面软件做演示

2. 打包完成后输出dist目录(在这个目录中能看到打包的桌面程序)

四、总结
本文是分成了node环境的安装、以及原始的electron桌面应用的生成,到后续使用electron-vite脚手架快速的构建项目,大大提高了开发者打包应用的速度。

