简介这份资源面向希望把本地HTML网页封装成Windows桌面程序的开发者尤其适合已掌握HTML、CSS与JavaScript、想快速上手Electron打包流程的前端或全栈人员。内容围绕Electron框架展开覆盖将网页资源打包为.exe可执行文件并实现全屏显示、隐藏任务栏、Esc键退出程序以及自定义exe图标与文件名等实用功能同时涉及主进程与渲染进程间的IPC通信、electron-packager与electron-builder的打包参数配置。压缩包共约2000个文件以js、ts、map、json、md、license等为主另有pak、dll、exe等运行时与打包产物整体约95.61MB目录结构完整便于对照查阅依赖与配置。目前已有1161人学习下载。读者可据此获得一套可直接参考的Electron工程结构、关键代码片段与打包命令示例理解全屏窗口、任务栏遮挡、快捷键退出及图标替换的实现思路并借助其中的依赖与配置信息排查版本兼容问题减少从零搭建的试错成本。1. 把网页塞进 exe为什么我选 Electron 而不是直接打包浏览器有个做内部工具的朋友找我说他们车间有台老工控机系统是 Windows 7浏览器版本锁死在 Chrome 60 左右但业务系统已经用上了 Vue 3 Vite 构建的页面一打开就白屏。他的诉求很具体把网页变成一个双击就能跑的 exe全屏显示、盖住任务栏、按 Esc 退出顺便把图标和文件名都换成自己公司的。这不是什么高深需求但真动手时坑不少——用 HTA 吧内核太老用 NW.js 吧社区凉了半截用 Tauri 吧Win7 支持又是个玄学。绕了一圈最后还是回到 Electron。它自带 Chromium 内核版本可控打包出来就是一个独立 exe不依赖客户机装没装浏览器。这篇就按我实际落地的顺序把从环境搭建到改图标、改文件名、全屏遮任务栏、Esc 退出的完整链路拆一遍顺带把几个容易翻车的地方标出来。2. 环境搭建与最小可运行 Electron 壳从零到看见窗口Electron 的本质是 Chromium Node.js 的运行时主进程管窗口和系统交互渲染进程管页面。你要做的不是“编译网页”而是让 Electron 加载你的 HTML再把整个运行时打包成 exe。所以第一步不是写代码而是把 Node 环境和项目骨架搭对。2.1 Node 版本选择与项目初始化Node 版本别追新尤其你要兼容 Win7 的话。Electron 从 23 开始就不支持 Win7 了所以如果目标机器有 Win7锁死 Electron 22.x对应 Node 16 左右。我一般用 nvm 切版本避免全局污染。# 查看当前 node 版本建议 16.x 或 18.x node -v # 新建项目目录并初始化 package.json mkdir my-electron-app cd my-electron-app npm init -y # 安装 electron指定 22.x 以兼容 Win7 npm install electron22.3.27 --save-dev这里--save-dev是因为 Electron 只是开发依赖最终打包时会被塞进 exe不需要作为生产依赖发布。装完后node_modules/electron/dist下会有对应平台的二进制国内网络如果卡在下载阶段设置ELECTRON_MIRROR环境变量指向国内镜像即可这个属于常规操作不展开。2.2 主进程与渲染进程的最小闭环项目根目录建两个文件main.js和index.html。main.js是主进程入口负责创建窗口、设置全屏、监听 Esc。// main.js const { app, BrowserWindow, globalShortcut } require(electron); const path require(path); let win null; function createWindow() { win new BrowserWindow({ width: 1920, height: 1080, fullscreen: true, // 全屏但任务栏可能还在 frame: false, // 去掉标题栏和边框 autoHideMenuBar: true, // 隐藏菜单栏 webPreferences: { nodeIntegration: false, // 安全起见关掉 contextIsolation: true } }); // 加载本地 HTML 或远程地址 win.loadFile(path.join(__dirname, index.html)); // 关键设置 alwaysOnTop 并覆盖任务栏 win.setAlwaysOnTop(true, screen-saver); win.setFullScreen(true); // 监听 Esc 退出 win.webContents.on(before-input-event, (event, input) { if (input.key Escape) { app.quit(); } }); } app.whenReady().then(() { createWindow(); }); app.on(window-all-closed, () { app.quit(); });index.html随便写个页面验证!DOCTYPE html html headmeta charsetutf-8titleDemo/title/head body stylebackground:#1e1e1e;color:#fff;display:flex;align-items:center;justify-content:center;height:100vh;margin:0; h1Electron 全屏测试按 Esc 退出/h1 /body /html在package.json里加启动脚本scripts: { start: electron . }跑npm start你应该能看到一个无边框全屏窗口按 Esc 直接退出。到这里最小闭环就通了。注意setAlwaysOnTop(true, screen-saver)这行第二个参数是层级screen-saver比普通alwaysOnTop更高能盖住任务栏。但有些系统上任务栏会闪一下再被盖住这是正常的后面避坑章节会讲怎么处理。3. 全屏遮任务栏与 Esc 退出的细节别让任务栏弹出来窗口能全屏了但任务栏偶尔还会冒出来尤其是用户按 Win 键或者鼠标移到屏幕底部时。这不是 Electron 的 bug是 Windows 的焦点机制在作祟。要彻底遮住得从窗口层级和事件拦截两方面下手。3.1 窗口层级与 kiosk 模式Electron 的BrowserWindow有个kiosk选项设为true后就是真正的信息亭模式任务栏、开始菜单全被屏蔽用户只能操作你的页面。但 kiosk 模式下退出得靠代码因为 AltF4 可能也被拦。我一般不用 kiosk而是用fullscreen alwaysOnTop frame:false组合灵活性更高。win new BrowserWindow({ fullscreen: true, frame: false, skipTaskbar: true, // 不在任务栏显示图标 alwaysOnTop: true, webPreferences: { ... } }); // 确保窗口获得焦点后再次置顶 win.on(focus, () { win.setAlwaysOnTop(true, screen-saver); }); // 防止窗口失去焦点时任务栏弹出 win.on(blur, () { win.setAlwaysOnTop(true, screen-saver); win.focus(); });skipTaskbar: true让 exe 不在任务栏占位blur事件里强制抢回焦点这样即使用户点了任务栏窗口也会立刻重新置顶。但注意win.focus()在blur里调用可能造成死循环所以加个延时或者判断条件更稳妥。我通常用setTimeout(() win.focus(), 10)绕开。3.2 Esc 退出的三种实现与取舍Esc 退出有三种写法各有适用场景第一种是上面用的before-input-event在渲染进程加载前拦截键盘事件优点是响应快缺点是如果页面里有输入框Esc 可能被页面逻辑吃掉。第二种是在渲染进程里用document.addEventListener(keydown)然后通过 IPC 通知主进程退出。第三种是注册全局快捷键globalShortcut.register(Escape, ...)但全局快捷键会抢占系统其他程序的 Esc不推荐。我一般用第一种并在页面里避免使用 Esc 作为功能键。如果页面确实需要 Esc就改成组合键比如CtrlShiftQ。// 组合键退出示例 win.webContents.on(before-input-event, (event, input) { if (input.control input.shift input.key.toLowerCase() q) { app.quit(); } });参数说明input.control和input.shift是布尔值input.key是按键名称。注意input.key对字母键返回的是小写所以用toLowerCase()统一处理。3.3 多显示器下的全屏策略如果客户机接了双屏fullscreen: true默认只在主屏全屏副屏会露出桌面。要覆盖所有屏幕得用screen模块获取所有显示器然后为每个显示器创建一个窗口或者用win.setBounds()把窗口拉到所有屏幕的并集区域。const { screen } require(electron); function createWindowOnAllDisplays() { const displays screen.getAllDisplays(); const primary displays[0]; // 计算所有屏幕的并集区域 let minX 0, minY 0, maxX 0, maxY 0; displays.forEach(d { minX Math.min(minX, d.bounds.x); minY Math.min(minY, d.bounds.y); maxX Math.max(maxX, d.bounds.x d.bounds.width); maxY Math.max(maxY, d.bounds.y d.bounds.height); }); win.setBounds({ x: minX, y: minY, width: maxX - minX, height: maxY - minY }); }这段代码在createWindow之后调用能把窗口横跨所有显示器。但实际用的时候如果副屏分辨率不同页面布局可能错位所以更稳妥的做法是只主屏全屏副屏用win.setFullScreen(false)后手动定位。这个看具体场景不是所有项目都需要。4. 改图标、改文件名与打包成 exeelectron-builder 实战开发时跑npm start没问题但交付给客户得是一个独立的 exe双击就能跑图标和文件名都得换。这里用electron-builder它比electron-packager更省心支持 NSIS 安装包和绿色版。4.1 安装 electron-builder 与基础配置npm install electron-builder --save-dev在package.json里加build字段build: { appId: com.example.myapp, productName: MyApp, directories: { output: dist }, win: { target: portable, icon: build/icon.ico }, portable: { artifactName: MyApp.exe } }target设为portable生成单文件绿色版双击直接运行不写注册表。artifactName控制最终 exe 的文件名这里就是MyApp.exe。icon指向build/icon.ico必须是 256x256 的 ico 文件否则打包会报错。4.2 图标制作的坑与验证图标不是随便找个 png 改后缀就行。Windows 的 ico 格式要求包含多个尺寸16x16、32x32、48x48、256x256否则在某些分辨率下会显示模糊或者默认 Electron 图标。我一般用在线工具或者 ImageMagick 生成# 用 ImageMagick 把 png 转成多尺寸 ico convert icon.png -define icon:auto-resize256,128,64,48,32,16 build/icon.ico转换完用file build/icon.ico检查一下确认是MS Windows icon resource且包含多个尺寸。如果打包后 exe 图标没变先清空dist目录再重新打包electron-builder 有缓存。4.3 打包命令与产物验证scripts: { start: electron ., dist: electron-builder --win portable }跑npm run dist等几分钟dist目录下会出现MyApp.exe。双击运行检查三件事图标是不是你设置的、文件名是不是MyApp.exe、全屏和 Esc 退出是否正常。如果 exe 启动后白屏大概率是loadFile的路径不对打包后__dirname指向的是 asar 包内部用path.join(__dirname, index.html)通常没问题但如果用了process.cwd()就会翻车。注意portable 模式每次运行会解压到临时目录启动比安装版慢几秒这是正常的。如果客户机有杀毒软件可能会误报需要加白名单。5. 避坑与常见问题排查我踩过的五个坑这一章全是血泪经验每个都是实际交付时遇到的按「现象 → 原因 → 解决」写你对照着排查能省不少时间。5.1 任务栏遮不住鼠标一碰就弹出来现象全屏后任务栏隐藏了但鼠标移到屏幕底部任务栏又冒出来甚至把窗口顶下去。原因Windows 的任务栏有自动弹出机制当鼠标触碰到屏幕边缘时会激活。alwaysOnTop只能保证窗口在普通窗口之上但任务栏的层级在某些情况下更高。解决用setAlwaysOnTop(true, screen-saver)把窗口层级提到最高同时在blur事件里重新抢焦点。如果还不行加一个定时器每 500ms 检查一次窗口是否被遮挡是的话重新置顶。但定时器耗电只建议在工控机这种常电场景用。5.2 Esc 退出失效按了没反应现象开发时 Esc 能退出打包后按 Esc 没反应。原因打包后页面加载速度变慢before-input-event注册时机可能晚于用户按键。或者页面里有 iframe焦点在 iframe 里主进程收不到键盘事件。解决把 Esc 监听到app.whenReady()之后立刻注册不要等窗口加载完。如果是 iframe 问题在渲染进程里也加一份监听通过ipcRenderer.send(exit-app)通知主进程退出。5.3 打包后 exe 体积巨大超过 200MB现象一个简单页面打包出来 200MB客户嫌大。原因Electron 自带 Chromium 和 Node基础体积就是 150MB 左右这是正常的。如果超过 200MB可能是把node_modules全打进去了或者包含了开发依赖。解决在build配置里加files字段只打包必要文件files: [ main.js, index.html, node_modules/**/* ]同时用electron-builder的asar压缩能再小一点。但别指望降到几十 MB那是 Tauri 的领域。5.4 图标改了但 exe 还是默认图标现象build/icon.ico明明换了打包出来还是 Electron 默认图标。原因electron-builder 有图标缓存或者 ico 文件尺寸不对。解决删掉dist和node_modules/.cache重新打包。确认 ico 包含 256x256 尺寸用identify build/icon.ico查看。如果还不行在win配置里显式指定icon的绝对路径。5.5 Win7 上启动报错提示缺少 api-ms-win-crt现象在 Win7 客户机上双击 exe弹窗提示缺少api-ms-win-crt-runtime-l1-1-0.dll。原因Electron 22 依赖 Visual C 2015 运行时Win7 默认没装。解决在打包时把 VC 运行库一起带上或者让客户机装vcredist_x86.exe。electron-builder 有nsis配置可以自动安装依赖但 portable 模式不行得手动放一个vcredist在 exe 同目录首次运行时静默安装。6. 进阶技巧用 asar 保护源码与自动更新预留打包成 exe 后源码其实还在 asar 包里用asar extract就能解出来。如果不想让客户随便改页面可以开asar并配合代码混淆但这不是绝对安全只是提高门槛。我一般会在build里加asar: true, compression: maximumcompression: maximum用 7z 压缩体积能再小 10% 左右但启动会慢一点。另外如果以后要加自动更新现在就把publish字段预留好指向一个静态文件服务器用electron-updater实现。不过内网工具通常不需要自动更新手动替换 exe 更简单。验证打包是否成功我有个习惯把 exe 拷到一台没装 Node、没装 Electron 的干净虚拟机上跑一遍确认所有依赖都打进去了。这个步骤帮我拦过好几次“开发机能跑、客户机白屏”的问题。从那以后我每次交付前都强制走一遍干净环境验证希望帮到你。本文还有配套的精品资源点击获取