feat(M7): electron-builder packaging (MSI + NSIS) + electron-updater

- electron-builder.yml: msi(fixed upgradeCode)+nsis x64, asarUnpack node-pty/ssh2, npmRebuild off, publish generic for latest.yml
- updater: packaged-only, OT_UPDATE_URL/OT_UPDATE_TOKEN env, ready+5s check, warn-only failures; auto-update channel is NSIS (MSI not supported by electron-updater)
- scripts dist/dist:dir; win-unpacked smoke verified (native modules load)
This commit is contained in:
954801926@qq.com committed 2026-09-06 20:48:17 +08:00
1 parent fa83097528
commit 2a32ee910a
4 files changed
+110 -2

No files matched your search

+50
View File
@@ -0,0 +1,50 @@
appId: site.codingplan.openterminal
productName: OpenTerminal
directories:
output: release
files:
- out/**
- package.json
asar: true
asarUnpack:
- "**/node_modules/@lydell/node-pty/**"
- "**/node_modules/ssh2/**"
# @lydell/node-pty ships prebuilt binaries; do not trigger a rebuild.
npmRebuild: false
# Electron-updater only supports NSIS auto-updates (MSI has no update channel).
# The NSIS .exe + latest.yml get uploaded together; MSI is manual/enterprise only.
win:
target:
- target: msi
- target: nsis
msi:
oneClick: false
# Fixed upgrade code keeps the upgrade chain consistent across releases.
upgradeCode: "{5ab9f79e-e4eb-4052-9df6-3af3a301ab0a}"
artifactName: ${productName}-${version}-setup.${ext}
# No build/icon.ico exists. The WiX template only emits <Icon> when an icon is
# set, but the shortcut elements still reference Icon=<iconId>, so MSI linking
# fails with LGHT0094. Disabling MSI shortcuts drops the dangling reference.
# NSIS still creates its shortcuts independently.
createDesktopShortcut: false
createStartMenuShortcut: false
nsis:
oneClick: false
allowToChangeInstallationDirectory: true
perMachine: false
artifactName: ${productName}-${version}-setup.${ext}
# Declaring a publish provider makes electron-builder emit the update-info file
# (latest.yml) into directories.output for upload. No token is stored here; the
# main agent handles feed authentication during upload. Build runs with the
# default publish policy, so nothing is uploaded from this script.
publish:
provider: generic
url: https://git.codingplan.site/api/packages/admin/generic/openterminal-update/stable/
+4 -2
View File
@@ -1,7 +1,7 @@
{ {
"name": "open-terminal", "name": "open-terminal",
"productName": "OpenTerminal", "productName": "OpenTerminal",
"version": "0.1.0", "version": "0.7.0",
"description": "Terminal with split panes, themes and fonts (XTerminal-inspired)", "description": "Terminal with split panes, themes and fonts (XTerminal-inspired)",
"main": "out/main/index.js", "main": "out/main/index.js",
"author": "Bill", "author": "Bill",
@@ -10,7 +10,9 @@
"dev": "electron-vite dev", "dev": "electron-vite dev",
"build": "electron-vite build", "build": "electron-vite build",
"preview": "electron-vite preview", "preview": "electron-vite preview",
"typecheck": "tsc --noEmit -p tsconfig.node.json && tsc --noEmit -p tsconfig.web.json" "typecheck": "tsc --noEmit -p tsconfig.node.json && tsc --noEmit -p tsconfig.web.json",
"dist": "electron-vite build && electron-builder --win msi nsis",
"dist:dir": "electron-vite build && electron-builder --win --dir"
}, },
"dependencies": { "dependencies": {
"@lydell/node-pty": "^1.2.0-beta.15", "@lydell/node-pty": "^1.2.0-beta.15",
+2
View File
@@ -3,6 +3,7 @@ import { join } from 'path'
import { registerIpc } from './ipc' import { registerIpc } from './ipc'
import { killAllPtys } from './pty' import { killAllPtys } from './pty'
import { applyStartupSystemSettings, loadSettings } from './settingsStore' import { applyStartupSystemSettings, loadSettings } from './settingsStore'
import { configureAutoUpdater } from './updater'
function createWindow(): void { function createWindow(): void {
const win = new BrowserWindow({ const win = new BrowserWindow({
@@ -54,6 +55,7 @@ app.whenReady().then(() => {
// settings dialog is never opened this run. // settings dialog is never opened this run.
applyStartupSystemSettings(loadSettings()) applyStartupSystemSettings(loadSettings())
createWindow() createWindow()
configureAutoUpdater()
app.on('activate', () => { app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow() if (BrowserWindow.getAllWindows().length === 0) createWindow()
+54
View File
@@ -0,0 +1,54 @@
import { app } from 'electron'
import { autoUpdater } from 'electron-updater'
/**
* Default update feed (generic provider). The main agent uploads latest.yml and
* the NSIS installer to this stable path.
*
* KNOWN LIMITATION: electron-updater does NOT support MSI auto-updates. The
* update channel always runs through the NSIS .exe (latest.yml + .exe are
* uploaded together). MSI is manual/enterprise distribution only.
*/
const DEFAULT_FEED_URL =
'https://git.codingplan.site/api/packages/admin/generic/openterminal-update/stable/'
export function configureAutoUpdater(): void {
// Update checks only run in packaged builds; no-op during development.
if (!app.isPackaged) {
return
}
const url = process.env.OT_UPDATE_URL || DEFAULT_FEED_URL
const token = process.env.OT_UPDATE_TOKEN
autoUpdater.setFeedURL({
provider: 'generic',
url,
...(token ? { requestHeaders: { Authorization: `token ${token}` } } : {})
})
autoUpdater.logger = console
autoUpdater.autoDownload = true
autoUpdater.autoInstallOnAppQuit = true
// Check shortly after startup; log errors without crashing the app.
const timer = setTimeout(() => {
autoUpdater
.checkForUpdatesAndNotify()
.catch((err) => console.warn('[updater] checkForUpdates failed:', err))
}, 5000)
timer.unref?.()
}
/** Public entry point for later UI wiring (not connected this milestone). */
export function checkForUpdates(): Promise<void> {
if (!app.isPackaged) {
return Promise.resolve()
}
return autoUpdater
.checkForUpdates()
.then(() => {})
.catch((err) => {
console.warn('[updater] checkForUpdates failed:', err)
})
}