# Electron 多标签浏览器实现计划(高性能方案) ## 目标 - 在现有 Electron + Vue + TypeScript + TailwindCSS 项目中实现类似 Chrome 的多标签页浏览体验:创建、切换、关闭、前进、后退、刷新、地址输入、拓展插件入口、收藏入口。 - 采用高性能与安全优先的架构:主进程 `BrowserView` 管理;渲染层仅通过受控 API;IPC 类型明确;持久化与插件机制可扩展。 ## 当前项目结构与集成点 - 主进程入口:`src/main.ts`(窗口创建与 IPC 注册,参考 `src/main.ts:11-57`) - 预加载:`src/preload.ts`(已暴露 `window.api`,参考 `src/preload.ts:7-17`) - 渲染层入口:`index.html` + `src/renderer.ts`(Vue 应用挂载,参考 `src/renderer.ts:35-45`) - 现有 IPC 控制器:`src/controller/changeWindowSize.js`(窗口操作) ## 高性能技术方案 - 选型:使用 `BrowserView` 每个标签一个 `BrowserView`,由主进程统一管理。 - 原因:`BrowserView` 与主窗口同进程但独立渲染,API 完整(`webContents` 导航、生命周期事件),相较 `` 更易管控、性能与兼容性更好。 - 视图复用与生命周期: - 活跃标签:将其 `BrowserView` attach 到主窗口;非活跃标签:detach(保留引用与状态),避免多视图同时渲染占用资源。 - 限制最大同时 attach 数量(默认 1),保障 GPU/CPU 负载稳定。 - 会话与隔离: - 默认共享 `session`(`partition: 'persist:main'`),减少多会话开销。 - 可按需支持隔离会话(隐私标签):`partition: 'tab:'`。 - 导航性能与安全: - 导航统一通过主进程 `view.webContents.loadURL(url)`;前进/后退/刷新使用 `goBack/goForward/reload`。 - 外链打开统一通过 `shell.openExternal(url)`,白名单校验(已存在 `external-open` 通道,参考 `src/main.ts:33-43`)。 - 地址栏与状态: - 渲染层地址栏仅发起 IPC;主进程执行导航并广播当前标签的 `url/title/loading/historyState`。 - 书签与持久化: - 存储方案优先使用 `electron-store`(JSON,轻量、跨平台);高并发或大数据可切换 `better-sqlite3`。 - 插件入口: - 设计内部插件机制(非 Chrome 扩展):定义 `onTabCreated/onNavigate/beforeLoad/afterLoad` 等钩子;插件注册于主进程。 - Chrome 扩展仅作为可选(`session.loadExtension`),受限于兼容性与审核,不作为默认方案。 ## 模块设计 ### 主进程(`src/main/`) - `TabManager`:管理 `BrowserView` 生命周期与状态 - 方法:`create(url?)`、`switch(tabId)`、`close(tabId)`、`navigate(tabId, url)`、`reload(tabId)`、`goBack(tabId)`、`goForward(tabId)`、`list()`。 - 事件:`tab-updated`(title/url/loading)、`tab-created`、`tab-closed`、`tab-switched`。 - `IPCRegistry`:集中注册通道 - `tab:create | tab:switch | tab:close | tab:navigate | tab:reload | tab:back | tab:forward | tab:list` - `bookmark:add | bookmark:remove | bookmark:list | bookmark:folders` - `plugin:invoke(hook, payload)`(内部插件钩子转发) - `BookmarkStore`:封装 `electron-store` 或 SQLite(可插拔) - `PluginHost`:插件注册与钩子执行(有序、可熔断) ### 预加载(`src/preload.ts`) - 扩展现有 `window.api`: - `tabs.*`:与上述 IPC 一一对应,统一 `invoke` 调用;`tabs.on(event, handler)` 用于订阅主进程广播(通过 `ipcRenderer.on` 包装)。 - `bookmarks.*`:增删改查接口。 - `plugins.invoke(hook, payload)`:触发插件钩子。 ### 渲染层(Vue) - 布局页面:`BrowserLayout`(地址栏、标签条、控制区、书签/插件入口) - 组件: - `TabBar`:显示标签列表,支持新建/切换/关闭、拖拽排序(后续) - `AddressBar`:URL 输入与状态展示(加载中、锁标识、HTTPS) - `Controls`:后退/前进/刷新/新建标签按钮 - `BookmarksPane`:收藏夹入口(侧栏或菜单) - `PluginsMenu`:插件入口(菜单或面板) - 路由:`/browser` 作为应用主界面;初始打开一个空白或主页标签。 ## IPC 通道与类型(示例) ```ts type TabId = string; interface TabInfo { id: TabId; url: string; title: string; isLoading: boolean; canGoBack: boolean; canGoForward: boolean } // 请求 tab:create(url?: string) => TabInfo tab:switch(tabId: TabId) => void tab:close(tabId: TabId) => void tab:navigate({ tabId, url }: { tabId: TabId, url: string }) => void tab:reload(tabId: TabId) => void tab:back(tabId: TabId) => void tab:forward(tabId: TabId) => void tab:list() => TabInfo[] // 广播 tab-updated: TabInfo tab-created: TabInfo tab-closed: { tabId: TabId } tab-switched: { tabId: TabId } ``` ## 数据模型 - `Tab`:`{ id, view, url, title, isLoading, createdAt }` - `Bookmark`:`{ id, title, url, folderId?, createdAt }` - `Folder`:`{ id, name, parentId? }` - `Plugin`:`{ id, name, hooks }` ## 性能优化要点 - 仅 attach 当前活跃 `BrowserView` 到窗口;对非活跃标签 `detach` 保留状态。 - 控制最大标签数(例如 20),超过时启用 LRU 释放策略(可配置)。 - 启用硬件加速,保持默认;避免禁用 GPU。 - 监听 `did-stop-loading`/`did-finish-load` 更新状态,减少渲染层轮询。 - 对地址栏与状态广播使用节流(例如 100ms)。 - 持久化异步批量写入(书签、会话恢复)。 ## 安全策略 - 保持 `contextIsolation: true`、`sandbox: true`、`nodeIntegration: false`(已在 `src/main.ts:20-26`) - 外链统一 `shell.openExternal` + 白名单(已在 `src/main.ts:33-43`) - 严格 CSP 保留于渲染层 `index.html`;`BrowserView` 加载外域不受该 CSP 限制,但需根据业务限制域名。 ## 迭代计划(三阶段) 1. 核心能力(主进程 + IPC + 预加载) - 实现 `TabManager` 与全部导航方法 - 注册 IPC(tabs/bookmarks/plugins)与广播 - 预加载扩展 `window.ipcAPI.tabs/*`、事件订阅封装 2. 渲染层界面 - 新建 `BrowserLayout` 与基础组件(TabBar、AddressBar、Controls) - 打通地址栏与导航;同步标题与加载状态 - 书签入口基础增删与列表展示 3. 插件与高级能力 - `PluginHost` 与钩子机制;内置示例插件(如:拦截导航统计) - 标签拖拽排序、会话恢复、快捷键(Ctrl/Cmd+T/W、Ctrl/Cmd+L、Ctrl/Cmd+R、Alt+←/→) ## 集成步骤(细化) - 主进程:新增 `src/main/tab-manager.ts`、`src/main/ipc.ts`、`src/main/bookmark-store.ts`、`src/main/plugin-host.ts`;在 `src/main.ts` 初始化与注册。 - 预加载:扩展 `window.api`,新增 `tabs`、`bookmarks`、`plugins` 命名空间。 - 渲染层:新增 `/browser` 页面与组件,替换应用首页或通过路由进入。 ## 决策点(需确认) 1. 标签视图方案:仅 `BrowserView`(推荐),允许 `` 兼容模式 2. 最大标签数量与释放策略:默认 20,接受LRU 释放 3. 会话策略:全部共享 `session` ,支持隐私标签独立 `partition` 4. 书签存储:默认 `electron-store` ,暂不考虑 SQLite(`better-sqlite3`) 5. 插件能力边界:需要支持加载 Chrome 扩展(`session.loadExtension`) 6. 首页与地址栏行为:默认主页 URL、空白页(`about:blank`),可自定义欢迎页 7. 路由集成:将 `/browser` 作为默认首页,保留现有 `/about` 等页面 ## 验收与测试 - 开发启动:`npm run start`,验证创建/切换/关闭/导航/刷新基本路径 - 事件广播:在 Vue 中订阅 `tab-updated`,确保标题/加载进度实时更新 - 书签:新增/删除/持久化验证与重启恢复 - 性能:在 10+ 标签场景观察 CPU/GPU 占用与 UI 响应 - 安全:尝试非法域名导航,验证白名单拦截与错误提示 --- 后续我将基于以上计划逐步实现。在“决策点”中的问题请先确认,我将据此微调实现(例如是否支持隐私标签、是否引入 SQLite、是否兼容 ``)。 **待反馈决策** - 顶部 UI 高度与 `BrowserView` 边界 - 当前使用固定偏移 `64px` 对齐顶部 UI。是否改为渲染层动态上报高度(例如在布局变化时通过 IPC 设置),以适配不同分辨率与主题? - Chrome 扩展加载 - 文档中确认“需要支持加载 Chrome 扩展”。建议作为后续阶段实现,采用 `session.loadExtension` 并隔离到特定 `partition`,以减少对主会话的影响;请确认是否需要默认加载的扩展清单或仅提供入口。 如果以上决策点确认,我将继续第二阶段:完善 UI 高度动态设置与扩展加载入口,同时补充书签持久化(基于 `userData` 目录 JSON 文件)与插件钩子框架。