升级electron egg脚手架版本
This commit is contained in:
459
doc/生命周期描述.md
Normal file
459
doc/生命周期描述.md
Normal file
@@ -0,0 +1,459 @@
|
||||
# ElectronEgg 生命周期详解
|
||||
|
||||
本文档详细说明 ElectronEgg 框架的应用生命周期机制及其在项目中的实现。
|
||||
|
||||
## 生命周期流程图
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ new │ 创建 ElectronEgg 实例
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ ready │ core app 加载完成(ee-core 框架初始化)
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌──────▼─────────────┐
|
||||
│ electronAppReady │ Electron app 加载完成
|
||||
└──────┬─────────────┘
|
||||
│
|
||||
├─────────────────┐
|
||||
│ │
|
||||
┌──────▼──────┐ ┌─────▼────────┐
|
||||
│ mainWindow │ │ windowReady │ 主窗口创建完成
|
||||
└──────┬──────┘ └─────▲────────┘
|
||||
│ │
|
||||
└─────────────────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ running │ 应用运行中
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│beforeClose │ 退出之前触发
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ quit │ 应用退出
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
## 生命周期钩子详解
|
||||
|
||||
### 1. new - 实例创建
|
||||
|
||||
**触发时机**:调用 `new ElectronEgg()` 时
|
||||
|
||||
**实现位置**:[electron/main.js](electron/main.js#L6)
|
||||
|
||||
```javascript
|
||||
const { ElectronEgg } = require('ee-core');
|
||||
const app = new ElectronEgg();
|
||||
```
|
||||
|
||||
**作用**:
|
||||
- 创建 ElectronEgg 应用实例
|
||||
- 初始化框架核心模块
|
||||
- 准备生命周期管理器
|
||||
|
||||
---
|
||||
|
||||
### 2. ready - 核心应用就绪
|
||||
|
||||
**触发时机**:ee-core 框架加载完成,Electron app 启动之前
|
||||
|
||||
**实现位置**:
|
||||
- 注册:[electron/main.js](electron/main.js#L10)
|
||||
- 实现:[electron/preload/lifecycle.js](electron/preload/lifecycle.js#L12-L14)
|
||||
|
||||
```javascript
|
||||
// 注册
|
||||
app.register("ready", life.ready);
|
||||
|
||||
// 实现
|
||||
async ready() {
|
||||
logger.info('[lifecycle] ready');
|
||||
// 在这里可以做:
|
||||
// - 初始化数据库连接
|
||||
// - 加载配置文件
|
||||
// - 初始化全局变量
|
||||
}
|
||||
```
|
||||
|
||||
**适用场景**:
|
||||
- ✅ 初始化数据库连接
|
||||
- ✅ 加载应用配置
|
||||
- ✅ 注册全局服务
|
||||
- ✅ 初始化日志系统
|
||||
- ❌ 不能操作窗口(窗口还未创建)
|
||||
|
||||
---
|
||||
|
||||
### 3. electronAppReady - Electron 应用就绪
|
||||
|
||||
**触发时机**:Electron 的 `app.ready` 事件触发后,主窗口创建之前
|
||||
|
||||
**实现位置**:
|
||||
- 注册:[electron/main.js](electron/main.js#L11)
|
||||
- 实现:[electron/preload/lifecycle.js](electron/preload/lifecycle.js#L19-L21)
|
||||
|
||||
```javascript
|
||||
// 注册
|
||||
app.register("electron-app-ready", life.electronAppReady);
|
||||
|
||||
// 实现
|
||||
async electronAppReady() {
|
||||
logger.info('[lifecycle] electron-app-ready');
|
||||
// 在这里可以做:
|
||||
// - 注册全局快捷键
|
||||
// - 设置应用菜单
|
||||
// - 初始化托盘图标
|
||||
// - 注册协议处理
|
||||
}
|
||||
```
|
||||
|
||||
**适用场景**:
|
||||
- ✅ 注册全局快捷键 (globalShortcut)
|
||||
- ✅ 创建应用菜单 (Menu)
|
||||
- ✅ 创建系统托盘 (Tray)
|
||||
- ✅ 注册自定义协议 (protocol)
|
||||
- ⚠️ 可以创建窗口,但通常在框架内部自动创建
|
||||
|
||||
---
|
||||
|
||||
### 4. mainWindow - 主窗口创建
|
||||
|
||||
**触发时机**:框架创建主窗口时(内部流程,不需要手动注册)
|
||||
|
||||
**说明**:
|
||||
- 这是框架内部自动执行的步骤
|
||||
- 根据 `electron/config/config.*.js` 中的 `windowsOption` 配置创建窗口
|
||||
- 窗口创建完成后会触发 `windowReady` 钩子
|
||||
|
||||
**配置示例**:
|
||||
```javascript
|
||||
// electron/config/config.default.js
|
||||
windowsOption: {
|
||||
width: 1200,
|
||||
height: 800,
|
||||
show: false, // 设置为 false 可实现无白屏启动
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. windowReady - 窗口就绪
|
||||
|
||||
**触发时机**:主窗口创建完成,页面加载完毕
|
||||
|
||||
**实现位置**:
|
||||
- 注册:[electron/main.js](electron/main.js#L12)
|
||||
- 实现:[electron/preload/lifecycle.js](electron/preload/lifecycle.js#L26-L37)
|
||||
|
||||
```javascript
|
||||
// 注册
|
||||
app.register("window-ready", life.windowReady);
|
||||
|
||||
// 实现
|
||||
async windowReady() {
|
||||
logger.info('[lifecycle] window-ready');
|
||||
|
||||
// 延迟显示窗口,避免白屏
|
||||
const { windowsOption } = getConfig();
|
||||
if (windowsOption.show == false) {
|
||||
const win = getMainWindow();
|
||||
win.once('ready-to-show', () => {
|
||||
win.show(); // 显示窗口
|
||||
win.focus(); // 聚焦窗口
|
||||
})
|
||||
}
|
||||
|
||||
// 在这里可以做:
|
||||
// - 向渲染进程发送初始化数据
|
||||
// - 检查更新
|
||||
// - 加载用户配置
|
||||
}
|
||||
```
|
||||
|
||||
**适用场景**:
|
||||
- ✅ 操作主窗口 (show/hide/maximize 等)
|
||||
- ✅ 向渲染进程发送消息
|
||||
- ✅ 执行自动更新检查
|
||||
- ✅ 加载用户数据并同步到前端
|
||||
- ✅ 实现无白屏启动(配合 `show: false`)
|
||||
|
||||
---
|
||||
|
||||
### 6. running - 应用运行中
|
||||
|
||||
**触发时机**:窗口显示后,应用正常运行期间
|
||||
|
||||
**说明**:
|
||||
- 这不是一个独立的生命周期钩子
|
||||
- 表示应用的正常运行状态
|
||||
- 此时所有功能都可用
|
||||
|
||||
**可用操作**:
|
||||
- IPC 通信(前后端交互)
|
||||
- 业务逻辑处理
|
||||
- 数据库操作
|
||||
- 网络请求
|
||||
- 文件系统操作
|
||||
|
||||
---
|
||||
|
||||
### 7. beforeClose - 关闭前钩子
|
||||
|
||||
**触发时机**:用户点击关闭按钮或调用 `app.quit()` 之前
|
||||
|
||||
**实现位置**:
|
||||
- 注册:[electron/main.js](electron/main.js#L13)
|
||||
- 实现:[electron/preload/lifecycle.js](electron/preload/lifecycle.js#L42-L44)
|
||||
|
||||
```javascript
|
||||
// 注册
|
||||
app.register("before-close", life.beforeClose);
|
||||
|
||||
// 实现
|
||||
async beforeClose() {
|
||||
logger.info('[lifecycle] before-close');
|
||||
// 在这里可以做:
|
||||
// - 保存用户数据
|
||||
// - 关闭数据库连接
|
||||
// - 清理临时文件
|
||||
// - 释放系统资源
|
||||
// - 确认是否退出
|
||||
}
|
||||
```
|
||||
|
||||
**适用场景**:
|
||||
- ✅ 保存应用状态
|
||||
- ✅ 关闭数据库连接
|
||||
- ✅ 清理临时资源
|
||||
- ✅ 询问用户是否确认退出
|
||||
- ✅ 上传日志或统计数据
|
||||
|
||||
**阻止关闭示例**:
|
||||
```javascript
|
||||
async beforeClose(args, event) {
|
||||
const { dialog } = require('electron');
|
||||
const result = await dialog.showMessageBox({
|
||||
type: 'question',
|
||||
buttons: ['取消', '退出'],
|
||||
message: '确定要退出应用吗?'
|
||||
});
|
||||
|
||||
if (result.response === 0) {
|
||||
// 阻止关闭
|
||||
return false;
|
||||
}
|
||||
|
||||
// 允许关闭
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. quit - 应用退出
|
||||
|
||||
**触发时机**:`beforeClose` 完成后,应用进程终止
|
||||
|
||||
**说明**:
|
||||
- 这是最终状态,不可逆
|
||||
- 所有资源清理应在 `beforeClose` 中完成
|
||||
- 退出后进程结束,无法执行代码
|
||||
|
||||
---
|
||||
|
||||
## 额外生命周期:preload
|
||||
|
||||
### preload - 预加载模块
|
||||
|
||||
**触发时机**:应用启动时,在所有其他钩子之前
|
||||
|
||||
**实现位置**:
|
||||
- 注册:[electron/main.js](electron/main.js#L16)
|
||||
- 实现:[electron/preload/index.js](electron/preload/index.js#L7-L9)
|
||||
|
||||
```javascript
|
||||
// 注册
|
||||
app.register("preload", preload);
|
||||
|
||||
// 实现
|
||||
function preload() {
|
||||
logger.info('[preload] load 1');
|
||||
// 在这里可以做:
|
||||
// - 加载环境变量
|
||||
// - 注册原生模块
|
||||
// - 设置全局异常处理
|
||||
}
|
||||
```
|
||||
|
||||
**适用场景**:
|
||||
- ✅ 加载环境变量
|
||||
- ✅ 注册 Node.js 原生模块
|
||||
- ✅ 设置全局错误处理
|
||||
- ✅ 初始化第三方 SDK
|
||||
|
||||
---
|
||||
|
||||
## 实际开发示例
|
||||
|
||||
### 示例 1:数据库初始化
|
||||
|
||||
```javascript
|
||||
// electron/preload/lifecycle.js
|
||||
const Database = require('better-sqlite3');
|
||||
let db;
|
||||
|
||||
class Lifecycle {
|
||||
async ready() {
|
||||
// 在 ready 钩子中初始化数据库
|
||||
const path = require('path');
|
||||
const dbPath = path.join(app.getPath('userData'), 'app.db');
|
||||
db = new Database(dbPath);
|
||||
logger.info('[lifecycle] database initialized');
|
||||
}
|
||||
|
||||
async beforeClose() {
|
||||
// 在关闭前关闭数据库连接
|
||||
if (db) {
|
||||
db.close();
|
||||
logger.info('[lifecycle] database closed');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 示例 2:自动更新检查
|
||||
|
||||
```javascript
|
||||
// electron/preload/lifecycle.js
|
||||
const { autoUpdater } = require('electron-updater');
|
||||
|
||||
class Lifecycle {
|
||||
async windowReady() {
|
||||
// 窗口就绪后检查更新
|
||||
const { getMainWindow } = require('ee-core/electron');
|
||||
const win = getMainWindow();
|
||||
|
||||
autoUpdater.checkForUpdates();
|
||||
|
||||
autoUpdater.on('update-available', () => {
|
||||
win.webContents.send('update-available');
|
||||
});
|
||||
|
||||
logger.info('[lifecycle] update check started');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 示例 3:托盘图标
|
||||
|
||||
```javascript
|
||||
// electron/preload/lifecycle.js
|
||||
const { Tray, Menu } = require('electron');
|
||||
let tray;
|
||||
|
||||
class Lifecycle {
|
||||
async electronAppReady() {
|
||||
// 在 Electron 就绪后创建托盘
|
||||
const path = require('path');
|
||||
const iconPath = path.join(__dirname, '../../public/images/tray-icon.png');
|
||||
|
||||
tray = new Tray(iconPath);
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: '打开主窗口', click: () => {
|
||||
const { getMainWindow } = require('ee-core/electron');
|
||||
getMainWindow().show();
|
||||
}},
|
||||
{ label: '退出', click: () => {
|
||||
const { app } = require('electron');
|
||||
app.quit();
|
||||
}}
|
||||
]);
|
||||
|
||||
tray.setContextMenu(contextMenu);
|
||||
logger.info('[lifecycle] tray created');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 示例 4:无白屏启动
|
||||
|
||||
```javascript
|
||||
// electron/config/config.default.js
|
||||
windowsOption: {
|
||||
width: 1200,
|
||||
height: 800,
|
||||
show: false, // 关键配置:初始不显示
|
||||
backgroundColor: '#ffffff'
|
||||
}
|
||||
|
||||
// electron/preload/lifecycle.js
|
||||
class Lifecycle {
|
||||
async windowReady() {
|
||||
// 页面加载完成后再显示,避免白屏
|
||||
const { getMainWindow } = require('ee-core/electron');
|
||||
const win = getMainWindow();
|
||||
|
||||
win.once('ready-to-show', () => {
|
||||
win.show();
|
||||
win.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 生命周期执行顺序总结
|
||||
|
||||
```
|
||||
1. preload() # 预加载模块
|
||||
2. new ElectronEgg() # 创建应用实例
|
||||
3. ready() # 核心框架就绪
|
||||
4. electronAppReady() # Electron 就绪
|
||||
5. [创建主窗口] # 框架内部创建窗口
|
||||
6. windowReady() # 窗口就绪
|
||||
7. [应用运行中] # 正常运行状态
|
||||
8. beforeClose() # 关闭前钩子
|
||||
9. [应用退出] # 进程结束
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **异步支持**:所有生命周期钩子都支持 `async/await`,可以执行异步操作
|
||||
|
||||
2. **错误处理**:建议在每个钩子中添加 try-catch 错误处理
|
||||
|
||||
3. **顺序依赖**:不要在早期钩子中访问尚未初始化的资源(如在 `ready` 中操作窗口)
|
||||
|
||||
4. **性能优化**:避免在钩子中执行耗时操作,会阻塞应用启动
|
||||
|
||||
5. **资源清理**:在 `beforeClose` 中务必清理所有资源,避免内存泄漏
|
||||
|
||||
6. **日志记录**:建议在每个钩子中记录日志,方便排查问题
|
||||
|
||||
---
|
||||
|
||||
## 相关文件
|
||||
|
||||
- 生命周期注册:[electron/main.js](electron/main.js)
|
||||
- 生命周期实现:[electron/preload/lifecycle.js](electron/preload/lifecycle.js)
|
||||
- 预加载模块:[electron/preload/index.js](electron/preload/index.js)
|
||||
- 窗口配置:[electron/config/config.default.js](electron/config/config.default.js)
|
||||
|
||||
---
|
||||
|
||||
## 参考资源
|
||||
|
||||
- ElectronEgg 官方文档:https://www.kaka996.com/pages/987b1c/
|
||||
- Electron 官方文档:https://www.electronjs.org/zh/docs/latest/
|
||||
Reference in New Issue
Block a user