mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-15 12:15:16 +00:00
fix(gui): 修发行打包的图标与资源漏装(Linux 包会缺星图依赖)
## 背景 上一提交修了 electron-packager 那条路径的 exe 图标。本提交处理另外两处 同类问题——**都是静默失败**:改了没人知道,坏了要等用户装上才发现。 ## 1) package.json build 段(electron-builder 路径) · files 白名单漏了 icon.ico / icon-tray.png / icon-tray@2x.png ⇒ 这些文件不会被打进包,托盘与窗口图标在发行版里丢失 · 补 win.target/win.icon;注意 electron-builder 的 icon 路径相对 **项目目录**(package.json 所在)解析,不是相对输出目录 (最初写成 'build/icon.ico',那会找不到文件 —— 已用存在性判据钉住) · icon.ico 含 256x256,满足 electron-builder 对 win 图标的要求 ## 2) deploy/packaging/package-linux.sh(Linux 发行实际走这条) 原实现手工 cp 七个文件: main.js / preload.js / package.json renderer/{index.html, app.js, style.css, mascot.svg} 实测漏掉: · renderer/mascot.svg —— 源码里根本不存在(真名 mascot.webp) · icon.svg / icon.ico / icon-tray*.png · renderer/icon.svg · renderer/vendor/* ★★ 本次本地化新增的四个第三方库 (three/OrbitControls/marked/purify) ⇒ Linux 发行包装完星图与 Markdown 渲染直接坏, 且**没有任何构建报错** 改为: · renderer 按目录整体同步(cp -r "$gui_dir/renderer/.") · 根级 *.svg / *.ico / icon-tray*.png 同步 · 新增必备文件校验:vendor 四库与 icon.svg 缺任一 ⇒ 报错并删目录跳过, 沿用本脚本既有的"宁可不发,也不发装了跑不起来的包"原则 ## 判据 新增 cmd/gui/package-config.test.mjs(进 npm test),14 条断言覆盖三条 打包路径的配置一致性。已做变异测试:Makefile 去 --icon、files 去 icon.ico、 package-linux.sh 还原逐文件 cp,三者均判红。 判据:cmd/gui npm test 全绿(60 条)。
This commit is contained in:
139
cmd/gui/package-config.test.mjs
Normal file
139
cmd/gui/package-config.test.mjs
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
// GUI 发行打包配置的一致性判据。
|
||||||
|
//
|
||||||
|
// ## 要判的是什么
|
||||||
|
//
|
||||||
|
// 两条打包路径的配置各自漏过东西,且都是**静默**失败:
|
||||||
|
//
|
||||||
|
// 1) electron-packager(make build-gui,Windows 发行 + 本机安装都走它)
|
||||||
|
// · 曾漏 --icon=icon.ico ⇒ exe 一直是 Electron 默认图标
|
||||||
|
// (已修:Makefile e79eff6)
|
||||||
|
//
|
||||||
|
// 2) package.json 的 build 段(electron-builder,Linux 发行走它)
|
||||||
|
// · files 白名单漏了 icon.ico / icon-tray*.png ⇒ 图标不进包
|
||||||
|
// · win.icon 路径写错(electron-builder 相对**项目目录**解析,
|
||||||
|
// 写 'build/icon.ico' 会找不到文件)
|
||||||
|
//
|
||||||
|
// 3) deploy/packaging/package-linux.sh 的手工组装曾逐文件 cp 七个文件,
|
||||||
|
// 漏掉 renderer/vendor/*(本地化的 four 个库)与全部图标文件
|
||||||
|
// ⇒ Linux 发行包装完星图与托盘图标直接坏,且**没有任何构建报错**
|
||||||
|
// (已修:改目录整体同步 + 必备文件校验)
|
||||||
|
//
|
||||||
|
// 打包配置类问题的特点是"改了没人知道、坏了要等用户装上才发现",
|
||||||
|
// 所以在这里钉死。
|
||||||
|
//
|
||||||
|
// 运行:node package-config.test.mjs
|
||||||
|
|
||||||
|
import { readFileSync, existsSync } from "node:fs";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
|
||||||
|
const here = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const repoRoot = join(here, "..", "..");
|
||||||
|
const guiDir = here;
|
||||||
|
|
||||||
|
let failures = 0;
|
||||||
|
const check = (name, ok, detail) => {
|
||||||
|
if (ok) console.log(` ✓ ${name}`);
|
||||||
|
else {
|
||||||
|
failures++;
|
||||||
|
console.log(` ✗ ${name}${detail ? " — " + detail : ""}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── 1) Makefile: electron-packager 必须带 --icon ──────────────────────
|
||||||
|
const mk = readFileSync(join(repoRoot, "Makefile"), "utf8");
|
||||||
|
const buildGui = mk.slice(
|
||||||
|
mk.indexOf("build-gui:"),
|
||||||
|
mk.indexOf("\nbuild-static:"),
|
||||||
|
);
|
||||||
|
|
||||||
|
check("能定位 build-gui 目标", buildGui.length > 0);
|
||||||
|
check(
|
||||||
|
"★ build-gui 传 --icon(否则 exe 一直是 Electron 默认图标)",
|
||||||
|
/--icon[= ]\S*icon\.ico/.test(buildGui),
|
||||||
|
"缺 --icon ⇒ exe 内嵌图标为 Electron 默认",
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
"build-gui 仍带 --no-sandbox",
|
||||||
|
/--no-sandbox/.test(buildGui),
|
||||||
|
"--no-sandbox 没了,本机可能起不来",
|
||||||
|
);
|
||||||
|
|
||||||
|
// ── 2) package.json build 段 ─────────────────────────────────────────
|
||||||
|
const pkg = JSON.parse(readFileSync(join(guiDir, "package.json"), "utf8"));
|
||||||
|
const files = pkg.build?.files || [];
|
||||||
|
|
||||||
|
check(
|
||||||
|
"★ files 白名单含 icon.ico",
|
||||||
|
files.includes("icon.ico"),
|
||||||
|
"files = " + JSON.stringify(files),
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
"files 白名单含托盘图标",
|
||||||
|
files.includes("icon-tray.png") && files.includes("icon-tray@2x.png"),
|
||||||
|
"缺 icon-tray*.png ⇒ 托盘图标在发行包里丢失",
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
"files 含 renderer/**/*(含 vendor/)",
|
||||||
|
files.some((f) => f.startsWith("renderer/")),
|
||||||
|
"renderer 未列入 ⇒ vendor 库不会进包",
|
||||||
|
);
|
||||||
|
|
||||||
|
// ── 3) win.icon 路径语义 ─────────────────────────────────────────────
|
||||||
|
// electron-builder 的 icon 相对**项目目录**(package.json 所在)解析。
|
||||||
|
// 写成 'build/icon.ico'(相对输出目录)会找不到文件。
|
||||||
|
const winIcon = pkg.build?.win?.icon;
|
||||||
|
check("配置了 win.icon", !!winIcon, "未配置 win.icon");
|
||||||
|
if (winIcon) {
|
||||||
|
check(
|
||||||
|
"★ win.icon 路径不是误写的 build/ 前缀",
|
||||||
|
!winIcon.startsWith("build/"),
|
||||||
|
`win.icon='${winIcon}' —— electron-builder 相对项目目录解析,` +
|
||||||
|
"带 build/ 前缀会找不到文件",
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
"win.icon 指向的文件真实存在",
|
||||||
|
existsSync(join(guiDir, winIcon)),
|
||||||
|
`${winIcon} 不存在于 cmd/gui/`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 4) icon.ico 本身要含足够尺寸 ────────────────────────────────────
|
||||||
|
const ico = readFileSync(join(guiDir, "icon.ico"));
|
||||||
|
const isIco = ico.readUInt16LE(0) === 0 && ico.readUInt16LE(2) === 1;
|
||||||
|
check("icon.ico 是合法 ICO", isIco, "头部不是 00 00 01 00");
|
||||||
|
const icoCount = ico.readUInt16LE(4);
|
||||||
|
check(
|
||||||
|
"icon.ico 含多尺寸(含 256x256,electron-builder 需要)",
|
||||||
|
icoCount >= 2,
|
||||||
|
`只含 ${icoCount} 个尺寸`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// ── 5) package-linux.sh 不得再逐文件手列 ────────────────────────────
|
||||||
|
const pkgLinux = readFileSync(
|
||||||
|
join(repoRoot, "deploy", "packaging", "package-linux.sh"),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
"★ package-linux.sh 按目录整体同步 renderer",
|
||||||
|
/cp -r "\$gui_dir\/renderer\/\."/.test(pkgLinux),
|
||||||
|
"仍在逐文件 cp ⇒ 新增资源(如 vendor/)不会被打进 Linux 包",
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
"package-linux.sh 同步根级图标",
|
||||||
|
/cp "\$gui_dir"\/\*\.ico/.test(pkgLinux) &&
|
||||||
|
/icon-tray/.test(pkgLinux),
|
||||||
|
"未同步根级 ico / 托盘图标",
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
"package-linux.sh 有必备文件校验",
|
||||||
|
/vendor\/three\.min\.js/.test(pkgLinux) && /rm -rf "\$gui_out"/.test(pkgLinux),
|
||||||
|
"缺必备文件校验 ⇒ 装完才发现坏包",
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("");
|
||||||
|
if (failures > 0) {
|
||||||
|
console.log(`全部失败:${failures} 条`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("全部通过");
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "electron . --no-sandbox",
|
"start": "electron . --no-sandbox",
|
||||||
"dev": "electron . --no-sandbox --dev",
|
"dev": "electron . --no-sandbox --dev",
|
||||||
"test": "node sse-backoff.test.mjs && node sse-backoff-behavior.test.mjs && node retry-guard.test.mjs && node endpoint-align.test.mjs && node connections-io.test.mjs && node silent-start.test.mjs",
|
"test": "node sse-backoff.test.mjs && node sse-backoff-behavior.test.mjs && node retry-guard.test.mjs && node endpoint-align.test.mjs && node connections-io.test.mjs && node silent-start.test.mjs && node package-config.test.mjs",
|
||||||
"test-live": "node chat-perf.test.mjs && node protocol-align.test.mjs"
|
"test-live": "node chat-perf.test.mjs && node protocol-align.test.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -40,7 +40,16 @@
|
|||||||
"renderer/**/*",
|
"renderer/**/*",
|
||||||
"icon.svg",
|
"icon.svg",
|
||||||
"node_modules/**/*",
|
"node_modules/**/*",
|
||||||
"!node_modules/electron-builder/**"
|
"!node_modules/electron-builder/**",
|
||||||
]
|
"icon.ico",
|
||||||
|
"icon-tray.png",
|
||||||
|
"icon-tray@2x.png"
|
||||||
|
],
|
||||||
|
"win": {
|
||||||
|
"target": [
|
||||||
|
"nsis"
|
||||||
|
],
|
||||||
|
"icon": "icon.ico"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -261,13 +261,43 @@ print(m.group(1) if m else '')
|
|||||||
rm -f "$gui_out/resources/default_app.asar" 2>/dev/null
|
rm -f "$gui_out/resources/default_app.asar" 2>/dev/null
|
||||||
|
|
||||||
# copy app source
|
# copy app source
|
||||||
|
#
|
||||||
|
# ★ 改成**按目录整体同步**,不再逐文件手列。
|
||||||
|
#
|
||||||
|
# 原实现手工 cp 七个文件,每加一个新文件就要记得补一行,漏了不会有
|
||||||
|
# 任何报错,只会做出一个"装完缺东西"的包。已实际漏掉过:
|
||||||
|
# · renderer/mascot.svg —— 源码里根本不存在(真名 mascot.webp)
|
||||||
|
# · icon.svg / icon.ico / icon-tray*.png —— 托盘与窗口图标
|
||||||
|
# · renderer/icon.svg
|
||||||
|
# · renderer/vendor/* —— three/OrbitControls/marked/purify
|
||||||
|
# (这四个是本地化后的第三方库,缺了 Linux 发行版的星图直接坏)
|
||||||
|
#
|
||||||
|
# 整体同步还顺带保证 .hmap 之外的任何新增资源都会进包。
|
||||||
cp "$gui_dir/main.js" "$gui_out/resources/app/"
|
cp "$gui_dir/main.js" "$gui_out/resources/app/"
|
||||||
cp "$gui_dir/preload.js" "$gui_out/resources/app/"
|
cp "$gui_dir/preload.js" "$gui_out/resources/app/"
|
||||||
cp "$gui_dir/package.json" "$gui_out/resources/app/"
|
cp "$gui_dir/package.json" "$gui_out/resources/app/"
|
||||||
cp "$gui_dir/renderer/index.html" "$gui_out/resources/app/renderer/"
|
cp "$gui_dir"/*.svg "$gui_out/resources/app/" 2>/dev/null || true
|
||||||
cp "$gui_dir/renderer/app.js" "$gui_out/resources/app/renderer/"
|
cp "$gui_dir"/*.ico "$gui_out/resources/app/" 2>/dev/null || true
|
||||||
cp "$gui_dir/renderer/style.css" "$gui_out/resources/app/renderer/" 2>/dev/null || true
|
cp "$gui_dir"/icon-tray*.png "$gui_out/resources/app/" 2>/dev/null || true
|
||||||
cp "$gui_dir/renderer/mascot.svg" "$gui_out/resources/app/renderer/" 2>/dev/null || true
|
|
||||||
|
# renderer 整目录同步(含 vendor/ 与全部静态资源)
|
||||||
|
cp -r "$gui_dir/renderer/." "$gui_out/resources/app/renderer/"
|
||||||
|
|
||||||
|
# ★ 必备文件校验:缺了就是"装完坏掉"的包,且不会有任何构建报错。
|
||||||
|
# renderer/vendor 是本地化后的第三方库(three/OrbitControls/marked/purify),
|
||||||
|
# 缺任何一份都会让星图或 Markdown 渲染在断网/离线环境下直接坏掉。
|
||||||
|
local missing=""
|
||||||
|
for _f in index.html app.js style.css vendor/three.min.js vendor/OrbitControls.js \
|
||||||
|
vendor/marked.min.js vendor/purify.min.js; do
|
||||||
|
[ -f "$gui_out/resources/app/renderer/$_f" ] || missing="$_f "
|
||||||
|
done
|
||||||
|
[ -f "$gui_out/resources/app/icon.svg" ] || missing="icon.svg "
|
||||||
|
if [ -n "$missing" ]; then
|
||||||
|
echo " ERROR: GUI 资源缺失:$missing"
|
||||||
|
echo " 宁可不发,也不发装了跑不起来的包。"
|
||||||
|
rm -rf "$gui_out"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# production node_modules for app
|
# production node_modules for app
|
||||||
if [ -d "$gui_dir/node_modules" ]; then
|
if [ -d "$gui_dir/node_modules" ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user