Electron 打包 HTML 成 exe:全屏、遮任务栏与 Esc 退出实战
简介:这份资源面向希望把本地HTML页面封装成Windows桌面程序的开发者,尤其适合已掌握HTML、CSS与JavaScript、想快速上手Electron打包流程的前端或全栈人员。内容围绕Electron框架展开,覆盖将网页资源打包为.exe可执行文件、窗口全屏显示、隐藏任务栏图标、监听Esc键退出程序,以及通过electron-packager或electron-builder自定义exe图标与输出文件名等实用知识点,并涉及主进程与渲染进程间的IPC通信写法。压缩包共约2000个文件,以js、ts、map、json、md、license等为主,另有cmd、yml、pak、dll、exe等配置与运行文件,整体约95.61MB,目录结构完整,便于对照查阅依赖与打包配置。目前已有1161人学习下载。读者可据此获得一套可直接参考的Electron工程结构与打包参数示例,理解全屏、退出、图标替换等常见需求的实现思路,并借助其中的依赖与配置文件排查版本兼容问题。
1. 从一次全屏展示翻车说起:Electron 打包 HTML 到底难在哪
去年帮一个做展厅项目的朋友处理过一台演示机,需求听起来简单得不像话:把一个本地 HTML 页面变成双击就能跑的 exe,全屏铺满、盖住任务栏、按 Esc 退出,顺便把图标和文件名换成他们自己的。结果第一版打出来,任务栏死活盖不住,按 Esc 没反应,图标还是默认的 Electron 原子图标,文件名带着一长串版本号。折腾到凌晨两点才把这几件事全捋顺。
这套流程其实非常常见——展厅大屏、教学演示、内部工具、离线文档,只要是想把网页当桌面程序跑,Electron 基本是首选。但「能跑」和「跑得像个正经软件」之间隔着一堆参数:fullscreen和kiosk的区别、frame和autoHideMenuBar的取舍、globalShortcut注册 Esc 的时机、electron-builder里图标和productName的写法。装不好,轻则任务栏露一条边,重则 Esc 按下去整个程序卡死。
这篇笔记面向的是手上有现成 HTML、想把它变成干净 exe 的开发者。新手照着命令能一步步走通,熟手可以重点看版本差异和参数取舍那几段。下面从环境列起,一路装到验证跑通。
2. 环境准备与版本选择:Node、Electron、electron-builder 怎么配
2.1 先确认 Node 版本,别用太新的
Electron 对 Node 版本有隐性要求。我一般用 Node 18 LTS 或 20 LTS,太新的奇数版本(比如 21、23)在electron-builder打包阶段偶尔会报node-gyp相关的编译错误,属于玄学范畴,能避就避。
# 查看当前 Node 和 npm 版本 node -v npm -v # 如果版本不对,用 nvm 切到 18 LTS(Windows 用 nvm-windows) nvm install 18 nvm use 18逻辑说明:node -v确认主版本号,18 或 20 开头即可。nvm是版本管理工具,Windows 下用nvm-windows,命令基本一致。这一步不做,后面npm install可能装出一堆警告。
2.2 初始化项目,锁定 Electron 版本
Electron 版本迭代很快,不同大版本对fullscreen、kiosk、globalShortcut的行为有细微差别。我一般锁在 28.x 或 29.x,这两个版本在 Windows 上盖任务栏的表现稳定。
# 新建项目目录并初始化 mkdir html-to-exe && cd html-to-exe npm init -y # 安装 Electron 和 electron-builder,锁定版本 npm install electron@28.2.0 --save-dev npm install electron-builder@24.13.3 --save-dev逻辑说明:npm init -y生成默认package.json,省去交互。--save-dev把依赖写进devDependencies,因为 Electron 和 builder 只在开发和打包阶段用,运行时不需要。版本号写死是为了避免^自动升级带来的行为漂移——这是血泪经验,某次^28.0.0升到 28.3 后全屏行为变了。
2.3 目录结构:HTML 放哪、主进程写哪
Electron 项目最小结构就三个东西:主进程文件、HTML 页面、package.json。我习惯这样放:
html-to-exe/ ├── main.js # 主进程,控制窗口 ├── index.html # 你的网页 ├── package.json └── build/ └── icon.ico # 打包用的图标main.js是入口,index.html是你要展示的页面。build/icon.ico是 Windows 图标,尺寸建议 256x256,格式必须是.ico,用在线工具或 ImageMagick 转都行。
提示:图标文件如果尺寸不对或格式不对,
electron-builder不会报错,而是静默用默认图标,很容易以为是自己没配对。
3. 主进程配置:全屏、遮任务栏、Esc 退出的参数怎么写
3.1 BrowserWindow 的关键参数逐个说
全屏和遮任务栏是两件事。fullscreen: true会让窗口占满屏幕,但在某些 Windows 版本上任务栏仍会浮在上面;kiosk: true才是真正的「锁死」模式,连 Alt+Tab 都受限。展厅场景我一般用fullscreen加frame: false,兼顾效果和可控性。
// main.js const { app, BrowserWindow, globalShortcut } = require('electron'); const path = require('path'); let mainWindow; function createWindow() { mainWindow = new BrowserWindow({ fullscreen: true, // 全屏,占满屏幕 frame: false, // 去掉标题栏和边框 autoHideMenuBar: true, // 隐藏菜单栏 skipTaskbar: false, // 是否在任务栏显示,false 表示显示 webPreferences: { nodeIntegration: false, // 安全起见,关闭 Node 集成 contextIsolation: true // 开启上下文隔离 } }); // 加载本地 HTML mainWindow.loadFile(path.join(__dirname, 'index.html')); // 注册 Esc 退出 globalShortcut.register('Escape', () => { app.quit(); }); } app.whenReady().then(createWindow); // 窗口关闭时注销快捷键,避免残留 app.on('will-quit', () => { globalShortcut.unregisterAll(); });逻辑说明:fullscreen: true是核心,让窗口进入全屏状态。frame: false去掉系统边框,视觉上更干净。autoHideMenuBar: true隐藏 Electron 默认菜单栏,不然按 Alt 会弹出来。skipTaskbar我设成false,因为展厅场景有时需要从任务栏切回来;如果你要彻底隐藏,改成true。
globalShortcut.register('Escape', ...)是全局快捷键,即使焦点不在窗口上也能响应。app.quit()直接退出整个应用。will-quit里注销所有快捷键是必须的,否则在某些系统上快捷键会残留,下次启动冲突。
3.2 遮不住任务栏时的两个补救参数
如果fullscreen: true之后任务栏还是露出来,通常是 Windows 的「全屏优化」在作怪。我一般加两个参数:
mainWindow = new BrowserWindow({ fullscreen: true, frame: false, alwaysOnTop: true, // 置顶,压住任务栏 skipTaskbar: true, // 不在任务栏显示 // ... 其他参数 }); // 进入全屏后再强制设置一次 mainWindow.setFullScreen(true); mainWindow.setAlwaysOnTop(true, 'screen-saver');逻辑说明:alwaysOnTop: true让窗口始终在最前,'screen-saver'这个层级比普通置顶更高,能压住任务栏。setFullScreen(true)在窗口创建后再调一次,是因为某些 Windows 版本在构造参数里设fullscreen不生效,需要运行时再触发。
注意:
alwaysOnTop加screen-saver层级会让窗口盖住所有东西,包括系统弹窗。调试阶段建议先不加,确认全屏正常后再加。
3.3 Esc 退出的三种写法与取舍
Esc 退出有三种常见做法,各有适用场景:
| 写法 | 实现方式 | 适用场景 | 缺点 |
|---|---|---|---|
| globalShortcut | 主进程注册全局快捷键 | 焦点不在窗口也能退 | 与其他软件快捷键冲突 |
| webContents 监听 | 在 HTML 里监听 keydown | 页面内可控 | 焦点丢失时失效 |
| before-input-event | 主进程监听输入事件 | 精准、不冲突 | 代码稍多 |
我一般用globalShortcut,因为展厅场景经常是触摸屏,焦点不一定在窗口上。如果担心冲突,可以换成before-input-event:
mainWindow.webContents.on('before-input-event', (event, input) => { if (input.key === 'Escape') { app.quit(); } });逻辑说明:before-input-event在页面处理输入之前拦截,只在窗口聚焦时生效,不会和其他软件冲突。适合对快捷键敏感的环境。
4. 打包成 exe:图标、文件名、productName 怎么改
4.1 package.json 里的 build 配置
electron-builder的配置写在package.json的build字段里。图标、文件名、输出目录都在这里控制。
{ "name": "html-to-exe", "version": "1.0.0", "main": "main.js", "scripts": { "start": "electron .", "build": "electron-builder --win" }, "build": { "appId": "com.example.htmltoexe", "productName": "展厅演示", "directories": { "output": "dist" }, "win": { "icon": "build/icon.ico", "target": [ { "target": "nsis", "arch": ["x64"] } ] }, "nsis": { "oneClick": false, "allowToChangeInstallationDirectory": true, "createDesktopShortcut": true } } }逻辑说明:productName决定 exe 的显示名称,改成「展厅演示」后,生成的 exe 就叫这个。appId是应用唯一标识,随便写但别和别的软件重复。win.icon指向图标文件,必须是.ico格式。target里nsis是安装包格式,arch指定 64 位。
nsis那几项控制安装行为:oneClick: false让用户能选安装目录,createDesktopShortcut: true自动创建桌面快捷方式。如果不需要安装包,只要一个绿色 exe,把target改成portable:
"win": { "icon": "build/icon.ico", "target": ["portable"] }4.2 执行打包与产物说明
# 开发阶段先跑起来看效果 npm start # 确认没问题后打包 npm run build逻辑说明:npm start直接调electron .,用main.js启动,改代码后重启即可。npm run build调electron-builder --win,产物在dist目录。
打包完成后dist里会有:
展厅演示 Setup 1.0.0.exe:安装包win-unpacked/:解压后的绿色版,里面展厅演示.exe可直接双击
提示:第一次打包会下载 Electron 的 Windows 二进制包,网络慢的话会卡很久。可以设
ELECTRON_MIRROR环境变量指向国内镜像,但别用来源不明的镜像。
4.3 文件名带版本号怎么去掉
默认产物名带版本号,比如展厅演示 Setup 1.0.0.exe。想去掉,在build里加artifactName:
"nsis": { "artifactName": "${productName}.${ext}" }逻辑说明:${productName}取productName字段的值,${ext}是扩展名。这样产物就叫展厅演示.exe。如果还要区分架构,可以写${productName}-${arch}.${ext}。
5. 避坑与排查:五个我踩过的真实问题
5.1 现象:任务栏盖不住,全屏后底部露一条
原因:Windows 的全屏优化和 Electron 的fullscreen参数在某些版本上不兼容,窗口虽然全屏但没进入「独占全屏」模式。
解决:加alwaysOnTop: true和setAlwaysOnTop(true, 'screen-saver'),并在app.whenReady之后延迟 100ms 再调setFullScreen(true)。延迟是因为窗口还没完全渲染时设置全屏可能被系统忽略。
5.2 现象:Esc 按下去没反应
原因:globalShortcut.register在app.whenReady之前调用,或者窗口还没创建就注册了。
解决:确保globalShortcut.register在createWindow内部、mainWindow创建之后调用。另外检查是否有其他软件占用了 Esc 快捷键,用globalShortcut.isRegistered('Escape')判断。
5.3 现象:图标改了但 exe 还是默认图标
原因:图标文件不是标准.ico,或者尺寸小于 256x256,electron-builder静默忽略。
解决:用 ImageMagick 重新生成:convert icon.png -define icon:auto-resize=256,128,64,48,32,16 icon.ico。确认build/icon.ico存在且路径正确。
5.4 现象:打包报错Cannot find module 'electron'
原因:electron装在了dependencies而不是devDependencies,或者node_modules损坏。
解决:删掉node_modules和package-lock.json,重新npm install。确认package.json里electron在devDependencies。
5.5 现象:exe 双击后白屏
原因:loadFile路径写错,或者 HTML 里的资源用了绝对路径。
解决:用path.join(__dirname, 'index.html')确保路径正确。HTML 里的 CSS、JS、图片全部用相对路径,不要用/开头。
6. 装完怎么验证:三步确认全屏、退出、图标都对了
打包完别急着交付,我一般走三步验证,每步都有明确的通过标准。
6.1 第一步:开发模式跑一遍
npm start通过标准:窗口全屏打开,任务栏被盖住,按 Esc 能退出,标题栏和菜单栏都不见。如果任务栏露出来,回到 3.2 加alwaysOnTop。如果 Esc 没反应,检查globalShortcut注册位置。
这一步别偷懒,开发模式改参数最快,打包一次要等好几分钟。
6.2 第二步:绿色版 exe 验证
进dist/win-unpacked/,双击展厅演示.exe。
通过标准:exe 文件名正确、图标是自定义的、双击后行为和开发模式一致。如果图标不对,检查build/icon.ico的格式和尺寸。如果文件名带版本号,检查artifactName配置。
6.3 第三步:安装包验证
双击dist/展厅演示 Setup 1.0.0.exe,走一遍安装流程。
通过标准:安装过程能选目录、装完桌面有快捷方式、从快捷方式启动行为正常。如果安装包名字不对,检查artifactName;如果安装时没有选目录的步骤,检查nsis.oneClick是否为false。
6.4 一个容易被忽略的验证点:多显示器
展厅场景经常接多个显示器。fullscreen: true默认在主显示器全屏,如果演示机接了副屏,窗口可能跑到副屏上。我一般加一句:
const { screen } = require('electron'); const primaryDisplay = screen.getPrimaryDisplay(); mainWindow.setBounds(primaryDisplay.bounds);逻辑说明:screen.getPrimaryDisplay()拿到主显示器,setBounds把窗口强制放到主显示器上。这一步在单屏环境看不出问题,多屏环境必加。
从那以后我每次打包完,都会在目标机器上把这三步走一遍,尤其是多显示器那台。有次就是漏了这步,现场演示时窗口跑到副屏,观众席一片茫然。希望帮到你。
本文还有配套的精品资源,点击获取