news 2026/8/26 19:54:20

Cartographist技术栈解剖:Electron + React + immer如何搭建实验性Web浏览器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cartographist技术栈解剖:Electron + React + immer如何搭建实验性Web浏览器

Cartographist技术栈解剖:Electron + React + immer如何搭建实验性Web浏览器

【免费下载链接】cartographistexperimental web browser optimized for rabbit-holing项目地址: https://gitcode.com/gh_mirrors/ca/cartographist

Cartographist 是一款用Electron + React + immer技术栈打造的实验性 Web 浏览器,专为喜欢"兔子洞式"深度浏览的用户设计:点击链接不再弹出新窗口,而是生成一个可横向滚动的窗格;浏览历史不是一条线性列表,而是一棵可以任意回溯的树;整个浏览会话还能保存成一条 "Trail",随时完整恢复。项目源码只有一个src/目录,是学习如何用现代前端技术搭建桌面浏览器的理想标本。

它和 Chrome 有什么不同:3个"反直觉"设计

在拆技术栈之前,先理解这个实验性浏览器想解决什么问题(详见 README.md):

传统浏览器Cartographist 的做法
Cmd+点击打开新窗口生成一个水平可滚动的窗格(Pane)
线性历史记录,只能往前/往后树状大纲,直观展示浏览的分支结构
关闭即丢失会话保存/加载Trail,长期跟踪研究主题

一句话概括:它不是让你"更快打开网页",而是让你"不迷路地迷路"。

技术栈一览:Electron 9 + React 16 + immer 7

核心依赖在 package.json 中,非常精简:

技术版本在项目中承担的角色
Electron^9.1.2桌面壳,提供BrowserWindow<webview>渲染容器
React / react-dom^16.13.1UI 框架,渲染窗格列表与历史树
immer^7.0.7状态管理,把"不可变更新"写得像可变操作
electron-webpack^2.8.2构建工具,本地开发服务器 + 热重载
tachyons^4.12.0原子化 CSS,零自定义样式搞定界面
md5 / normalize-url^2.2.1 / ^5.0.0Trail 未保存变更检测、URL 规范化

整套架构是 Electron 经典的双进程模型src/main/是主进程,src/renderer/是渲染进程,中间靠 IPC 通信。下面逐层解剖。

主进程:一个窗口 + 一份菜单,撑起整个浏览器

📁 src/main/index.js 中创建窗口的代码不到 20 行,但 3 个配置项决定了整个浏览器的形态:

  • titleBarStyle: "hiddenInset"— 隐藏系统标题栏,浏览器自己画一条可拖拽的深色顶栏(配合WebkitAppRegion: "drag"),这就是截图中那种紧凑的"专业工具"质感;
  • webviewTag: true— 开启<webview>标签,这是"一个窗格装一个网页"的物理基础;
  • nodeIntegration: true— 让渲染进程能直接require("fs"),后面的 Trail 保存/加载全靠它。

再看 src/main/menu.js:File 菜单下的New Pane / New Trail / Save Trail / Load Trail四个自定义项,本质都只是mainWindow.webContents.send(cmd)发一条 IPC 消息。主进程不做任何业务逻辑——它只是把键盘快捷键转发给渲染进程,这种"薄主进程"的写法值得学习。

渲染进程:每个窗格都是一个 webview

渲染进程的核心状态定义在 src/renderer/index.js:

{ history, panes, fullscreenId }

panes是一个 URL 数组,map一下就是界面右侧并排的窗格(每个固定 640px 宽,水平滚动)。每个窗格由 webview.js 组件渲染,关键就三行:

  • <webview src={url}>加载网页本体;
  • preload="inject.js"预载一段脚本,监听鼠标悬停并回传链接地址(见 inject.js),实现截图底部那条"悬停 URL 提示";
  • 监听new-window事件:网页里target=_blank打开的新窗口,被劫持成新的 Pane——这就是"不弹新窗口"的魔法入口。

状态管理:immer 如何让"不可变数据"改得像可变数据

React 官方要求状态更新必须返回新对象,但树状浏览历史里有几十层嵌套,手动slice+map+spread写起来极其痛苦。immer的 draft 模式解决了这个问题——项目里 use-immer.js 把它包成了一个 5 行的 Hook:

setState((draft) => { draft.panes.push(newUrl); // 直接"改",immer 自动生成新对象 });

进阶的 use-persisted-immer.js 在此基础上加了localStorage自动读写:启动时恢复上次会话,每次变更自动落盘。一个 Hook 同时拿到"不可变更新 + 本地持久化",是 immer 最优雅的用法之一。

而 Trail 功能(index.js)则演示了 Electron 特有的能力:渲染进程用remote.dialog弹系统对话框,再用fs把整个 state 序列化写成.trail文件,并用md5 哈希判断"当前会话是否有未保存的修改",避免误覆盖。

核心算法:浏览历史是一棵树,不是列表

传统浏览器的历史是链表,而 Cartographist 把每次跳转建模为"在父节点下挂一个子节点",于是历史天然长成树。核心逻辑在 src/renderer/history.js:

  • navigate(history, fromUrl, toUrl)— 从fromUrl节点下找到或创建toUrl子节点;
  • back/forward/get— 在树中定位节点,取父节点或最后访问的子节点。

难点在于:如何在深层递归的遍历中"提前退出"。作者在 utils.js 里给出了一个非常实验性的答案——callcc(continuation-passing 风格):用throw new Exit(arg)模拟"从任意深度直接跳回顶层"的语义,traverse负责递归走树,callcc负责携带结果逃离。这套组合拳只有 40 行代码,却同时被历史操作和可视化复用,是全项目最值得咀嚼的一段。

history-visualization.js 则把这棵树画成了截图中左侧的 SVG:竖线表示分支跨度,横线连接同层节点,点开任意节点即可"沿着祖先路径"直达那个窗格。

快速上手:两条命令跑起这个实验性浏览器

项目目前只提供源码运行方式(README 原话:No binary builds are available right now, purely out of laziness):

git clone https://gitcode.com/gh_mirrors/ca/cartographist cd cartographist npm install npm start

运行后就是一个带历史树的实验性浏览器,Ctrl/Cmd+T开新窗格,Ctrl/Cmd+S保存 Trail。

总结:这个"小项目"值得抄的三个作业

  1. 薄主进程 + 厚渲染进程:主进程只做窗口、菜单和 IPC 转发(src/main/),业务全在 React 里,架构边界清晰;
  2. immer 的 draft 模式:管理深层嵌套状态时,"像改可变对象一样写代码,拿到的却是不可变更新",配合 5 行自定义 Hook 即可叠加持久化(src/renderer/use-persisted-immer.js);
  3. 用数据模型而非 UI 驱动行为:窗格是数组、历史是树,界面只是这两个数据结构的投影——状态对了,UI 几乎自动就对了。

如果你想给自己的浏览器加"空间感",或者研究 Electron 中<webview>+ IPC + immer 的完整闭环,Cartographist 这个千行级小项目就是最好的起点。🗺️

【免费下载链接】cartographistexperimental web browser optimized for rabbit-holing项目地址: https://gitcode.com/gh_mirrors/ca/cartographist

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/26 19:51:26

GPUIX元素完全参考:11个原生元素一次看懂(附代码示例)

GPUIX元素完全参考&#xff1a;11个原生元素一次看懂&#xff08;附代码示例&#xff09; 【免费下载链接】gpuix Node.js & React bindings for Zed GPUI. 项目地址: https://gitcode.com/gh_mirrors/gp/gpuix GPUIX 是 Zed 编辑器 GPU 渲染框架 GPUI 的 React 绑定…

作者头像 李华
网站建设 2026/8/26 19:40:10

女主播的“单身人设”到底值多少钱?——2500万打赏背后的法律红线

2500万元。这不是一桩商业并购案的金额&#xff0c;而是一名女主播凭借“单身未婚”人设从三名男粉丝手中获取的打赏总额。近日&#xff0c;95后抖音女主播魏莹被控诈骗一案再度引发舆论热议。这位福建连江籍、拥有近200万粉丝的女主播&#xff0c;2019年入局直播后长期隐瞒已婚…

作者头像 李华