☰
menubar 版本演进指南:从 6.0 到 9.5 的 API 变更、Electron 兼容性与迁移实战
2026/10/15 17:48:12 网站建设 项目流程
  • 桌面应用
  • 开发工具

【免费下载链接】menubar

➖ high level way to create menubar desktop applications with electron

项目地址:https://gitcode.com/gh_mirrors/me/menubar
点击查看免费下载

导读

menubar 是一个基于 Electron 的高层封装库,让开发者可以用极少的样板代码创建常驻系统托盘(菜单栏)的桌面应用:只需指向你的index.html,剩下的 Tray 图标、窗口定位、显隐切换等都由它处理。本文以仓库中的 CHANGELOG.md 为骨架,系统梳理 menubar 从 6.0.0 到 9.5.3 的版本演进脉络,完整覆盖各版本新增的特性(Features)、修复的缺陷(Bug Fixes)与破坏性变更(BREAKING CHANGES),并结合 src/Menubar.ts 等源码说明这些变更的底层实现,帮助你理解 API 演进的来龙去脉,并在升级时做出正确的迁移决策。

读完本文,你将掌握:menubar 各项核心选项与事件的生命周期及来源版本、browserWindow字段的引入背景、activateWithApp与before-load等新能力的用法、Electron 版本与 menubar 版本的对应关系,以及 7.0.0 / 6.0.0 两次破坏性变更的具体迁移写法。


版本总览:一条通向 9.5.x 的演进线

当前仓库的版本为9.5.3(见 package.json),CHANGELOG 记录的演进时间线如下:

版本发布日期类型核心要点
9.5.32026-07-29Patch例行维护
9.5.22025-10-10Patch例行维护
9.5.12024-10-11Patch例行维护
9.5.02024-06-25Minor扩大 Electron 支持范围;修复 Win32 定位与原生菜单示例
9.4.02023-11-28Minor升级至 Electron 27;修复setVisibleOnAllWorkspaces破坏 Dock 状态的问题
9.3.02023-02-13Minor新增 Electron 22 支持
9.2.32022-10-05Minor新增 Electron 21 支持
9.2.22022-09-05Minor将 Electron 20 加入 peerDependency;修复 arrow 示例
9.2.12022-07-11Patch新增 Electron 19 支持
9.2.02022-04-11Minor新增before-load事件
9.1.22022-03-29Patch新增 Electron 17 支持
9.1.12021-12-09Patch新增 Electron 16 支持
9.1.02021-10-27Minor新增activateWithApp选项
9.0.62021-10-15Patch新增 Electron 14/15 支持
9.0.52021-06-28Patch新增 Electron 13 支持;修复 Linux/Windows 任务栏在左侧时的窗口定位
9.0.42021-05-03Patch新增 Electron 12 支持
9.0.32021-02-24Patch新增 Electron 10/11 支持
9.0.22021-01-20Patch改进 Windows 任务栏位置检测
9.0.12021-05-28Patch修复showWindow()阻止窗口关闭的问题
9.0.02020-05-27Major要求 Electron 9
8.0.x2020Minor/PatchElectron 8 支持;修复 Dock 图标点击显示窗口、Windows 闪烁
8.0.02020-02-10Major推荐 peer dependency 为electron@^8.0.0
7.2.02020-01-16Minor新增loadUrlOptions选项
7.1.02019-11-25Minor允许跳过loadUrl(index: false)
7.0.02019-10-23Major破坏性变更:放弃 Electron 4/5/6;menubar参数改为dir字段;窗口尺寸参数迁入browserWindow
6.0.x2019系列修复Windows 定位、after-hide重复触发、Menubar.window访问等
6.0.02019-05-31Major破坏性变更:代码库全部迁移至 TypeScript;导出方式改为具名导出menubar;新增browserWindow字段;支持NativeImage图标

从这张表中可以提炼出两条清晰的演进主线:一是跟随 Electron 大版本不断扩宽兼容性(9.x 系列几乎每个版本都对应一个新 Electron 大版本);二是 API 的收敛与现代化(字符串参数 →dir字段、散落的窗口参数 →browserWindow对象、CommonJS 默认导出 → 具名导出)。


一、6.0.0:TypeScript 重写与第一次破坏性变更

6.0.0 是 menubar 历史上的分水岭,它同时完成了三件事:全量 TypeScript 重写、导出方式变更、窗口配置收敛到browserWindow。

1.1 导出方式:从默认导出到具名导出

6.0.0 之前的写法是 CommonJS 默认导出:

var menubar = require('menubar');

6.0.0 之后必须使用具名导出:

- var menubar = require('menubar'); + var { menubar } = require('menubar');

使用 ES6/TypeScript 语法时等价于:

import { menubar } from 'menubar';

这一变更与源码的模块组织方式直接对应:入口文件 src/index.ts 中menubar是一个具名导出的工厂函数,同时导出了Menubar类与getWindowPosition工具函数。工厂函数内部会创建一个Menubar实例:

export function menubar(options?: Partial<Options>): Menubar { return new Menubar(app, options); }

1.2 新增browserWindow字段,废弃散落的窗口参数

6.0.0 引入了options.browserWindow字段,用于统一承载所有 BrowserWindow 构造参数,取代原先直接挂在menubar()参数表上的height、width、x、y、alwaysOnTop等字段。这一设计延续至今:在 src/types.ts 中,browserWindow的类型就是 Electron 官方的BrowserWindowConstructorOptions,这意味着 Electron 支持的所有窗口选项都可以原样透传。

底层实现上,src/Menubar.ts 的createWindow()方法会把默认行为与用户配置合并后交给new BrowserWindow():

const defaults = { show: false, // 创建时不显示,等待第一次点击托盘图标 frame: false, // 移除窗口边框,使其看起来像菜单栏 }; this._browserWindow = new BrowserWindow({ ...defaults, ...this._options.browserWindow, });

其中show: false与frame: false是 menubar 强加的默认行为,用户传入的browserWindow配置会覆盖它们。

1.3 图标支持NativeImage

6.0.0 同时让icon选项支持Electron.NativeImage类型(见 src/types.ts 中icon?: string | Electron.NativeImage),不再局限于 PNG 路径字符串,这为动态生成托盘图标提供了可能。

1.4 6.0.x 系列的关键修复

6.0.x 期间修复了若干影响实际使用的缺陷,其中与窗口生命周期相关的几个值得关注:

  • 修复访问Menubar.window的问题(6.0.3):此前在部分时机访问.window可能拿不到 BrowserWindow 实例。当前实现中window是一个 getter,返回this._browserWindow,在窗口被关闭(after-close触发)后会被置为undefined(见 src/Menubar.ts 的windowClear())。
  • 修复 Windows 定位崩溃(6.0.6):位置计算在 Windows 上的崩溃问题,与下方定位逻辑的迭代有关。
  • 修复after-hide事件重复触发(6.0.4):当前hideWindow()实现中先emit('hide')、再调用this._browserWindow.hide()、随后emit('after-hide'),配合_isVisible标志位避免了重复触发(见 src/Menubar.ts 的hideWindow())。
  • 无图标时使用内置猫图标兜底(6.0.2):当用户未提供icon且默认路径的IconTemplate.png也不存在时,回退到仓库 assets/IconTemplate.png。对应逻辑见 src/Menubar.ts 的appReady():
let trayImage = this._options.icon || path.join(this._options.dir, 'IconTemplate.png'); if (typeof trayImage === 'string' && !fs.existsSync(trayImage)) { trayImage = path.join(__dirname, '..', 'assets', 'IconTemplate.png'); // Default cat icon }
  • 修正 Windows 多任务栏下的窗口位置(6.0.4):这与下面将要详述的taskbarLocation检测逻辑一脉相承。

二、7.0.0:API 收敛的破坏性变更

7.0.0 引入了 CHANGELOG 中标注最详细的破坏性变更,主要体现在放弃对 Electron 4/5/6 的支持以及两处参数形态的迁移。这些迁移规则至今仍有效,理解它们有助于避免在老教程中看到过时写法。

2.1 字符串参数迁移为dir字段

旧版本允许把应用目录以字符串形式直接传给menubar(),7.0.0 起必须改为dir字段:

- menubar('/home/me/MY_ABSOLUTE_PATH'); + menubar({ dir: '/home/me/MY_ABSOLUTE_PATH' });

在 src/util/cleanOptions.ts 中,dir会经过两项预处理:若未提供则取app.getAppPath(),若为相对路径则path.resolve()转为绝对路径。而默认的index则基于dir拼接生成file://协议的地址,指向dir/index.html:

options.index = url.format({ pathname: path.join(options.dir, 'index.html'), protocol: 'file:', slashes: true, });

2.2 窗口参数迁移进browserWindow

旧版本将x、y、height、width、alwaysOnTop直接挂在menubar()参数上,7.0.0 要求把它们放进browserWindow字段:

- menubar({ - x: 12, - y: 34, - height: 500, - width: 320, - alwaysOnTop: true - }); + menubar({ + browserWindow: { + x: 12, + y: 34, + height: 500, + width: 320, + alwaysOnTop: true + } + });

注意alwaysOnTop与窗口显隐行为的关联:在 src/Menubar.ts 的createWindow()中,窗口失焦(blur)行为取决于是否设置了alwaysOnTop—— 若窗口始终置顶,失焦时仅触发focus-lost事件而不自动隐藏;否则在 100ms 延时后自动调用hideWindow()。

2.3 7.1.0 与 7.2.0:加载行为的新选项

在 7.x 的后续小版本中,加载行为获得两个重要选项:

  • index: false跳过loadUrl(7.1.0):当应用希望自行控制加载(例如加载特定 URL 或使用@electron/remote等预加载场景)时,可以将index显式设为false。在 src/Menubar.ts 的createWindow()中,仅当this._options.index !== false时才调用loadURL。注意index的类型是string | false,不能用undefined代替,否则会走默认的dir/index.html拼接逻辑。
  • loadUrlOptions(7.2.0):加载index时透传给browserWindow.loadURL(url, options)的附加选项,类型为 Electron 的LoadURLOptions(见 src/types.ts),默认值为{}(由 src/util/cleanOptions.ts 归一化)。

三、8.x:Electron 8 支持与平台行为修复

8.0.0 将推荐的 peer dependency 更新为electron@^8.0.0。8.x 期间的修复主要集中在平台行为一致性上:

  • Windows 上 Dock 图标点击显示窗口(8.0.2):确保点击任务栏 Dock 图标时窗口能正确显示,避免菜单栏应用在 Windows 上“唤不醒”的体验问题。
  • 修复 Windows 上的闪烁(8.0.2,对应 issue #274):通过调整窗口创建与显示的时机减少打开瞬间的闪烁。这与 src/Menubar.ts 中show: false默认值 +showWindow()显式控制显示的机制相关:窗口创建时不直接显示,而是在托盘事件触发后才setPosition()并show()。
  • 安全依赖升级(8.0.1):将acorn从 6.1.1 升至 6.4.1,属于常规安全维护。

四、9.0.x:定位系统大修与 Electron 兼容性扩张

9.0.0 是 Electron 9 时代的起点(CHANGELOG 明确要求 "Please use Electron 9 with this menubar version")。9.0.x 系列除了逐版本跟进 Electron 大版本外,还密集修复了跨平台窗口定位问题,这正是 menubar 在 Linux/Windows 上体验的核心。

4.1 平台定位逻辑的源码实现

从 9.0.2(改进 Windows 任务栏位置检测)、9.0.5(修复 Linux/Windows 任务栏在左侧时的定位)到 9.5.0(win32 位置修复),背后是 src/util/getWindowPosition.ts 中一套完整的任务栏方位推断算法。

核心函数taskbarLocation(tray)通过对比**屏幕工作区(workArea)与显示器边界(screenBounds)**的相对关系来判断任务栏方位:

// TASKBAR LEFT: 工作区起点 x > 0,说明左侧被任务栏占用 if (workArea.x > 0) { if (isLinux && workArea.y > 0) return 'top'; return 'left'; } // TASKBAR TOP: 工作区起点 y > 0 if (workArea.y > 0) { return 'top'; } // TASKBAR RIGHT: 工作区宽度小于显示器宽度,且左侧情形已被排除 if (workArea.width < screenBounds.width) { return 'right'; } // 其余情况都是底部任务栏 return 'bottom';

在此基础上,getWindowPosition(tray)按平台映射出最终的窗口锚点:

  • macOS(darwin):固定返回trayCenter,托盘图标居中弹出;
  • Linux / Windows:根据任务栏方位返回topRight(任务栏在顶部且为 Linux 时)、bottomRight(底部/右侧)、bottomLeft(左侧)等;
  • 无法判断时兜底为topRight。

4.2 显示前的实时同步

在 src/Menubar.ts 的showWindow()中,Windows 与 Linux 平台会在每次显示前重新计算窗口位置,以应对任务栏位置或分辨率变化:

if (['win32', 'linux'].includes(process.platform)) { this._options.windowPosition = getWindowPosition(this.tray); }

随后通过electron-positioner的calculate()计算坐标,并优先使用用户在browserWindow.x/y中显式指定的值覆盖计算结果(注意源码中特意不用||而是用!== undefined判断,以允许 x/y 为 0 的合法值),最后Math.round()后调用setPosition()—— 这一 round 处理正是为了避免setPosition传入非整数而崩溃(对应 6.0.6 的修复背景)。

4.3 9.0.1:showWindow()与窗口关闭

9.0.1 修复了调用showWindow()导致菜单栏窗口无法关闭的问题(issue #287)。从当前实现看,showWindow()会先确保 Tray 与 BrowserWindow 存在(必要时调用createWindow()),再走“缓存 bounds → 计算位置 → show”的流程,配合_isVisible状态与blur自动隐藏机制,保证窗口既能被点击打开、也能正常失焦关闭。


五、9.1.x - 9.2.x:事件与激活行为的精细化

这一阶段以功能新增为主,全部沉淀为当前稳定 API。

5.1activateWithApp:控制 macOS 激活行为(9.1.0)

macOS 下点击 Dock 图标会触发app.on('activate')。默认情况下 menubar 会监听该事件并在没有可见窗口时打开菜单栏窗口;新增的activateWithApp选项让你可以关闭这一行为(见 src/types.ts,默认true)。

底层实现在 src/Menubar.ts 的appReady()中:

if (this._options.activateWithApp) { this.app.on('activate', (_event, hasVisibleWindows) => { if (!hasVisibleWindows) { this.showWindow().catch(console.error); } }); }

该选项与showDockIcon(macOS 专属,控制是否调用app.dock.hide()隐藏 Dock 图标)配合,可精细控制菜单栏应用在 macOS 上的“存在感”。注意 src/Menubar.ts 中仅在this.app.dock存在且showDockIcon未开启时才隐藏 Dock 图标。

5.2before-load事件:在加载页面之前介入(9.2.0)

before-load是 9.2.0 新增的事件,位于create-window之后、loadURL之前。从 src/Menubar.ts 的createWindow()可以看到完整的事件序列:

this.emit('create-window'); // ... 创建 BrowserWindow、Positioner、blur 监听 ... this.emit('before-load'); if (this._options.index !== false) { await this._browserWindow.loadURL(this._options.index, this._options.loadUrlOptions); } this.emit('after-create-window');

before-load的典型用途是启用@electron/remote等需要抢在页面加载前完成的设置。README 中列举的完整事件生命周期如下:

事件触发时机
readyTray 图标已创建并初始化完成(注意区别于 Electron 的app.on('ready'))
create-window调用new BrowserWindow()的前一行
before-load窗口创建后、loadURL前
after-create-window所有窗口初始化代码完成且 URL 加载完成后
showwindow.show()被调用的前一行
after-showwindow.show()被调用后
hidewindow.hide()被调用的前一行(窗口失焦时)
after-hidewindow.hide()被调用后
after-close.window(BrowserWindow)属性被置空后
focus-lost设置alwaysOnTop时用户点击窗口外部触发

5.3 Electron 兼容性的连续跟进(9.1.x - 9.2.x)

这一阶段逐版本跟进 Electron:9.1.1(Electron 16)、9.1.2(Electron 17)、9.2.1(Electron 19)、9.2.2(Electron 20 进入 peerDependency,并修复 arrow 示例)、9.2.3(Electron 21)。当前 package.json 中的 peerDependencies 为electron >= 9.0.0,devDependencies 使用electron ^43.0.0,README 的兼容性表也说明 9.x 在 CI 中持续对 Electron 35.x - 43.x 做类型检查。


六、9.3.x - 9.5.x:近期的平台修复与兼容性扩张

6.1 9.4.0:Electron 27 与 Dock 状态保护

9.4.0 将 Electron 升级到 27,并修复了一个隐蔽的 macOS 问题:setVisibleOnAllWorkspaces会破坏app.dock原本的可见状态(issue #442)。修复后的实现(见 src/Menubar.ts 的createWindow())为setVisibleOnAllWorkspaces增加了skipTransformProcessType选项:

if (this._options.showOnAllWorkspaces !== false) { this._browserWindow.setVisibleOnAllWorkspaces(true, { skipTransformProcessType: true, // Avoid damaging the original visible state of app.dock }); }

这里也体现了选项的默认值:showOnAllWorkspaces默认开启(仅当显式设为false时跳过),让窗口在所有 macOS 工作区(Space)中可见。

6.2 9.5.0:Electron 支持扩张与示例修复

9.5.0 完成了三项工作:

  • 扩大 Electron 支持范围(issue #473):与整个 9.x 系列“持续扩宽 peerDependency 兼容面”的路线一致;
  • 修复原生菜单示例(issue #471):对应 examples/native-menu/main.js。该示例展示了如何先创建带右键菜单的Tray,再通过menubar({ tray })传入(此时icon选项会被忽略),并在ready后调用tray.removeAllListeners()以规避 macOS 上的白屏问题;
  • 修复 win32 位置(issue #479):继续完善 Windows 平台下的窗口定位,最终沉淀为上文所述的getWindowPosition算法。

6.3 9.5.1 - 9.5.3:稳定期

9.5.1、9.5.2、9.5.3 均为无破坏性的例行维护版本,标志着 9.x 系列进入稳定期。


七、升级迁移实战:把旧代码一次性迁移到现代 API

综合两次破坏性变更(6.0.0 与 7.0.0),把一份“上古”代码迁移到当前 9.5.x 版本需要同时完成三处改写。以下是一个完整的迁移对照:

迁移前(v5/v6 早期风格):

var menubar = require('menubar'); var mb = menubar('/home/me/MY_ABSOLUTE_PATH');

迁移后(9.x 风格):

const { menubar } = require('menubar'); const mb = menubar({ dir: '/home/me/MY_ABSOLUTE_PATH', browserWindow: { width: 400, height: 400, alwaysOnTop: true, }, }); mb.on('ready', () => { console.log('Menubar app is ready.'); });

迁移要点归纳:

  1. 导出方式:require('menubar')改为const { menubar } = require('menubar'),或使用import { menubar } from 'menubar';
  2. 目录参数:字符串参数改为{ dir: ... }对象字段;
  3. 窗口参数:x/y/width/height/alwaysOnTop全部迁入browserWindow对象;
  4. Electron 版本:确保项目使用 Electron 9 及以上(建议跟随 README 兼容表选择当前 CI 持续验证的 Electron 版本范围)。

验证迁移结果:跑通测试

迁移后可以用仓库自带的 Jest 测试验证基础对象契约。当前 src/Menubar.spec.ts 验证了四个核心不变量:

  • mb.app始终存在(Electron App 实例);
  • 在after-create-window事件触发前访问mb.positioner会抛出异常,触发后可正常访问;
  • 在ready事件触发前访问mb.tray会抛出异常,触发后为Tray实例;
  • mb.window在ready前为undefined,ready后为BrowserWindow实例。

这些断言与 src/Menubar.ts 中positioner、traygetter 的“未就绪即抛错”设计一一对应,也印证了 CHANGELOG 中各版本围绕事件时序所做修复的最终形态。


结语:从 CHANGELOG 看 menubar 的演进哲学

回看这份 CHANGELOG,menubar 的演进路径非常清晰:每解锁一个新 Electron 大版本就发布一个小版本(9.0.x - 9.5.x 几乎与 Electron 12 - 43 一一对应),功能新增始终围绕菜单栏场景的核心体验(定位、显隐、事件时序、激活行为),而两次破坏性变更都服务于 API 的收敛与类型安全(TypeScript 化、参数归入browserWindow、具名导出)。对使用方而言,掌握 7.0.0 的迁移规则与 9.x 的 Electron 兼容矩阵,就能让项目长期稳定地跟随这个库的演进节奏。

如需查阅完整的 API 参考,可继续阅读仓库内的 API 文档、Menubar 类文档 与 Options 接口文档;动手实验可参考 hello-world、arrow、icon-animation 与 native-menu 四个示例。

  • 桌面应用
  • 开发工具

【免费下载链接】menubar

➖ high level way to create menubar desktop applications with electron

项目地址:https://gitcode.com/gh_mirrors/me/menubar
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询