Files
ele-HeiXiu/electron/main/load-env.ts
YoungestSongMo 6204c14b88 feat: 重构更新流程 — 无更新不抛异常、用户决定下载、更新详情展示(md文件中的)
【核心重构】
  - getLatestVersion() 不再 throw Error,无更新时返回 { version: APP_VERSION }
  - checkForUpdates() 先自行预检 → 无更新直发 IPC,有更新才交 electron-updater
  - 移除 NO_UPDATE_MESSAGE 常量及所有字符串匹配拦截代码
  - HeiXiuProvider 增加 500ms TTL 缓存,避免预检+electron-updater 重复请求 API

  【用户体验】
  - 检查到新版本后不再自动下载,展示更新内容供用户决定
  - 新增"下载更新"按钮(与"安装更新"分离为两步操作)
  - 设置页新增"查看详情"弹窗,Markdown 格式化渲染更新日志
  - available / downloading / downloaded 三个状态 UI 独立展示

  【Bug 修复】
  - 测试服务器版本排序:字符串序 → 语义版本序(_version_key),0.0.10 正确 > 0.0.9
  - 版本比较:!= → <(_version_key),防止高版本误判为有更新
  - get_best_release fallback 同样改为语义版本排序
  - Windows cmd set 命令尾部空格 → Invalid URL(.trim() 修复)
  - electron-updater 'error' 事件中拦截 NO_UPDATE_MESSAGE → UPDATE_NOT_AVAILABLE

  【文档更新】
  - CHANGELOG.md、PROJECT.md、UpdateA.md 同步更新架构图和流程说明
2026-06-04 18:31:52 +08:00

93 lines
3.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 主进程 .env 加载器:.env.{mode} → .env.local → OS 环境变量(后者覆盖前者)
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
// ESM 中 __dirname 不可用,手动计算
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
/**
* 解析单个 .env 文件,将 key=value 写入 process.env。
* 已存在的 process.env 值不会被覆盖OS 环境变量优先)。
* 返回成功加载的变量数。
*/
function parseEnvFile(filePath: string, fileName: string): number {
try {
const content = readFileSync(filePath, 'utf-8');
let count = 0;
for (const line of content.split('\n')) {
const trimmed = line.trim();
// 跳过空行和注释
if (!trimmed || trimmed.startsWith('#')) continue;
// 解析 key=value
const eqIdx = trimmed.indexOf('=');
if (eqIdx === -1) continue;
const key = trimmed.slice(0, eqIdx).trim();
let value = trimmed.slice(eqIdx + 1).trim();
// 去除引号(支持 "value" 和 'value'
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
}
// 不覆盖已在 OS 环境变量中设置的值
if (key && !process.env[key]) {
process.env[key] = value;
count++;
}
}
if (count > 0) {
console.log(`[load-env] 从 ${fileName} 加载了 ${count} 个环境变量`);
}
return count;
} catch (err) {
// 文件不存在 — 静默跳过(打包后 .env.* 不在 ASAR 中,这是正常情况)
if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
return 0;
}
// 其他错误(权限、编码等)— 警告但不中断
console.warn(`[load-env] 读取 ${fileName} 失败:`, (err as Error).message);
return 0;
}
}
/**
* 加载环境变量文件到 process.env。
* 开发模式加载 .env.development生产模式加载 .env.production
* 之后再加载 .env.local 作为覆盖层。
*/
export function loadEnvFile(): void {
// 项目根目录
// APP_ROOT 在 main.ts 中设置dist-electron/.. = 项目根)
// fallbackdist-electron/main/load-env.js → __dirname/../.. = 项目根
const projectRoot = process.env.APP_ROOT || join(__dirname, '..', '..');
// 确定当前模式
const mode =
!process.env.NODE_ENV || process.env.NODE_ENV === 'development'
? 'development'
: 'production';
console.log(
`[load-env] 模式: ${mode}, projectRoot: ${projectRoot}`,
);
// ① 基础环境文件(按模式选择)
const baseFile = `.env.${mode}`;
parseEnvFile(join(projectRoot, baseFile), baseFile);
// ② 本地覆盖文件(不进 git用于打包后连测试服务器等特殊场景
const localFile = '.env.local';
parseEnvFile(join(projectRoot, localFile), localFile);
}