文章目录
-
- 一、写在前面
- 二、项目背景
- 三、总体变化概览
-
- [3.1 新增鸿蒙工程壳](#3.1 新增鸿蒙工程壳)
- [3.2 新增构建脚本](#3.2 新增构建脚本)
- [3.3 新增运行时识别](#3.3 新增运行时识别)
- [3.4 新增本地服务启动入口](#3.4 新增本地服务启动入口)
- [四、为什么 Logseq 选择 Web release 优先](#四、为什么 Logseq 选择 Web release 优先)
- 五、鸿蒙适配核心路径
-
- [5.1 第一步:构建 Logseq Web release 产物](#5.1 第一步:构建 Logseq Web release 产物)
- [5.2 第二步:同步资源到 HAP](#5.2 第二步:同步资源到 HAP)
- [5.3 第三步:注入 OpenHarmony 运行标记](#5.3 第三步:注入 OpenHarmony 运行标记)
- [5.4 第四步:生成本地服务入口](#5.4 第四步:生成本地服务入口)
- [5.5 第五步:补齐 WebAssembly 启动参数](#5.5 第五步:补齐 WebAssembly 启动参数)
- [5.6 第六步:给 SQLite 持久化增加 OpenHarmony 分支](#5.6 第六步:给 SQLite 持久化增加 OpenHarmony 分支)
- [5.7 第七步:把图谱创建过程拆成可诊断阶段](#5.7 第七步:把图谱创建过程拆成可诊断阶段)
- 六、问题困难解决
-
- [6.1 困难一:鸿蒙日志噪声容易误导判断](#6.1 困难一:鸿蒙日志噪声容易误导判断)
- [6.2 困难二:`null.oo1` 背后是 SQLite WASM 没起来](#6.2 困难二:
null.oo1背后是 SQLite WASM 没起来) - [6.3 困难三:传统 Electron 判断会把 Logseq 带到错误路径](#6.3 困难三:传统 Electron 判断会把 Logseq 带到错误路径)
- [6.4 困难四:OPFS 不能当作唯一持久化基础](#6.4 困难四:OPFS 不能当作唯一持久化基础)
- [6.5 困难五:窗口按钮不能只在页面里画出来](#6.5 困难五:窗口按钮不能只在页面里画出来)
- [6.6 运行链路确认顺序](#6.6 运行链路确认顺序)
- 七、构建与运行方式
- 八、适配成果
- 九、功能验证结果
- 十、结语
一、写在前面
欢迎加入鸿蒙PC开发者社区,共同打造开发者工具生态:鸿蒙PC开发者社区 :https://harmonypc.csdn.net/
开源项目地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_logseq
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
这篇文章记录的是 Logseq 在 OpenHarmony / HarmonyOS Electron 环境中的一次适配过程。
Logseq 是一个本地优先的知识管理和协作工具。它表面上是笔记软件,实际运行时会牵涉块编辑器、图谱、页面索引、搜索、SQLite、Web Worker、IndexedDB、OPFS、PDF、白板等一整套前端与本地数据能力。和普通 Web 工具不同,Logseq 不是页面打开就算迁移完成,它真正的关键在于:
图谱能不能创建,SQLite 能不能初始化,数据能不能落盘,重新打开以后还能不能回到同一个图谱。
针对鸿蒙适配,这次没有直接把桌面 Electron 版本完整搬过来,也没有用 ArkTS 重写业务界面,而是先选择一条更可控的路线:
使用 Logseq Web release 产物作为核心承载,由 OpenHarmony Electron runtime 启动本地服务并加载页面。
这样做的目标很明确:优先打通 Logseq 在鸿蒙窗口中的主界面、日记页、图谱创建、基础编辑、搜索弹层和本地持久化能力。等这条核心链路稳定以后,再继续考虑桌面端更重的文件系统、插件、同步、附件、PDF 标注等能力。
本文会按工程结构、资源同步、运行入口、数据库链路、问题定位和功能验证几个角度复盘这次适配。
先说结论:这次适配已经让 Logseq 在鸿蒙 Electron runtime 中完成了从 HAP 工程、Web 资源、运行入口、SQLite WASM 到图谱恢复的基础闭环。它不是一个只展示页面的壳,而是可以进入日记、打开搜索、进入编辑状态并保留图谱数据的知识库应用。

二、项目背景
Logseq 项目本身不是单一形态应用,它同时包含 Web、桌面端和移动端路径。
仓库中比较关键的目录和能力包括:
src/main/frontend/:Logseq 主前端逻辑,包含页面、编辑器、图谱、repo handler 等核心代码src/main/frontend/worker/:浏览器侧 DB worker 与 SQLite WASM 相关逻辑static/:Logseq Web release 构建后的静态资源目录electron/、src/electron/:传统桌面 Electron 相关能力scripts/:构建、打包和本次新增的鸿蒙同步脚本ohos_hap/:本次新增的鸿蒙 HAP 工程
Logseq 的运行路径可以粗略分成三类:
- 浏览器路径:ClojureScript、React/Rum、Web Worker、IndexedDB、OPFS、SQLite WASM
- 桌面路径:Electron 主进程、IPC、Node DB worker、
better-sqlite3、本地文件系统 - 移动路径:Capacitor、移动端入口和原生插件
这次适配选择 Web release 作为鸿蒙第一阶段承载目标,主要原因是桌面端依赖更重。传统桌面版会涉及 better-sqlite3、文件系统 IPC、keychain、系统托盘、窗口菜单、全局快捷键、自动更新等能力。如果一开始就完整迁移桌面端,问题会迅速扩散到原生模块和系统 API 上。
Web release 路线能先把核心知识库体验收敛到浏览器能力上:页面渲染、worker、SQLite WASM、IndexedDB、图谱列表和基础持久化。对第一阶段来说,这条路更容易形成可验证结果。
三、总体变化概览
3.1 新增鸿蒙工程壳
适配后的项目新增:
text
ohos_hap/
├── AppScope/
├── electron/
├── web_engine/
└── build-profile.json5
鸿蒙 Electron runtime 最终读取的应用资源目录是:
text
ohos_hap/web_engine/src/main/resources/resfile/resources/app
同步后的资源目录大致是:
text
resources/app/
├── main.js
├── package.json
└── www/
├── index.html
├── css/
├── js/
└── ...
其中 www/ 是 Logseq Web release 产物,main.js 是为鸿蒙环境生成的 Electron 启动入口。
3.2 新增构建脚本
新增脚本:
text
scripts/build-ohos-package.cjs
scripts/build-ohos-hap.cjs
package.json 中新增:
json
{
"ohos:sync": "node scripts/build-ohos-package.cjs",
"ohos:build": "node scripts/build-ohos-hap.cjs"
}
这两条命令分别负责:
- 构建或复用 Logseq Web release 产物
- 将资源同步到 HAP 的
resources/app - 注入 OpenHarmony 运行标记
- 生成轻量 Electron runtime 入口
- 调用 Hvigor 构建 HAP
3.3 新增运行时识别
构建脚本会在 index.html 中注入:
js
window.__LOGSEQ_OPENHARMONY__ = true;
window.__LOGSEQ_OPENHARMONY_BROWSER_STORAGE__ = true;
前端代码据此把 OpenHarmony Electron runtime 和传统桌面 Electron 区分开,避免 Logseq 误走 Node IPC、桌面 DB worker 和 better-sqlite3 路径。
3.4 新增本地服务启动入口
生成的 resources/app/main.js 不直接 loadFile(index.html),而是启动本地静态服务:
text
http://127.0.0.1:37910/
再由 Electron 窗口加载这个地址。这样可以统一处理 MIME、资源回退、worker、WASM 以及跨源隔离相关响应头。

四、为什么 Logseq 选择 Web release 优先
Logseq 桌面版能力很完整,但对鸿蒙第一阶段来说,直接迁移桌面端不是最稳的起点。
桌面 Electron 路径里有几类问题会同时出现:
- Node 原生模块需要重新适配或替代
better-sqlite3依赖原生编译能力- 文件系统访问和图谱目录选择需要鸿蒙侧重新设计
- 托盘、菜单、自动更新、全局快捷键等桌面能力不一定有同等 API
- renderer 很容易误以为自己处在传统 Electron 环境,从而走错数据库链路
而 Web release 路径能先覆盖 Logseq 最核心的使用链路:
- 页面加载
- 日记页渲染
- 图谱创建
- DB worker 启动
- SQLite WASM 初始化
- IndexedDB 持久化
- 搜索弹层
- 块编辑入口
所以这次路线可以概括为:
static/Web release 资源 + 本地 HTTP 服务 + OpenHarmony Electron 窗口 + HAP 工程承载。
这里和一些纯静态 Web 项目略有不同。Logseq 没有直接从 file:// 加载页面,而是通过本地服务加载 http://127.0.0.1:37910/。这样做是为了让 SQLite WASM、worker、SharedArrayBuffer 和资源类型处理更接近普通 Web 运行环境。
五、鸿蒙适配核心路径
5.1 第一步:构建 Logseq Web release 产物
scripts/build-ohos-package.cjs 会检查 static/ 下是否已经存在关键文件:
text
static/index.html
static/js/main.js
static/js/db-worker.js
static/js/db-worker-bundle.js
static/js/sqlite3.wasm
如果缺少这些产物,脚本会执行 Logseq 的前端构建链路,包括:
text
pnpm gulp:build
clojure -M:cljs release app db-worker db-worker-node
pnpm webpack-app-build
构建时会设置:
text
LOGSEQ_OPENHARMONY_BUILD=1
并把 ClojureScript 的 asset-path 调整为本地 /js,避免 HAP 内运行时继续请求远端资源。
5.2 第二步:同步资源到 HAP
脚本会把 static/ 复制到:
text
ohos_hap/web_engine/src/main/resources/resfile/resources/app/www
复制时会过滤 .DS_Store、.cache 和 sourcemap,减少 HAP 内不必要的资源。
5.3 第三步:注入 OpenHarmony 运行标记
同步后会修改 www/index.html,写入:
js
window.__LOGSEQ_OPENHARMONY__ = true;
window.__LOGSEQ_OPENHARMONY_BROWSER_STORAGE__ = true;
对应的前端判断是:
clojure
(defn openharmony?
[]
(boolean (and js/window
(gobj/get js/window "__LOGSEQ_OPENHARMONY__"))))
(defn- electron*?
[]
(when (and js/window
(not (openharmony?))
(gobj/get js/window "navigator"))
(gstring/caseInsensitiveContains js/navigator.userAgent " electron")))
这一步很关键。OpenHarmony 里虽然使用 Electron runtime,但 Logseq 不能把自己当成传统桌面 Electron,否则会去找当前阶段并不存在的桌面 DB worker 和 Node IPC 能力。
5.4 第四步:生成本地服务入口
resources/app/main.js 会启动本地服务,默认端口:
text
37910
服务会为资源设置:
text
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
同时补充 .wasm、.js、.css、字体、图片等 MIME 类型。这样 SQLite WASM、worker 和前端资源都能在更稳定的 Web 运行模型下加载。
5.5 第五步:补齐 WebAssembly 启动参数
Logseq 的 SQLite 依赖 @sqlite.org/sqlite-wasm。鸿蒙 Electron runtime 里不能默认假设 WebAssembly 已经暴露出来,因此需要在两处补运行参数。
第一处是鸿蒙侧默认命令行参数:
ts
"--js-flags=--expose-wasm",
"--enable-webassembly",
"--enable-features=UseOzonePlatform,SharedArrayBuffer,WebAssembly",
第二处是生成的 Electron 入口:
js
app.commandLine.appendSwitch('js-flags', '--expose-wasm');
app.commandLine.appendSwitch('enable-webassembly');
app.commandLine.appendSwitch('enable-experimental-web-platform-features');
app.commandLine.appendSwitch('enable-features', 'SharedArrayBuffer,WebAssembly');
只改其中一处不够稳。鸿蒙 Electron 壳默认参数和应用包内生成入口都要覆盖,否则容易出现本次手动调通、下次重新打包又退回空白或数据库失败的情况。
5.6 第六步:给 SQLite 持久化增加 OpenHarmony 分支
Logseq 浏览器侧原本会优先尝试 OPFS 和 SQLite WASM 的 VFS 能力。OpenHarmony Electron runtime 对 OPFS、SAH pool、SharedArrayBuffer 这一组能力不能完全按桌面 Chromium 来假设。
因此 DB worker 增加了 OpenHarmony 分支:
- worker URL 带上
openharmony=true - OpenHarmony 下跳过 OPFS SAH pool
- 图谱列表保存到 IndexedDB
- SQLite DB 内容导出成二进制 payload 后保存到 IndexedDB
- 下次打开图谱时从 IndexedDB 还原数据库文件
使用的 key 包括:
text
logseq-openharmony-graphs/v1
logseq-openharmony-db/v1/<encoded>
这里还有一个细节:没有有效 payload 时不创建 0 字节 SQLite 文件。0 字节文件会让后续打开数据库时变得更难判断,看起来像"文件存在但数据库损坏"。适配里只在 IndexedDB 里确实存在正长度数据时才恢复。
5.7 第七步:把图谱创建过程拆成可诊断阶段
Logseq 启动空白或点击无反应时,只看鸿蒙设备日志很容易被干扰。比如剪贴板、输入法、GPU、DNS、窗口事件都可能输出 error 或 warning,但不一定是根因。
这次在图谱创建链路里增加了 stage 诊断:
text
persist-new
start-conn
add-repo
restore-setup
redirect-home
repo-config
如果失败,页面会提示:
text
创建图谱失败。 stage=<stage> error=<message>
同时会记录当前环境中 WebAssembly、Worker、SharedArrayBuffer 等能力是否存在。这样就能把"空白页""点击没反应"拆成具体阶段,定位效率会高很多。

六、问题困难解决
Logseq 适配中最大的困难是:
页面加载成功以后,图谱创建链路仍然可能失败,而失败表象经常只是空白或点击无反应。
这个问题主要集中在四个方面。
6.1 困难一:鸿蒙日志噪声容易误导判断
启动时可以看到一些比较醒目的日志,例如:
text
XComponentManager::Initialize napi_unwrap fail
PermissionManagerAdapter unsupported permission:pasteboard
clipboard_ohos.cc load OH_Pasteboard_GetChangeCount failed
这些日志说明鸿蒙 Electron 适配层里仍有一些能力差异,但它们不是 Logseq 空白或无法创建图谱的根因。
真正需要盯的是 Logseq 自己的图谱创建链路、DB worker 初始化和 SQLite WASM 加载结果。迁移时不能看到 error 就马上改方向,需要把系统适配层噪声和应用自身错误分开。
6.2 困难二:null.oo1 背后是 SQLite WASM 没起来
早期失败时出现过:
text
Cannot read properties of null (reading 'oo1')
这个错误表面像是普通空对象访问,实际是 SQLite WASM 模块没有初始化成功。后续代码继续访问 sqlite.oo1.DB,于是变成了 null.oo1。
所以适配里做了两件事:
- SQLite 初始化完成后检查
oo1.DB和capi是否存在 - 图谱创建失败时把 stage 和真实错误显示出来
处理后错误可以收敛成:
text
创建图谱失败。 stage=persist-new error=WebAssembly is not defined
这个提示出现以后,方向就非常明确了:不是图谱 UI 坏了,也不是路由坏了,而是运行环境里的 WebAssembly 没有打开。

6.3 困难三:传统 Electron 判断会把 Logseq 带到错误路径
鸿蒙里使用 Electron runtime,但这不等于 Logseq 可以直接走传统桌面 Electron 分支。
传统桌面分支会依赖:
- Electron IPC
- Node DB worker
better-sqlite3- 本地文件系统图谱目录
- 桌面端窗口和系统能力
这些能力在第一阶段并不是迁移目标。适配中通过 __LOGSEQ_OPENHARMONY__ 把 OpenHarmony 单独识别出来,让 Logseq 继续沿浏览器侧 DB worker 和 SQLite WASM 路径运行。
这个判断看起来只是一小段环境识别代码,但它决定了后续数据库链路走向。
6.4 困难四:OPFS 不能当作唯一持久化基础
普通 Chromium 环境中,OPFS 与 SQLite WASM 可以形成比较理想的浏览器侧数据库方案。但在 OpenHarmony Electron runtime 中,这组能力的行为需要重新验证。
所以适配里增加 IndexedDB 兜底持久化:
- 图谱列表存 IndexedDB
- SQLite DB blob 存 IndexedDB
- 重启时再恢复到 SQLite 文件
这不是为了替代 Logseq 后续更完整的文件系统能力,而是为了第一阶段先保证"创建图谱 -> 进入日记 -> 重启恢复"这条链路不会断。
6.5 困难五:窗口按钮不能只在页面里画出来
用户实际使用时会关注鸿蒙外壳有没有最小化、最大化、关闭按钮。这个问题不能通过在 Logseq 页面里画三个按钮解决,因为它属于窗口装饰和 runtime 行为。
生成的 BrowserWindow 中设置了:
js
frame: true,
titleBarStyle: 'default',
minimizable: true,
maximizable: true,
closable: true,
resizable: true
这样窗口控制权交给鸿蒙 Electron runtime,应用界面本身只负责 Logseq 内容。
6.6 运行链路确认顺序
Logseq 在鸿蒙中的运行链路可以按下面顺序确认:
static/index.html、static/js/main.js、static/js/db-worker.js、static/js/sqlite3.wasm是否生成resources/app/www是否同步成功resources/app/package.json的main是否指向main.js- 本地服务是否加载
http://127.0.0.1:37910/ window.__LOGSEQ_OPENHARMONY__是否注入- Logseq 是否避开传统桌面 Electron 判断
- worker 是否带
openharmony=true - SQLite WASM 是否能看到
WebAssembly - 图谱创建 stage 是否全部通过
- 重启后图谱是否仍能恢复
这个顺序可以把 HAP 工程、资源目录、Electron 入口、前端环境判断、worker、SQLite 和持久化逐层拆开。
七、构建与运行方式
同步资源:
bash
cd /logseq-master-ohos
pnpm ohos:sync
构建 HAP:
bash
cd /logseq-master-ohos
pnpm ohos:build
HAP 输出目录:
text
ohos_hap/electron/build/default/outputs/default/
当前构建生成的未签名 HAP:
text
electron-default-unsigned.hap
构建时会先同步 Logseq Web release 资源,再查找 DevEco / Hvigor 和 OpenHarmony SDK,最后执行:
text
hvigor assembleHap
实际输出中可能出现 Shadow CLJS、ArkTS 或权限相关 warning,只要 HAP 正常生成,并且设备侧不再出现 WebAssembly is not defined、null.oo1、SQLite WASM module is not ready 这类关键错误,就说明核心链路已经通过。

八、适配成果
logseq-master-ohos 已经完成:
- 鸿蒙 Electron HAP 工程接入
- Logseq Web release 资源构建与同步
resources/app/main.js运行入口生成- 本地静态服务器加载
http://127.0.0.1:37910/ - COOP / COEP / CORP 响应头补齐
- OpenHarmony 运行环境标记注入
- 避免误走传统桌面 Electron / Node IPC 路径
- 浏览器侧 DB worker 路径接入
- SQLite WASM 启动参数补齐
- OpenHarmony 下 IndexedDB 图谱列表持久化
- OpenHarmony 下 SQLite DB blob 兜底持久化
- 图谱创建 stage 诊断
- 原生窗口最小化、最大化、关闭按钮显示
- 日记页、搜索弹层、基础编辑入口验证
九、功能验证结果
logseq-master-ohos 按知识库应用的核心路径完成了功能验证。
第一组是启动与页面:
- HAP 可以安装并启动
- 应用窗口标题显示 Logseq
- 原生最小化、最大化、关闭按钮显示
- 主界面不再停留空白
- 日记页能够正常渲染
第二组是图谱与数据库:
- 首次启动可以创建图谱
- 图谱创建不再报
WebAssembly is not defined - SQLite 初始化不再出现
null.oo1 - DB worker 可以进入 OpenHarmony 分支
- 强停或关闭后重新打开,图谱可以恢复
第三组是交互:
- 搜索按钮点击后能弹出搜索面板
- 最近页面或搜索结果区域可以显示
- 正文块可以进入编辑状态
- 输入法可以被唤起
- 光标和基础点击交互可用
第四组是日志检查:
- 不再出现
SQLite WASM module is not ready - 不再出现图谱创建阶段的 WASM 缺失错误
- 系统侧仍可能有剪贴板、输入法、GPU 相关 warning,但不影响 Logseq 主链路

十、结语
logseq-master-ohos 的适配本质上是一次"本地知识库 Web 内核鸿蒙承载"实践。
它和普通 Web 工具迁移最大的区别在于:Logseq 的核心不是页面,而是图谱和数据库。页面能显示只是第一步,真正决定可用性的,是 worker、SQLite WASM、存储、运行时判断和构建链路。
这次适配里最关键的转折点,是把"空白页""点击没反应""null.oo1"这类表象问题,拆成具体的图谱创建 stage,并最终定位到 WebAssembly is not defined。当错误变得足够具体以后,后续就可以通过运行参数、环境识别和持久化分支逐步解决。
第一阶段完成后,Logseq 已经可以在鸿蒙 Electron runtime 中完成启动、进入日记、创建图谱、打开搜索、进入编辑和恢复图谱这些核心动作。后续如果继续向完整桌面版靠拢,还需要处理附件路径、文件导入导出、插件系统、PDF 标注、白板性能、Logseq Sync、剪贴板权限以及更完整的本地文件系统能力。
对复杂软件迁移来说,这次经验比较清楚:
先让关键路径稳定闭环,再逐步扩大桌面能力边界。
Logseq 的鸿蒙适配第一阶段,基本就是沿着这条路线完成的。