ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Electron-Vue模板实战:IPC通信、打包配置与原生模块重建

Electron-Vue模板实战:IPC通信、打包配置与原生模块重建 简介这是一套基于 Electron 与 Vue.js 的桌面应用工程模板集成 Element UI 组件库、Vue Router 动态路由并实现了菜单导航与选项卡联动适合前端开发者学习跨平台应用搭建或作为后台项目起始模板。压缩包共 45 个文件以 JS 脚本、Vue 组件、JSON 配置及字体图标为主包含 Babel 配置、npm 依赖清单、Webpack 构建脚本、Electron 主进程与渲染进程入口等压缩后体积约 25.91MB。文件内还提供 App.vue 示例、路由与状态管理目录、Travis CI/AppVeyor 持续集成配置及 README 说明结构清晰便于按需查阅。目前已有 465 人学习适合具备一定 Vue 基础、想了解 Electron-vue 脚手架与 Element UI 实际联动的开发者参考。1. 一个 electron-vue.zip 背后模板压缩包到底省了哪几步打开一个 electron-vue.zip看到的往往不是项目源码而是一整套能直接npm install npm run dev的骨架Electron 主进程、Vue 渲染层、预加载脚本、打包配置一次给齐。这个压缩包解决的不是能不能跑而是三套 Node 环境怎么共存——主进程跑在 Node 里渲染进程跑在 Chromium 里两者还要通过 IPC 对话任何一层配置错了窗口就是一片白。对五年以上的前端或桌面端开发者来说这个 zip 的价值在边界哪些依赖进 dependencies哪些进 devDependencies为什么预处理脚本能在 Vite 里工作却在打包后失效serialport 这类原生模块为什么每次升级 Electron 都要重编。下面按我平时接手这类模板的顺序拆先读结构再打通开发链路最后处理打包和排错。2. 读懂 electron-vue.zip 的目录三份 package.json 与 preload 桥接拿到压缩包后第一件事不是npm install而是先分清哪个 package.json 属于谁。典型模板会把 Electron 主进程、Vue 渲染层和项目根分开放有的还带独立 preload 目录。三套代码跑在三种运行时里主进程是 Node.js 环境渲染进程是 Chromium 环境Vue 代码和浏览器里几乎没差别差别就在 preload 这一层——它是唯一能同时摸到 Node API 和 DOM 的地方也是安全配置的咽喉。2.1 主进程、渲染进程与 preload 各自负责什么目录/文件运行时职责是否打进安装包electron/main.jsNode.js创建窗口、生命周期、IPC、原生菜单是electron/preload.js隔离上下文通过 contextBridge 暴露白名单 API是src/ChromiumVue 组件、路由、状态管理是构建为 dist根 package.json构建工具同时管理两条启动链路的脚本否常见模板在根 package.json 的 devDependencies 里放 electron、vite、electron-builder在 dependencies 里只放运行时确实需要的库。判断依据很简单渲染进程的依赖要打进包原生模块和主进程依赖也要在打包机安装纯构建工具放 devDependencies 能显著缩小安装包体积。若觉得多进程目录太绕也可以换 electron-vite 这类单配置脚手架它把 main、preload、renderer 三段配置放在同一个文件里原理与手拆目录完全一致只是把读模板变成了读配置。2.2 contextIsolation 下最小 IPC 通道老教程里renderer.require(electron)的做法现在默认被禁nodeIntegration: false时渲染进程没有 requirecontextIsolation: true时连 window 对象也被隔离。正确姿势是 preload 里用 contextBridge 暴露方法渲染层只调白名单函数。// electron/preload.js只在 preload 里可以 require渲染层不行 const { contextBridge, ipcRenderer } require(electron) contextBridge.exposeInMainWorld(appAPI, { // invoke 走 Promise适合点按钮弹出系统对话框这类场景 selectFile: () ipcRenderer.invoke(dialog:selectFile), // 主进程菜单推送事件时渲染层通过回调接收 onOpenFile: (callback) { const listener (_event, payload) callback(payload) ipcRenderer.on(menu:openFile, listener) // 返回清理函数组件卸载时调用防止重复订阅 return () ipcRenderer.removeListener(menu:openFile, listener) } })主进程对应注册 handle// electron/main.js主进程收到 invoke 请求后真正打开系统对话框 ipcMain.handle(dialog:selectFile, async () { const { canceled, filePaths } await dialog.showOpenDialog({ properties: [openFile] }) return canceled ? null : filePaths[0] })这段代码的执行顺序是渲染层调用window.appAPI.selectFile()contextBridge 把请求转成ipcRenderer.invoke主进程 handle 打开系统对话框结果沿 Promise 链路返回。注意 preload 里不能把整个 ipcRenderer 直接抛出去那样等于关闭了白名单约束每个暴露的方法都要显式声明参数也要在 preload 里做类型校验。提示如果渲染层报window.appAPI is undefined先确认 preload 路径是否写对。path.join(__dirname, preload.js)里的__dirname是主进程文件所在目录不是项目根目录这也是模板压缩包最常见的路径错误点。2.3 Vue Router 用 hash 模式的原因打包后主进程用loadFile加载 dist/index.html文件协议下历史路由的pushState会失效——刷新或深层链接都找不到对应 html。模板里若已配置createWebHashHistory()就是为打包场景准备的路径变成#/about纯前端变化不触发文件请求。若坚持用 history 模式就得在主进程加will-navigate拦截或注册自定义协议维护成本高对桌面应用收益很小。3. 开发模式双进程协作让 Vue 开发服务器和 Electron 同时启动electron-vue 模板真正省时间的不是打包配置而是把 Vite 和 Electron 两个进程串成一条命令。Vite 提供热更新Electron 负责把页面装进窗口两条链路之间靠环境变量传地址。这个变量的命名和传递方式不统一正是打包后打不开页面的头号原因。3.1 用环境变量区分 dev 和 loadFile变量dev 阶段打包后VITE_DEV_SERVER_URLhttp://localhost:5173未定义NODE_ENVdevelopmentproduction主进程启动时按此分支有地址就loadURL没有就loadFile。所以模板里isDev的判断通常是!!process.env.VITE_DEV_SERVER_URL !app.isPackaged双条件app.isPackaged兜底防止手动导出变量误判。3.2 一条命令拉起两条进程# 常见模板的 dev 脚本用 concurrently 并行wait-on 保证时序 npm run dev对应的 scripts 配置写在根 package.json 里。JSON 不支持注释用_comment字段说明用途执行时会被 npm 安全忽略{ scripts: { dev: concurrently -k -n renderer,main \npm:dev:renderer\ \npm:dev:electron\, dev:renderer: vite --port 5173 --strictPort, dev:electron: wait-on tcp:5173 cross-env VITE_DEV_SERVER_URLhttp://localhost:5173 electron ., build: vite build, dist:win: npm run build electron-builder --win --x64 }, _comment: wait-on 等待 5173 端口就绪后再启动 Electron避免白屏 }# 拆分执行便于观察哪个进程出错 npm run dev:renderer # 另开终端等服务起来后再起 Electron npm run dev:electron这里concurrently只负责并行启动和退出时互相终止真正的时序靠wait-on tcp:5173保证——Electron 必须等服务端口起来才能loadURL否则主进程不报错窗口却是白的。--strictPort是另一个容易被忽略的参数端口被占用时 Vite 默认会换端口而环境变量里写死了 5173两边对不上表现为窗口一直加载失败。-k表示任一进程退出就杀掉另一个避免改了主进程代码后残留旧窗口。3.3 生产构建与页面打不开的排查顺序构建命令通常是npm run build electron-builder但 build 产物路径必须和主进程的loadFile路径一致。典型目录约定是Vite 输出到 dist主进程在 electron/ 下相对路径要写成path.join(__dirname, ../dist/index.html)。很多人打包后双击 exe 白屏第一个动作不是看代码而是去安装目录确认资源是否真被拷进 asar# 在安装目录下查看 app.asar 里的内容Windows 用 7z 或 npx 命令 npx asar list resources/app.asar | grep dist/index.html有这个文件而仍然白屏再回头查 loadFile 路径和 CSP。开发模式正常、打包后才坏的问题九成出在路径基于 __dirname和文件协议下的资源引用这两类下面一章的打包配置就是围绕它们展开的。4. electron-builder 打包配置与 serialport 原生模块重建electron-vue 模板大多自带 electron-builder但能打包和能给别人装之间隔着三个坑asar 里少了文件、安装包体积失控、原生模块 ABI 不匹配。第三个最常见于 serialport 这类带 C 二进制的库每次升级 Electron 都要重新编译否则加载时报版本号不匹配。4.1 最小可用的 electron-builder.ymlappId: com.example.demo productName: DemoApp directories: output: release files: - dist/** - electron/** - package.json asar: true win: target: - nsis nsis: oneClick: false # 关闭一键安装允许用户改安装目录 allowToChangeInstallationDirectory: true extraResources: - from: resources/ # 不进 asar 的外部资源运行时拷贝到 resources 目录 to: resources/# 完整打包命令产物输出到 release/ npm run build electron-builder --win --x64files 字段决定哪些文件进 asar路径相对项目根用 glob 语法Vite 默认原样复制的 static 资源如果被页面引用记得加进 files 或改用 extraResources。extraResources 里的文件应用代码无法用相对__dirname访问必须通过process.resourcesPath拼路径——这个差异是模板代码里最常见的本地能跑、打包就挂来源。4.2 参数速查与体积控制参数作用常见误设asar把应用代码封进单个文件设为 false 后小文件过多安装变慢files入口白名单默认含全项目node_modules 体积失控extraResources外部资源目录与 files 混用导致路径错误artifactName产物文件名不设时含空格内网分发常被拦截打包后常见反应是怎么 80 兆。Electron 本体加 Chromium 就有 60M 以上真正能砍的是 dependencies 里被无意识带进的构建工具。建议打包前去node_modules检查哪些包只在构建时用挪进 devDependencies 再打一次看体积差。如果对体积敏感electron-builder 的electronDownload镜像配置也能省下载时间但那是另一个话题这里不展开。4.3 serialport 等原生模块的 ABI 重建# 安装依赖后必须针对 Electron 的 Node 版本重新编译原生模块 npm install npx electron/rebuild -f -w serialport npm run devElectron 内置 Node 版本和系统 Node 版本不同serialport 编译产物针对的 ABI 也不一样。安装依赖后必须用electron/rebuild重编一次否则运行时抛NODE_MODULE_VERSION不匹配的错误。重建完立刻npm run dev验证不要等到打包后再查。electron-builder 默认在打包前也会尝试 rebuild但失败时常静默跳过所以显式执行一次更可靠。换成 node-hid、robotjs 等原生库时把-w后面的包名替换即可流程完全相同。5. electron-vue 打包后现场菜单、m3u8 与产物验证5.1 菜单快捷键在菜单模板里统一注册// electron/main.js菜单点击通过 webContents.send 推给渲染层 const template [ { label: 文件, submenu: [ { label: 打开, accelerator: CmdOrCtrlO, click: () mainWindow.webContents.send(menu:openFile) } ] } ] Menu.setApplicationMenu(Menu.buildFromTemplate(template))这个事件的接收端是第 2.2 节 preload 里暴露的onOpenFile渲染层组件挂载时订阅、卸载时清理与 IPC 通道形成完整闭环。5.2 页面播放 m3u8 的资源路径与 CSP打包后页面从 file:// 加载而 m3u8 分片流通常来自 https 地址。Vite 模板默认的严格 CSP 会拦截媒体请求需要在 index.html 的 meta 里显式放行流媒体域名meta http-equivContent-Security-Policy contentdefault-src self; connect-src self https://cdn.example.com本地 m3u8 文件则不要把 file 路径直接塞给 video 标签跨域规则下原生播放器会被卡死常见做法是用 hls.js 走 http 或自定义协议取流import Hls from hls.js if (Hls.isSupported() videoEl.canPlayType(application/vnd.apple.mpegurl) ) { const hls new Hls({ maxBufferLength: 30 }) hls.loadSource(https://cdn.example.com/stream.m3u8) hls.attachMedia(videoEl) }5.3 用远程调试端口验证打包产物# 打包后的无源码 exe打开远程调试端口 ./release/win-unpacked/DemoApp.exe --remote-debugging-port8315启动后本机浏览器访问http://localhost:8315就能看到渲染进程的 console 和 DOM这是打包后白屏问题的排错入口。两个判断法则贴近现场渲染层拿不到数据先检查 preload 白名单是否暴露了对应方法打包后才出的问题先查 asar 资源与 CSP再查文件路径最后才考虑原生模块重建。本文还有配套的精品资源点击获取
返回列表