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 LTSWindows 用 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 electron28.2.0 --save-dev npm install electron-builder24.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才是真正的「锁死」模式连 AltTab 都受限。展厅场景我一般用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-eventmainWindow.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改成portablewin: { 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里加artifactNamensis: { 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或者尺寸小于 256x256electron-builder静默忽略。解决用 ImageMagick 重新生成convert icon.png -define icon:auto-resize256,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把窗口强制放到主显示器上。这一步在单屏环境看不出问题多屏环境必加。从那以后我每次打包完都会在目标机器上把这三步走一遍尤其是多显示器那台。有次就是漏了这步现场演示时窗口跑到副屏观众席一片茫然。希望帮到你。本文还有配套的精品资源点击获取