Electron 实时更新允许已安装的桌面应用下载新的渲染层 bundle,并在下次启动时加载。这对于 JavaScript、HTML、CSS 和静态资源的修复非常有用,无需签发新的安装程序。
这并不能替代正常的 Electron 二进制更新流程。对 /src-electron/electron-main、预加载脚本、原生依赖、Electron 本身、包元数据、代码签名或安装程序配置的更改仍然需要发布新的桌面版本。
一个开源选择是 @capgo/electron-updater。它将下载的 bundle 存储在 Electron 的用户数据目录中,通过预加载桥暴露有限的更新 API,并且如果应用没有确认正确启动,可以回滚 bundle。下面的手动流程不需要托管账户;你只需提供一个 HTTPS 元数据端点和存放 bundle zip 的存储空间。
安装
更新器由 Electron 主进程和预加载脚本使用,所以从 Electron 目录安装:
cd src-electron$ yarn add @capgo/electron-updater主进程
在 /src-electron/electron-main.js 中创建一个 updater 实例,用 BrowserWindow 初始化它,并用它加载当前的生产 bundle。在开发模式下,继续加载 Quasar dev server。
import { app, BrowserWindow } from 'electron'
import path from 'node:path'
import {
ElectronUpdater,
setupEventForwarding,
setupIPCHandlers
} from '@capgo/electron-updater'
const updater = new ElectronUpdater({
appId: 'com.example.desktop',
autoUpdate: false,
statsUrl: ''
})
async function createWindow() {
const mainWindow = new BrowserWindow({
// ...
webPreferences: {
contextIsolation: true,
preload: path.join(import.meta.dirname, 'electron-preload.cjs')
}
})
await updater.initialize(
mainWindow,
path.join(import.meta.dirname, 'index.html')
)
setupIPCHandlers(updater)
setupEventForwarding(updater, mainWindow)
if (import.meta.env.QUASAR_DEV) {
await mainWindow.loadURL(import.meta.env.QUASAR_APP_URL)
} else {
await mainWindow.loadFile(updater.getCurrentBundlePath())
}
}
void app.whenReady().then(() => {
createWindow()
})appId 应该是你桌面应用的稳定标识符。示例中禁用了自动检查,这样你的应用可以自行决定何时向更新端点查询新的 bundle。
预加载脚本
从 /src-electron/electron-preload.js 暴露更新器 API。保留任何已有的 Quasar 运行时桥接代码。
import { contextBridge } from 'electron'
import { exposeUpdaterAPI } from '@capgo/electron-updater/preload'
import { quasarRuntime } from '#q-app/electron/preload'
contextBridge.exposeInMainWorld('quasarRuntime', quasarRuntime)
exposeUpdaterAPI()渲染进程
UI 启动后调用 notifyAppReady()。这会告诉更新器当前 bundle 是有效的。如果在配置的超时时间内没有调用此方法,更新器会认为该 bundle 失败并回滚。
if (import.meta.env.QUASAR_ELECTRON_MODE) {
await window.electronUpdater?.notifyAppReady()
}对于手动自托管流程,获取你自己的更新元数据,下载 zip 并排队等待下次应用启动时应用:
const syncUpdate = async () => {
const updater = window.electronUpdater
if (!updater) {
return
}
const response = await fetch(
'https://updates.example.com/desktop/latest.json'
)
if (!response.ok) {
return
}
const update = await response.json()
if (!update?.url || !update?.version) {
return
}
const bundle = await updater.download({
url: update.url,
version: update.version,
checksum: update.checksum
})
await updater.next({ id: bundle.id })
}你的端点可以是一个简单的 JSON 文件或 API 响应:
{
"version": "1.0.1",
"url": "https://updates.example.com/desktop/1.0.1.zip",
"checksum": "SHA256_CHECKSUM"
}如果你想在自己的确认 UI 后立即应用更新,使用 set(...) 代替 next(...):
await updater.set({ id: bundle.id })发布更新
构建 Electron 应用但不打包成安装程序:
$ quasar build -m electron --skip-pkg渲染进程文件会生成在 /dist/electron/UnPackaged。将属于 web bundle 的文件(如 index.html、assets/ 以及从 /public 复制的文件)准备好,然后用 CLI 创建 zip:
$ npx @capgo/cli@latest bundle zip --path dist/electron/live-update传给 bundle zip 的文件夹根目录必须包含 index.html。将生成的 zip 上传到你自己的 HTTPS 存储,并更新元数据端点指向它。
WARNING
请通过 HTTPS 提供更新元数据和 bundle,保持校验和启用,并且只通过实时更新发布渲染层的变更。任何影响 Electron 主进程/预加载代码或打包应用的更改都应通过签名的桌面发布流程进行。
托管方案
如果你不想自己运维更新 API、bundle 存储、通道、回滚和分析,Capgo Cloud 为同一个更新器包提供了托管方案。你可以先使用上面的自托管流程,之后如果需要托管基础设施再迁移到托管服务。