Skip to content

Mac 启动思源出现错误 #17817

@TCOTC

Description

@TCOTC

https://ld246.com/article/1780623219729

A JavaScript error occurred in the main process

Uncaught Exception:
Error: Cannot create BrowserWindow before app is ready
    at initMainWindow (/Applications/SiYuan.app/Contents/Resources/app/electron/main.js:397:27)
    at EventEmitter.<anonymous> (/Applications/SiYuan.app/Contents/Resources/app/electron/main.js:1503:9)
    at EventEmitter.emit (node:events:508:28)

AI 分析:


## 错误含义

这是 **Electron 生命周期** 问题,不是内核或笔记数据问题。

报错信息:

```text
Error: Cannot create BrowserWindow before app is ready
```

含义:在 Electron 的 `app` 尚未完成初始化(未触发 `ready` / `app.whenReady()` 尚未完成)时,就调用了 `new BrowserWindow()`。Electron 不允许这样做。

堆栈指向 `initMainWindow` 里创建主窗口,以及 `main.js` 约 1503 行的 `activate` 事件监听——与当前源码一致。

## 触发原因(macOS 常见)

正常启动流程在 `app.whenReady()` 里走 `initKernel` → `initMainWindow`:

```736:737:app/electron/main.js
app.whenReady().then(() => {
    const resetTrayMenu = (tray, lang, mainWindow) => {
```

但 macOS 还会在 Dock 点击等场景触发 `activate`,且 **可能在 `app` 尚未 ready 时就触发**(Electron 官方也认为这是合法行为)。

当前 `activate` 处理如下:

```1502:1511:app/electron/main.js
app.on("activate", () => {
    if (workspaces.length > 0) {
        const mainWindow = (latestActiveWindow && !latestActiveWindow.isDestroyed()) ? latestActiveWindow : workspaces[0].browserWindow;
        if (mainWindow && !mainWindow.isDestroyed()) {
            mainWindow.show();
        }
    }
    if (BrowserWindow.getAllWindows().length === 0) {
        initMainWindow();
    }
});
```

若启动时 `activate` 早于 `whenReady` 完成,且此时还没有任何窗口(`getAllWindows().length === 0`),就会直接调用 `initMainWindow()`,在约 402 行执行 `new BrowserWindow()` 并崩溃。

典型场景:

- 启动阶段用户很快点击 Dock 图标  
- 系统或启动项在应用尚未 ready 时激活应用  
- 冷启动较慢时,`activate` 与 `whenReady` 竞态  

## 与截图的对应关系

| 项目 | 说明 |
|------|------|
| 平台 | `/Applications/SiYuan.app`,macOS |
| 出错位置 | `initMainWindow` 内 `new BrowserWindow` |
| 调用链 | `app.on("activate")` → `initMainWindow()` |
| 性质 | 主进程未捕获异常,启动即弹窗 |

## 修复思路(供参考)

在 `activate` 里创建窗口前,先判断 `app.isReady()`;或把 `activate` 监听注册放到 `app.whenReady()` 内部(与 [electron-quick-start 的修复](https://github.com/electron/electron-quick-start/pull/382) 类似):

```javascript
app.on("activate", () => {
    if (!app.isReady()) {
        return;
    }
    // 原有逻辑...
});
```

这样 `whenReady` 仍会负责首次正常启动;`activate` 只在 ready 之后、且确实没有窗口时再重建窗口,避免竞态崩溃。

---

**总结**:用户反馈的是 **macOS 上 `activate` 过早触发、在 `app` 未 ready 时创建主窗口** 导致的启动崩溃,属于 Electron 主进程代码问题,而非用户配置或数据损坏。

如果你需要,我可以在仓库里直接加上 `app.isReady()` 防护并提一个小 patch。

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions