当前位置:首页>鸿蒙APP>Electron 在鸿蒙 PC 上存数据,绕了三条路我选了最朴素的

Electron 在鸿蒙 PC 上存数据,绕了三条路我选了最朴素的

  • 2026-11-02 12:23:56
Electron 在鸿蒙 PC 上存数据,绕了三条路我选了最朴素的

Electron 在鸿蒙 PC 上存数据,绕了三条路我选了最朴素的

昨天下午,我把一个 Electron 项目里的 SQLite 依赖删了。不是因为 SQLite 不好,是因为在鸿蒙 PC 上,它让我绕了太多弯路。


昨天下午两点,斌哥在群里说:"用户配置和历史记录得存本地,你搞个数据库吧。“我当时正在喝咖啡,回了句"SQLite 呗,轻量又成熟”。这个轻率的决定,让我接下来三个半小时经历了从自信到自嘲的完整过程。

下午 2:15 —— 方案一:sqlite3

打开项目目录,npm install sqlite3。在 Windows 上这是常规操作,npm 会自动拉取预编译二进制包。但在鸿蒙 PC 上,安装日志里弹出一堆 node-gyp 报错:找不到鸿蒙平台的预编译二进制。sqlite3 的 npm 包只提供了 Windows、macOS 和 Linux 的预编译二进制,鸿蒙不在支持列表里。

const sqlite3 = require('sqlite3').verbose();const db = new sqlite3.Database('./user.db');db.serialize(() => {  db.run("CREATE TABLE IF NOT EXISTS config (key TEXT, value TEXT)");  db.run("INSERT INTO config VALUES (?, ?)", ['theme', 'dark']);});db.close();

但在鸿蒙上,第一行的 require('sqlite3') 就过不去。把 sqlite3 从 package.json 里删掉。第一条路,断了。

下午 2:50 —— 方案二:better-sqlite3

sqlite3 不行,那 better-sqlite3 呢?据说它用的是预编译绑定,性能更好。

npm install better-sqlite3,同样的问题:没有鸿蒙平台的预编译二进制,而且编译依赖更复杂。我试着配置了鸿蒙的交叉编译环境,编译跑起来了,我在旁边盯了五分钟,心里升起一丝希望。然后报错来了:uv_dlopen 不支持鸿蒙的动态库格式。鸿蒙 PC 上 Electron 的 Node.js 运行时对原生模块的加载有自己的规则,跟标准 Linux 不完全兼容。我坐在椅子上发了五分钟呆。

下午 3:30 —— 方案三:鸿蒙原生数据存储

这时候我换了个思路。既然 Node.js 的原生数据库模块在鸿蒙上水土不服,那能不能用鸿蒙系统自己的数据存储能力?

翻了翻鸿蒙文档,找到了 @ohos.data.preferences 这个模块。它是鸿蒙提供的轻量级键值存储,类似 Android 的 SharedPreferences。我的思路是在 Electron 主进程里调用它,然后通过 IPC 暴露给渲染进程:

const { ipcMain, app } = require('electron');let preferences;try {  preferences = require('@ohos.data.preferences');} catch (e) {  console.error('鸿蒙原生存储模块不可用', e.message);}ipcMain.handle('save-config', async (_event, key, value) => {  if (!preferences) return false;  const pref = await preferences.getPreferences(    app.getPath('userData'),     'app_config'  );  await pref.put(key, value);  await pref.flush();  return true;});

思路很合理,但踩了一个没想到的坑:@ohos.data.preferences 只能在鸿蒙的原生应用环境里使用。Electron 主进程的 Node.js 模块加载路径并不包含鸿蒙的系统模块目录,require 会报 MODULE_NOT_FOUND。我试了 NODE_PATH、符号链接,甚至复制模块文件到 node_modules 里,都不行。这时候已经过去了一个半小时。有一种奇怪的倔强——我就不信这个简单的存储需求搞不定。

下午 4:15 —— 我到底在解决什么问题

去洗手间的路上,脑子里突然闪过一个念头:我到底需要数据库来干什么?

回到座位打开需求文档。用户配置:主题色、窗口大小、最近打开的文件列表,顶多二十个键值对。历史记录:最近 20 次操作记录。全部数据量加起来顶天了几百 KB,没有多表关联,没有并发写入。

"我他妈为什么要为几百 KB 的数据引入一个数据库?"我在心里骂了自己一句。我需要的是持久化存储,不是关系型数据库。一个 JSON 文件就能解决的事,我为什么要折腾 SQLite?不是因为 SQLite 不好,是因为我在用惯性做技术选型,而不是用脑子。

下午 4:30 —— 回归朴素

我删掉了所有数据库相关的依赖,在 main.js 同级目录下新建了 storage.js:

const fs = require('fs').promises;const path = require('path');const { app } = require('electron');const CONFIG_PATH = path.join(app.getPath('userData'), 'app-config.json');async function readConfig() {  try {    const data = await fs.readFile(CONFIG_PATH, 'utf-8');    return JSON.parse(data);  } catch (err) {    if (err.code === 'ENOENT') return {};    throw err;  }}async function writeConfig(config) {  const dir = path.dirname(CONFIG_PATH);  await fs.mkdir(dir, { recursive: true });  await fs.writeFile(    CONFIG_PATH,     JSON.stringify(config, null, 2),     'utf-8'  );}async function setTheme(theme) {  const config = await readConfig();  config.theme = theme;  await writeConfig(config);}async function getTheme() {  const config = await readConfig();  return config.theme || 'light';}module.exports = { readConfig, writeConfig, setTheme, getTheme };

渲染进程通过 preload 桥接调用:

const { contextBridge, ipcRenderer } = require('electron');contextBridge.exposeInMainWorld('electronAPI', {  setTheme: (theme) => ipcRenderer.invoke('set-theme', theme),  getTheme: () => ipcRenderer.invoke('get-theme'),});

主进程里注册 handler:

const { ipcMain } = require('electron');const { setTheme, getTheme } = require('./storage');ipcMain.handle('set-theme', async (_event, theme) => {  await setTheme(theme);});ipcMain.handle('get-theme', async () => {  return getTheme();});

就这么简单。没有编译,没有原生模块依赖,没有平台兼容性烦恼。fs.promises 在鸿蒙的 Node.js 环境里完全支持,JSON 的读写速度对于几百 KB 的数据来说完全可以忽略。

我在鸿蒙 PC 上打包测试,两分钟通过。那一刻的心情有点哭笑不得。

尾声

回头想想,我其实掉进了"技术选型惯性"的坑。以前一说存数据就是 MySQL、PostgreSQL、SQLite,但很多时候我们不是在选"最好的工具",而是在选"最熟悉的工具"。当最熟悉的工具在新平台上失灵时,与其硬磕,不如退一步问问自己:我到底需要解决什么问题?

昨天下午五点,我把这段经历记在了团队 wiki 里,标题叫《关于我在鸿蒙上白折腾三小时这件事》。斌哥回了一个大笑的表情。你遇到过类似的情况吗?欢迎留言聊聊。


关于我

我叫老三,一个写了十年代码的前端 + 鸿蒙 ArkTS 水手。

目前主业做 Taro 多端项目,业余时间全泡在 AI 自动化和独立开发上——不是因为多热爱加班,而是打心底觉得,程序开发这件事正在被 AI 重构,我不跟上就会被甩下。

这个账号记录的就是我在这条路上的真实经历:踩过的坑、推翻过的方案、以及偶尔值得高兴的小进展。不写教科书,不讲大道理,只分享我自己试过、做过、确认过的东西。

如果你也在写代码,或者也在思考 AI 时代开发者该往哪走——欢迎留言聊聊,一起摸索。


本文遵循 MIT 协议,转载请注明出处。

最新文章

随机文章