从 Electron 迁移到 Lynxtron
如果你已经有一个 Electron 应用,可以把迁移到 Lynxtron 理解为:尽量保留主进程和桌面端能力,把 Chromium Renderer 中的 Web UI 替换为 Lynx UI。
Lynxtron 的主进程 API 基本沿用 Electron,LynxWindow、Menu、Tray、Notification、dialog、shell、screen 等桌面端 API 的使用方式接近 Electron。真正需要重新设计的是 UI 层:Lynxtron 不加载 HTML 页面,也没有 DOM 渲染层;窗口内容由 Lynx bundle 驱动,使用 Lynx 元素、样式和运行时 DSL 渲染。
迁移前先划分边界
迁移时建议先按代码所在层级拆分,而不是直接逐文件替换:
API 对照速查
迁移主进程窗口创建
Electron 中常见的窗口创建代码:
迁移到 Lynxtron 后,主进程仍然运行在 Node.js 中,但窗口类型和 UI 加载目标要替换:
窗口形态选项可以优先按原 Electron 配置迁移,例如 width、height、frame、transparent、titleBarStyle、trafficLightPosition。无边框、透明窗口和自定义标题栏的 Lynx UI 写法见构建自定义窗口。
重写 Renderer UI
Lynxtron 不把 Electron Renderer 里的 HTML 页面直接运行起来。迁移 UI 时,需要把 DOM 结构、Web CSS 和浏览器事件模型改写为 Lynx UI。
事件也需要从 React DOM 事件改成 Lynx 元素事件。例如,一个 Electron React 按钮:
迁移到 ReactLynx 后:
如果你的 Electron 应用大量依赖 DOM API、浏览器布局、Canvas、WebGL 或 Web 组件库,建议把 UI 迁移拆成独立阶段:先保留主进程服务和通信协议,再逐个窗口用 Lynx UI 重写。
渐进式迁移:先把现有 Web UI 放进 <webview>
如果一次性重写全部 Renderer UI 成本太高,可以先用 Lynx UI 搭出窗口外壳,再把暂时未迁移的 Web UI 放进 <webview>。这样可以先完成主进程、窗口创建、打包、preload scripts 和 IPC 的迁移,同时保留部分现有 Web 页面继续运行。
这种方式适合作为过渡方案:
- 先用 Lynx 实现窗口框架、标题栏、导航、全局状态和新的页面入口。
- 暂时把复杂度高、依赖 DOM 或 Web 组件库的旧页面放入
<webview>。 - 每迁移完一个页面,就用 Lynx 元素替换对应的
<webview>内容。 - 新迁移的主进程能力尽量收口到 Lynxtron 的 bridge 或 preload scripts,避免继续扩大旧 Web UI 对 Electron Renderer API 的依赖。
需要注意的是,<webview> 中的内容仍然是 Web 内容,不会自动变成 Lynx UI。它适合降低迁移风险和拆分迁移节奏,但最终仍建议把核心桌面 UI 逐步改写为 Lynx 元素。
迁移 Preload Scripts 和 Node.js 能力暴露
Electron 中常见做法是在 preload script 中用 contextBridge.exposeInMainWorld() 暴露能力:
Renderer 侧通过 window.desktop 调用:
在 Lynxtron 中,preload script 仍然可以使用 Node.js 能力,但暴露目标变为 Lynx BTS 的 NativeModules.nodejs.exposed:
Lynx UI 侧通过 NativeModules.nodejs.exposed 调用:
Lynxtron 的 preload scripts 和 Lynx BTS 都在同一进程内的隔离 JS context 中。exposeInLynxBTS() 暴露的是 BTS 可直接调用的 JS 对象,可以包含函数、闭包和返回 Promise 的异步 API。详细说明见 Node.js 与 Lynx 通信:使用 Preload Scripts。
迁移 IPC
如果原 Electron Renderer 通过 ipcRenderer.invoke() 调用主进程:
Lynx UI 侧使用 NativeModules.bridge.call 发起调用:
Node 主进程通过监听 -lynx-invoke 事件处理 bridge.call 调用,并通过 event.sendReply 返回:
如果原 Electron 主进程用 webContents.send() 向 Renderer 推送事件:
迁移到 Lynxtron 后使用 LynxWindow.sendGlobalEvent():
Lynx UI 侧通过 GlobalEventEmitter 接收。完整示例见 Node 主进程与 Lynx 双向消息通信。
处理原生模块、构建和打包
如果 Electron 项目使用了 Node.js 原生模块,迁移后需要按 Lynxtron 运行时重新构建:
应用打包建议使用 @lynx-js/lynxtron-builder。它基于 electron-builder,可以继续读取 electron-builder.yml,但会把 Electron runtime 替换为当前 Lynxtron 依赖对应的 Lynxtron runtime。通常可以把原来的 electron-builder 命令改成:
迁移时建议检查以下内容:
- 原生模块是否依赖 Electron ABI,需要用
@lynx-js/lynxtron-rebuild重新构建。 - 原 Renderer 中直接访问 Node.js 的代码是否已经移入主进程或 preload scripts。
electron-builder.yml中的directories.app、files、extraResources等配置是否已经指向 Lynxtron 主进程产物、Lynx bundle 和必要资源。- Lynx bundle 是否被正确构建并包含在打包产物中。
- 无边框窗口、透明窗口、拖拽区域和系统按钮是否已用 Lynx UI 重写。
推荐迁移顺序
- 创建一个新的 Lynxtron 工程,跑通最小窗口和打包流程。
- 迁移 Electron 主进程中的应用生命周期、菜单、托盘、对话框等桌面端逻辑。
- 把
BrowserWindow替换为LynxWindow,加载一个最小 Lynx bundle。 - 迁移 preload scripts,把 UI 需要的 Node.js 能力暴露到
NativeModules.nodejs.exposed。 - 按窗口重写 Renderer UI,把 HTML/DOM/CSS 改成 Lynx 元素和样式;如果需要渐进式迁移,可以先用
<webview>承载暂时未迁移的 Web 页面。 - 迁移 IPC,统一使用
NativeModules.bridge.call/NativeModules.bridge.send和LynxWindow.sendGlobalEvent(),并在主进程侧监听-lynx-invoke/-lynx-message事件。 - 重建原生模块,使用
@lynx-js/lynxtron-builder检查打包产物和平台相关能力。