解决 Actual Budget 在 Windows 系统上的 ESM 加载问题:从报错到完美运行

【免费下载链接】actual A local-first personal finance app 【免费下载链接】actual 项目地址: https://gitcode.com/GitHub_Trending/ac/actual

Actual Budget 作为一款本地优先的个人财务管理应用(A local-first personal finance app),在 Windows 系统上部署时可能会遇到 ESM(ECMAScript Modules)模块加载问题。本文将从问题根源出发,提供详细的分析和解决方案,帮助用户快速定位并修复相关错误。

问题表现与环境分析

在 Windows 系统中启动 Actual Budget 桌面客户端时,常见的 ESM 加载错误包括:

  • Error [ERR_REQUIRE_ESM]: require() of ES Module not supported
  • SyntaxError: Cannot use import statement outside a module
  • 模块路径解析失败(如 ENOENT: no such file or directory

这些问题主要与 Windows 系统的路径处理机制、Node.js 模块加载策略以及 Electron 应用的打包配置相关。从项目结构来看,核心问题文件集中在 packages/desktop-electron/ 目录下,特别是主进程入口文件和构建配置。

项目目录结构示意图

核心问题定位

通过分析 packages/desktop-electron/index.tspackages/desktop-electron/server.ts,可以发现以下关键问题:

1. 模块加载方式冲突

server.ts 中使用了动态 import 加载后端模块:

const bundle = await import(process.env.lootCoreScript);

而 Windows 环境下,当 process.env.lootCoreScript 指向 ESM 模块时,CommonJS 环境下的 require 调用会触发兼容性错误。

2. TypeScript 编译配置问题

tsconfig.dist.json 中配置:

"module": "CommonJS",
"moduleResolution": "node10"

这种配置会将 TypeScript 代码编译为 CommonJS 模块,但项目中部分依赖(如 @actual-app/sync-server)可能以 ESM 格式提供,导致模块系统冲突。

3. Electron 打包路径处理

Windows 系统使用反斜杠 \ 作为路径分隔符,而 Electron 打包过程中若未正确处理路径转换,会导致模块解析失败。在 beforePackHook.ts 中可以看到:

const buildPath = context.packager.projectDir;
const projectRootPath = buildPath + '/../../';

这种硬编码路径拼接在 Windows 下会生成非法路径(如 C:\project/../../)。

分步解决方案

1. 调整 TypeScript 编译配置

修改 tsconfig.dist.json 以支持混合模块系统:

{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  }
}
  • NodeNext 模式允许 TypeScript 正确处理 .mjs.cjs 文件
  • forceConsistentCasingInFileNames 解决 Windows 大小写不敏感的路径问题

2. 修复动态模块加载逻辑

重构 server.ts 中的模块加载代码:

// 替换原有的动态 import
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const bundle = require(process.env.lootCoreScript);

使用 Node.js 内置的 createRequire 方法在 ESM 环境中安全加载 CommonJS 模块,反之亦然。

3. 标准化路径处理

在所有涉及路径操作的文件中(如 index.tsbeforePackHook.ts),使用 path 模块进行路径处理:

import * as path from 'path';

// 替换硬编码路径拼接
const projectRootPath = path.resolve(buildPath, '..', '..');
const lootCoreScript = path.resolve(
  BUILD_ROOT, 
  'loot-core/lib-dist/electron/bundle.desktop.js'
);

这种方式可自动适配 Windows 的路径格式。

4. 配置 Electron 运行时标志

修改 package.json 中的启动脚本:

"scripts": {
  "watch": "cross-env NODE_OPTIONS=--experimental-specifier-resolution=node electron ."
}

添加 --experimental-specifier-resolution=node 标志,启用 Node.js 的 ESM 路径解析算法。

验证与测试

完成上述修改后,通过以下步骤验证修复效果:

  1. 清理构建缓存:
yarn clean
  1. 重新编译项目:
yarn build:dist
  1. 启动开发环境验证:
yarn watch
  1. 执行完整打包流程:
yarn build

若所有步骤顺利完成,Electron 应用应能在 Windows 系统上正常启动,且控制台无模块加载相关错误。可通过 e2e 测试脚本 进一步验证功能完整性。

深层解决方案:模块化架构重构

对于长期维护,建议考虑将 desktop-electron 模块重构为纯 ESM 架构:

  1. package.json 中添加 "type": "module" 声明
  2. 将所有 .ts 文件的模块导入语法统一为 ESM 格式
  3. 使用 import.meta.url 替代 __dirname__filename
  4. 使用 vite-electron-plugin 优化构建流程

这种架构调整可从根本上解决模块系统冲突,同时提升开发体验和构建效率。

总结

Windows 系统上的 ESM 加载问题是 Actual Budget 部署过程中的常见障碍,但通过合理的配置调整和代码重构完全可以解决。本文提供的解决方案涵盖了从紧急修复到架构优化的完整路径,用户可根据实际场景选择适合的方案。

官方文档:README.md
开发指南:CONTRIBUTING.md
问题反馈:通过项目 Issues 系统提交

通过本文的方法,您应该能够顺利解决 Actual Budget 在 Windows 上的 ESM 加载问题,享受流畅的本地财务管理体验。

【免费下载链接】actual A local-first personal finance app 【免费下载链接】actual 项目地址: https://gitcode.com/GitHub_Trending/ac/actual

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐