Skip to content

从 Electron 迁移

webview 的 WindowTem 对标 Electron TS 版 WindowTem,迁移路径直接:TS 桌面主进程 → C++,渲染层前端基本原样复用。

概念对照

Electronwebview
BrowserWindowWindowApp::createWindow
WindowTem(TS 模板基类)WindowTem(C++ 模板基类)
ipcMain.handle / ipcRenderer.invokebridge.call / on
webContents.sendwin->send / broadcast
preload.ts 暴露 window.bridgeruntime.js 自动注入 window.bridge
app.on('second-instance')onSecondInstance
BrowserWindow 选项Window::Opts

通道迁移

Electron IPC 通道名照搬,把 ipcMain.handle 换成 on

ts
// Electron(TS)
ipcMain.handle('getProject', (_e, id) => loadProject(id))
win.webContents.send('projectReady', data)
cpp
// webview(C++)
tem->on("getProject", [](int id) { return loadProject(id); });
tem->send("projectReady", data);

前端 ipcRenderer.invokebridge.call

js
// Electron
const p = await ipcRenderer.invoke('getProject', 42)

// webview(契约一致)
const p = await bridge.call('getProject', 42)

WindowTem 迁移

TS 子类的 initBridge / emitNames 几乎逐行搬:

ts
// TS
class MainWindow extends WindowTem {
  emits = ['downloadCb']
  initBridge() {
    this.on('addTzm', this.addTzm)
    this.on('useTzm', this.useTzm)
  }
}
cpp
// C++
class MainWindow : public webview::WindowTem {
public:
  using webview::WindowTem::WindowTem;
  void initBridge() override {
    emits({"downloadCb"});
    on("addTzm", &MainWindow::addTzm);
    on("useTzm", &MainWindow::useTzm);
  }
};

反射差异

TS 可字符串反射 this[name] 自动循环绑定。C++ 不行——WindowTem 不支持反射,槽必须逐个 on(name, &Cls::method) 显式绑。

数值字段:bigint 序列化

Electron 常用 bigint 字段。webview JSON 约定:bigint 字段以字符串序列化(对齐 TS 行为)。改 C++ 序列化时保持此约定,否则前后端不兼容。

js
// 前端:收到的 bigint 是字符串
const id = String(data.id)   // 已是 "123..."

资源迁移

Electron loadFile('dist/index.html') → webview 打包模式:

cpp
opts.url = L"src/assets/html/index.html";   // 约定目录

前端 dist 拷进 src/assets/html/,构建期自动嵌入 exe。详见 嵌入 Vue 工程

去掉的东西

  • preload.ts:不再需要,runtime.js 自动注入 window.bridge
  • electron npm 依赖:整个渲染层可脱离 Electron
  • contextBridge:直接用 window.bridge
  • Node 内置模块(fs/path):文件操作走 C++ RPC 槽,前端不直接碰

fs / getPath 迁移

框架内置 getPath + userData 白名单 fsWindowTem 自动绑),前端 Node fs/app.getPath 直接对应:

Electron本框架
app.getPath('userData')await bridge.call('getPath', 'userData')
fs.promises.readFile(p)await bridge.call('fs.readFile', p)(返 base64,atob 解)
fs.promises.writeFile(p, buf)await bridge.call('fs.writeFile', p, btoa(buf))
fs.promises.mkdir(p,{recursive})await bridge.call('fs.mkdir', p)
fs.promises.readdir(p)await bridge.call('fs.listDir', p){entries}
fs.promises.unlink/rmdirawait bridge.call('fs.remove', p)(空目录/文件)

白名单约束:fs 操作强制限 %APPDATA%\<exe>\ 子树,越界返 {error:"out of userData"}。系统目录读写用 App::showSaveDialog/openExternal。详见 路径与文件系统

下一步