为什么捐赠
API 浏览器
升级指南
NEW!
创建新项目
quasar.config 配置文件
从 Webpack 项目转换
浏览器兼容性
TypeScript 支持
目录结构
命令列表
CSS 预处理器
使用 VueRouter 进行页面路由
懒加载 - 代码分割
资源处理
Boot 文件
预取特性
API 代理
配置 Vite
处理 import.meta.env
使用 Pinia 管理状态
代码检查与格式化
测试与审计
开发移动应用
Ajax 请求
开放开发服务器到公网
联系站长
Quasar CLI with Vite - @quasar/app-vite
Electron 实时更新

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。

/src-electron/electron-main file

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 运行时桥接代码。

/src-electron/electron-preload file

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.htmlassets/ 以及从 /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 为同一个更新器包提供了托管方案。你可以先使用上面的自托管流程,之后如果需要托管基础设施再迁移到托管服务。