Electron v43.1.0 已发布。这是一个偏修复型的版本,最值得桌面应用开发者注意的一点是:修复了替换已经打开的应用程序菜单时可能触发的崩溃。对于依赖动态菜单的应用,比如根据登录状态、当前文档、插件能力或窗口焦点实时调整菜单的产品,这类修复比看起来更关键。
这次更新影响的是哪类应用
Electron 本身把 Chromium、Node.js 和原生桌面能力封装在一起,让开发者用 JavaScript、HTML 和 CSS 构建 macOS、Windows、Linux 三端桌面应用。菜单系统是 Electron 应用里比较靠近操作系统的一层:你写的是 JavaScript,但最终会映射到平台原生菜单行为。
这次 v43.1.0 提到的修复点是“替换已打开的应用程序菜单时触发的崩溃”。换句话说,风险通常出现在这种场景:
- 用户已经打开了应用顶部菜单或上下文菜单;
- 应用代码此时调用
Menu.setApplicationMenu()替换菜单; - 替换时机和原生菜单生命周期撞在一起,导致进程崩溃。
这不是每个 Electron 应用都会遇到的问题。一个静态菜单、启动后基本不变的应用,受影响面较小。但如果你的应用会频繁重建菜单,就值得尽快验证 v43.1.0。
动态菜单为什么容易踩坑
很多桌面应用都会把菜单当成状态的一部分。例如:
- 未登录时显示“登录”,登录后显示“同步”“退出登录”;
- 编辑器有选中文本时启用“复制”“格式化”,没有选区时禁用;
- 当前文件是只读时禁用“保存”;
- 插件安装或卸载后刷新菜单项;
- 多窗口应用根据当前激活窗口切换菜单。
这些逻辑本身没问题,但菜单不是普通 DOM。DOM 节点更新失败,通常只是界面不对;原生菜单更新撞上平台状态,严重时可能直接影响主进程稳定性。Electron v43.1.0 对“打开中的应用菜单被替换”崩溃做了修复,说明这类边界状态在真实应用里足够重要。
可以这样实践:集中管理菜单刷新
下面是一个最小 Electron 示例,演示如何把菜单构建逻辑集中在主进程里,并通过 IPC 根据渲染进程状态刷新菜单。示例可以直接改造成你的应用结构。
运行前需要安装依赖:
mkdir electron-menu-refresh-demo
cd electron-menu-refresh-demo
npm init -y
npm install electron@43.1.0 --save-dev
把 package.json 改成:
{
"name": "electron-menu-refresh-demo",
"version": "1.0.0",
"private": true,
"main": "main.js",
"scripts": {
"start": "electron ."
},
"devDependencies": {
"electron": "43.1.0"
}
}
创建 main.js:
const { app, BrowserWindow, Menu, ipcMain } = require('electron');
let mainWindow;
let state = {
signedIn: false,
documentDirty: false
};
function buildApplicationMenu() {
const template = [
{
label: 'File',
submenu: [
{
label: state.documentDirty ? 'Save Changes' : 'Save',
enabled: state.documentDirty,
click: () => {
if (mainWindow) {
mainWindow.webContents.send('menu:save');
}
}
},
{ type: 'separator' },
{ role: 'quit' }
]
},
{
label: 'Account',
submenu: [
{
label: state.signedIn ? 'Sign out' : 'Sign in',
click: () => {
state.signedIn = !state.signedIn;
refreshApplicationMenu();
if (mainWindow) {
mainWindow.webContents.send('account:changed', state.signedIn);
}
}
}
]
}
];
return Menu.buildFromTemplate(template);
}
function refreshApplicationMenu() {
Menu.setApplicationMenu(buildApplicationMenu());
}
function createWindow() {
mainWindow = new BrowserWindow({
width: 900,
height: 600,
webPreferences: {
preload: `${__dirname}/preload.js`
}
});
mainWindow.loadFile('index.html');
refreshApplicationMenu();
}
ipcMain.on('document:setDirty', (_event, documentDirty) => {
state.documentDirty = Boolean(documentDirty);
refreshApplicationMenu();
});
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
创建 preload.js:
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('appApi', {
setDocumentDirty: (dirty) => ipcRenderer.send('document:setDirty', dirty),
onSaveFromMenu: (handler) => ipcRenderer.on('menu:save', handler),
onAccountChanged: (handler) => ipcRenderer.on('account:changed', (_event, signedIn) => handler(signedIn))
});
创建 index.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Electron Menu Refresh Demo</title>
</head>
<body>
<h1>Electron Menu Refresh Demo</h1>
<p id="status">Document is clean.</p>
<p id="account">Signed out.</p>
<button id="dirty">Mark document dirty</button>
<button id="clean">Mark document clean</button>
<script>
const status = document.querySelector('#status');
const account = document.querySelector('#account');
document.querySelector('#dirty').addEventListener('click', () => {
window.appApi.setDocumentDirty(true);
status.textContent = 'Document has unsaved changes.';
});
document.querySelector('#clean').addEventListener('click', () => {
window.appApi.setDocumentDirty(false);
status.textContent = 'Document is clean.';
});
window.appApi.onSaveFromMenu(() => {
window.appApi.setDocumentDirty(false);
status.textContent = 'Saved from application menu.';
});
window.appApi.onAccountChanged((signedIn) => {
account.textContent = signedIn ? 'Signed in.' : 'Signed out.';
});
</script>
</body>
</html>
启动:
npm start
这个示例的重点不是 UI,而是菜单刷新策略:菜单模板由主进程统一生成,渲染进程只发送状态变化。升级到 v43.1.0 后,可以重点测试“菜单打开时状态变化并触发菜单替换”的场景。
升级时要测什么
建议把 v43.1.0 当作稳定性补丁来验证,而不是只看应用能否启动。可以按下面清单跑一遍:
- 在 macOS、Windows、Linux 上分别打开应用菜单后触发状态变化;
- 在菜单展开时执行登录、退出登录、切换工作区、插件启停等会重建菜单的操作;
- 检查主进程是否有崩溃、未捕获异常或菜单项状态错乱;
- 如果应用有自动更新机制,确认新版本安装后菜单行为一致;
- 对长期运行的应用,测试多次重复刷新菜单后的内存和响应情况。
升级命令很直接:
npm install electron@43.1.0 --save-dev
npm test
npm start
如果你使用 pnpm 或 yarn,对应命令可以改成:
pnpm add -D electron@43.1.0
# 或
yarn add -D electron@43.1.0
采用建议
如果你的 Electron 应用存在动态菜单,尤其是会在用户交互过程中调用 Menu.setApplicationMenu(),v43.1.0 值得优先纳入验证。这个版本的公开重点是修复崩溃,不适合期待它带来明显功能变化;它的价值在于减少一个靠近原生菜单生命周期的稳定性风险。
边界也要说清楚:升级 Electron 只能修掉框架层已经修复的问题,不能替代应用自身的菜单状态管理。菜单刷新仍应集中、可追踪,避免多个窗口、插件或异步任务同时争抢全局应用菜单。对复杂桌面应用来说,稳定的菜单系统不是小装饰,而是主进程质量的一部分。