前言
在将 Pomotroid(一款 Electron 桌面番茄工作法计时器)适配到鸿蒙 PC 平台的过程中,我们遇到了多个技术挑战:OpenSSL 兼容性问题 、node-sass ARM64 架构不支持 、webpack-cli 版本不兼容 、模块找不到错误 、contextBridge API 错误等。
本文将详细记录我们如何通过问题排查和系统化解决方案逐一解决这些适配过程中的常见问题,帮助开发者快速定位和解决类似问题。
关键词:鸿蒙PC、Electron适配、Pomotroid、问题排查、WebSocket、模块依赖、IPC通信、Remote模块
文档说明
本文档系统化地记录了在将 Pomotroid 番茄工作法计时器应用适配到鸿蒙PC平台过程中遇到的 10 个典型问题及其详细解决方案。每个问题都包含问题描述、原因分析、解决方案和注意事项,帮助开发者快速定位和解决适配过程中的常见问题。
问题 1:OpenSSL 兼容性问题
问题描述
在构建渲染进程代码时,遇到以下错误:
Error: error:0308010C:digital envelope routines::unsupported
原因分析
Node.js 17+ 版本使用了 OpenSSL 3.0,而旧版本的 webpack 使用了已弃用的 OpenSSL API,导致不兼容。
解决方案
在 package.json 的 dev 脚本中添加 NODE_OPTIONS=--openssl-legacy-provider 环境变量:
json
{
"scripts": {
"dev": "NODE_OPTIONS=--openssl-legacy-provider node .electron-vue/dev-runner.js",
"pack:renderer": "NODE_OPTIONS=--openssl-legacy-provider cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js"
}
}
注意事项
- 此方案适用于 Node.js 17+ 版本
- 如果使用 Node.js 16 或更低版本,可能不需要此配置
- 建议在构建脚本中统一添加,避免在不同环境中出现问题
问题 2:node-sass ARM64 架构不支持
问题描述
在 macOS ARM64 架构上安装依赖时,node-sass 模块编译失败:
Error: Node Sass does not yet support your current environment: OS X Unsupported architecture (arm64)
原因分析
node-sass 是一个已弃用的包,不支持 ARM64 架构(Apple Silicon)。
解决方案
将 node-sass 替换为 sass(Dart Sass):
bash
# 1. 卸载 node-sass
npm uninstall node-sass
# 2. 安装 sass
npm install sass --save-dev --legacy-peer-deps
# 3. 重新安装依赖
npm install --legacy-peer-deps
注意 :sass 是 node-sass 的替代品,API 兼容,但不需要编译原生模块。
问题 3:webpack-cli 版本不兼容
问题描述
使用 npm run pack:renderer 构建渲染进程时,遇到以下错误:
[webpack-cli] TypeError: Cannot read properties of undefined (reading 'getArguments')
原因分析
webpack-cli 版本与 webpack 版本不兼容,或者 webpack-cli 的 API 发生了变化。
解决方案
创建自定义构建脚本,直接使用 webpack API:
javascript
// build-renderer.js
const webpack = require('webpack');
const config = require('./.electron-vue/webpack.renderer.config.js');
webpack(config, (err, stats) => {
if (err) {
console.error(err);
process.exit(1);
}
if (stats.hasErrors()) {
console.error(stats.toString({ colors: true }));
process.exit(1);
}
console.log(stats.toString({ colors: true }));
});
然后在 package.json 中更新脚本:
json
{
"scripts": {
"pack:renderer": "node build-renderer.js"
}
}
问题 4:模块找不到错误(ws、winston)
问题描述
应用运行时出现以下错误:
Cannot find module 'ws'
Cannot find module 'winston'
原因分析
Electron for 鸿蒙PC 应用的模块解析路径与标准 Electron 应用不同,需要将依赖模块复制到应用目录中。
解决方案
-
手动复制模块:
bash# 复制 ws 模块 cp -r pomotroid/node_modules/ws \ ElectronForHarmony_pomotroid/web_engine/src/main/resources/resfile/resources/app/node_modules/ # 复制 winston 模块及其依赖 cp -r pomotroid/node_modules/winston \ ElectronForHarmony_pomotroid/web_engine/src/main/resources/resfile/resources/app/node_modules/ -
添加自定义模块解析逻辑:
javascript// main.js const Module = require('module'); const fs = require('fs'); const nodeModulesPath = path.join(__dirname, 'node_modules'); if (fs.existsSync(nodeModulesPath)) { const originalResolveFilename = Module._resolveFilename; Module._resolveFilename = function(request, parent, isMain) { // 优先从当前目录的 node_modules 查找 if (request === 'ws') { const wsPath = path.join(nodeModulesPath, 'ws', 'index.js'); if (fs.existsSync(wsPath)) { return wsPath; } } // ... 其他模块处理 return originalResolveFilename.apply(this, arguments); }; } -
创建自动化脚本:
bash# copy-dependencies.sh #!/bin/bash SOURCE_DIR="../pomotroid/node_modules" TARGET_DIR="web_engine/src/main/resources/resfile/resources/app/node_modules" mkdir -p "$TARGET_DIR" # 复制必要的模块 cp -r "$SOURCE_DIR/ws" "$TARGET_DIR/" cp -r "$SOURCE_DIR/winston" "$TARGET_DIR/" # ... 复制其他依赖
注意事项
- 需要复制所有直接依赖和间接依赖
- 某些模块可能有平台特定的二进制文件,需要确保兼容性
- 建议使用自动化脚本,避免遗漏依赖
问题 5:contextBridge API 错误
问题描述
在 preload.js 中使用 contextBridge 时出现错误:
contextBridge API can only be used when contextIsolation is enabled
原因分析
contextBridge API 只能在 contextIsolation: true 时使用,但某些 Electron 应用需要 contextIsolation: false 来保持兼容性。
解决方案
如果 contextIsolation 设置为 false,直接暴露到 window 对象:
javascript
// preload.js
// ❌ 错误写法(contextIsolation: false 时)
// contextBridge.exposeInMainWorld('electron', { ... });
// ✅ 正确写法
const electron = require('electron');
const { ipcRenderer } = electron;
// 直接暴露到 window
window.ipcRenderer = ipcRenderer;
window.remote = {
app: {
getPath: (name) => ipcRenderer.sendSync('electron-app-getPath-sync', name),
getVersion: () => ipcRenderer.sendSync('electron-app-getVersion-sync'),
getName: () => ipcRenderer.sendSync('electron-app-getName-sync')
}
};
问题 6:renderer.js 中无法访问 electron.remote
问题描述
在 renderer.js 中访问 electron.remote.app 时返回 undefined。
原因分析
preload.js 中只设置了 window.remote,但代码中可能使用 electron.remote。
解决方案
在 preload.js 中同时设置 window.remote 和 electron.remote:
javascript
// preload.js
const electron = require('electron');
// 创建 remote 代理对象
const remote = {
app: {
getPath: (name) => ipcRenderer.sendSync('electron-app-getPath-sync', name),
// ...
}
};
// 同时设置 window.remote 和 electron.remote
window.remote = remote;
electron.remote = remote;
// 同时设置 electron.app
if (!electron.app) {
electron.app = remote.app;
}
问题 7:Ability 不存在错误
问题描述
安装应用时出现错误:
Error Code:10104001 Error Message:The specified ability does not exist
原因分析
module.json5 中 EntryAbility 的 launchType 配置错误,或 JSON 格式有问题。
解决方案
检查并修正 electron/src/main/module.json5:
json5
{
"module": {
"abilities": [
{
"name": "EntryAbility",
"launchType": "singleton", // ✅ 必须是 "singleton"
// ...
}
]
}
}
注意:
launchType必须是"singleton",不能是"specified"- 确保 JSON 格式正确,没有多余的逗号
问题 8:页面内容未正常展示
问题描述
应用启动后窗口显示,但页面内容为空白或未正常渲染。
原因分析
可能的原因:
renderer.js未正确构建或路径错误__static路径设置不正确- HTML 文件中的脚本路径错误
- 资源文件路径问题
解决方案
-
检查 renderer.js 构建:
bashcd pomotroid npm run pack:renderer # 确保生成的文件存在 ls dist/electron/renderer.js -
检查 index.html 中的脚本路径:
html<!-- ✅ 正确 --> <script type="text/javascript" src="renderer.js"></script> <!-- ❌ 错误 --> <script type="text/javascript" src="./renderer.js"></script> -
检查 __static 路径设置:
javascript// index.html <script> window.__static = require('path') .join(__dirname, '/static') .replace(/\\/g, '\\\\'); </script> -
添加调试日志:
javascript// main.js mainWindowRef.webContents.on('did-finish-load', () => { console.log('Window finished loading'); // 自动打开 DevTools 以便调试 if (process.env.NODE_ENV !== 'production') { mainWindowRef.webContents.openDevTools(); } });
问题 9:WebSocket 连接失败
问题描述
应用启动后,WebSocket 服务器无法正常启动或连接失败。
原因分析
ws模块未正确加载- 端口被占用
- 模块路径解析问题
解决方案
-
确保 ws 模块已复制:
bashls web_engine/src/main/resources/resfile/resources/app/node_modules/ws -
添加模块解析逻辑(见问题 4)
-
检查端口占用:
javascript// main.js function initWebSocket(port) { try { wss = new WebSocket.Server({ port }); console.log(`WebSocket server started on port ${port}`); } catch (e) { console.error('Failed to start WebSocket server:', e); } }
问题 10:主题文件无法加载
问题描述
切换主题时,主题文件无法加载或主题不生效。
原因分析
- 主题文件路径错误
- 主题文件格式不正确
- 主题名称不匹配
解决方案
-
检查主题文件路径:
javascript// Themer.js 中 const localDir = join(__static, 'themes'); console.log('Theme directory:', localDir); -
验证主题文件格式:
json{ "name": "主题名称", "colors": { "--color-background": "#2f384b", // ... 其他颜色 } } -
确保主题名称一致:
- 主题文件中的
name字段 - 主题选择器中的名称
- 文件名(可选,不影响功能)
- 主题文件中的
总结
在适配过程中遇到的主要问题类型:
- 构建工具兼容性:Node.js 版本、webpack 版本、sass 编译器
- 模块依赖管理:Node.js 模块路径解析、依赖复制
- Electron API 兼容性:contextBridge、remote 模块、IPC 通信
- HarmonyOS 平台特性:硬件加速、Ability 配置、资源路径
最佳实践
- 统一环境:使用相同的 Node.js 版本和构建工具版本
- 自动化脚本:创建脚本自动复制依赖和资源文件
- 调试工具:充分利用 DevTools 和日志输出
- 参考文档:参考其他已适配项目的实现方式
- 逐步测试:每完成一个功能就进行测试,避免问题累积