From 9fee6f2da541e485e73b7d9e68cf2d301a50cc3e Mon Sep 17 00:00:00 2001 From: AskaEth Date: Sun, 13 Sep 2026 15:25:01 +0800 Subject: [PATCH] =?UTF-8?q?fix(installer):=20=E5=AE=89=E8=A3=85=E5=99=A8?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E4=B8=8D=E8=83=BD=E5=B8=A6=20BOM=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20=E5=AE=83=E4=BC=9A=E6=8B=BC=E8=BF=9B=E5=A4=A7?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E4=B8=AD=E9=97=B4=E8=AE=A9=20makensis=20?= =?UTF-8?q?=E6=8A=A5=20Invalid=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 构建机上真实失败:`Invalid command: "?;"` / `Error in script "" on line 83`。 本机单编这个脚本一切正常,只有 electron-builder 出包才炸。 根因:electron-builder 把「它的共享头部 + 我们的脚本」拼成一个整脚本、经 stdin 喂给 makensis, 而 Node 的 readFileSync(…, 'utf8') **不会**吃掉文件开头的 BOM —— 那个 U+FEFF 落在拼接结果 中间某一行的行首,makensis 就把它当成命令名的一部分(控制台显示成问号)。 - 去掉 console/installer/installer.nsi 的 UTF-8 BOM - deploy/prepare-extra.mjs 的检查反向:从「必须有 BOM」改成「必须没有 BOM」,并把原因写进注释, 避免下一个人再按直觉加回去;中文编码改由 makensis 的 -INPUTCHARSET UTF8 保证 (electron-builder 本来就会传这个参数,本机手工编译也要带) 验证:无 BOM → prepare-extra 退出 0;临时加回 BOM → 退出 1 且提示准确。 --- console/installer/installer.nsi | 2 +- deploy/prepare-extra.mjs | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/console/installer/installer.nsi b/console/installer/installer.nsi index 571976c..587c2c4 100644 --- a/console/installer/installer.nsi +++ b/console/installer/installer.nsi @@ -1,4 +1,4 @@ -; ============================================================================= +; ============================================================================= ; 赛事积分榜 安装器 —— 完全自绘的五页向导 ; ; 这是 electron-builder 的「自定义 installer 脚本」(package.json 的 build.nsis.script)。 diff --git a/deploy/prepare-extra.mjs b/deploy/prepare-extra.mjs index ad9e4d2..1097407 100644 --- a/deploy/prepare-extra.mjs +++ b/deploy/prepare-extra.mjs @@ -34,18 +34,22 @@ for (const doc of docsToStage) { } // ---- 1b. 自绘安装器脚本的编码检查 ------------------------------------------- -// 本机手工跑 makensis 时必须带 UTF-8 BOM,否则脚本里的中文直接被判成 Bad text encoding; -// electron-builder 那边传了 -INPUTCHARSET UTF8,构建机上没 BOM 也能过 —— 两边口径不一致, -// 出问题时只会表现为「本地编不过、构建机编得过」这种最难查的差异,所以统一要求带 BOM。 +// 这条检查要求**没有** BOM —— 方向反直觉,但踩过一次真实的构建失败: +// electron-builder 把「它自己的共享头部 + 我们的脚本」拼成一个整脚本、经 stdin 喂给 makensis, +// 而 Node 的 readFileSync(…, 'utf8') **不会**吃掉文件开头的 BOM:那个 U+FEFF 会落在拼接结果 +// 中间某一行的行首,makensis 报 `Invalid command: "?;"`(BOM 被控制台显示成问号), +// 且报的是拼接后的行号 —— 本地单编这个脚本时一切正常,只有构建机才炸,极难定位。 +// 中文编码由 makensis 的 `-INPUTCHARSET UTF8` 保证(electron-builder 会传这个参数); +// 本机手工编译时同样带上它,**不要靠加 BOM**。 const installerScript = join(root, 'console', 'installer', 'installer.nsi') if (existsSync(installerScript)) { const head = readFileSync(installerScript).subarray(0, 3) - if (!(head[0] === 0xef && head[1] === 0xbb && head[2] === 0xbf)) { - console.error(` [installer] ${installerScript} 缺少 UTF-8 BOM:本机 makensis 会报 Bad text encoding`) - console.error(' [installer] 修复:用编辑器另存为「UTF-8 with BOM」,或跑 python3 -c "…" 补 BOM') + if (head[0] === 0xef && head[1] === 0xbb && head[2] === 0xbf) { + console.error(` [installer] ${installerScript} 带了 UTF-8 BOM:它会被拼进大脚本中间,`) + console.error(' [installer] 构建时 makensis 报 Invalid command: "?;"。请另存为不带 BOM 的 UTF-8。') process.exit(1) } - console.log(' installer script has UTF-8 BOM') + console.log(' installer script has no BOM (required by the build)') } // ---- 2. installer custom script ---------------------------------------------