前言与背景
做前端或跨平台桌面开发的朋友,应该苦 Electron 久矣。一个简单的 Hello World 打包出来动辄 100MB+,启动先黑屏两秒,日常跑起来吃掉两三百兆内存更是家常便饭。如果直接调用系统自带的 WebView,又会陷入各平台渲染行为不一致、底层能力受限的泥潭。
为了探究现代浏览器内核底层的真实运行机制,同时也为了做一个真正极端轻量的桌面级运行时,我用纯 C99 从零写了一个轻量级浏览器内核与桌面应用框架 ——TinyFramework。
不依赖 Chromium、Webkit,也不依赖 Node.js。从最底层的 GPU 上下文、WHATWG HTML5 状态机、CSS 计算、DOM 树、布局排版,到 JS 引擎集成与 VFS 加密打包全部自研。最终产出的完整二进制发布包体积仅约4MB,冷启动耗时在0.15 秒左右,运行时内存占用稳定在10~20MB。
开源仓库地址:https://github.com/tzdwindows/TinyFramework
Git Clone:
git clone [https://github.com/tzdwindows/TinyFramework.git](https://github.com/tzdwindows/TinyFramework.git)
架构设计与核心指标
TinyFramework 采用单线程主循环 + 异步 I/O 线程池模型,对外统一暴露简洁的 C API,并支持双模式自由切换:
CUSTOM_MINI 模式:全自研渲染管线 + QuickJS 引擎,功能完全可控。
NATIVE 模式:体积极致敏感时委托给系统原生 WebView。
| 核心指标 | 自研引擎模式 (CUSTOM_MINI) | 传统 Electron 方案 |
| 二进制打包体积 | ~4 MB(含 JIT、TLS、内置字体) | 120 MB ~ 200 MB+ |
| 冷启动耗时 | ~0.15 秒 | 1.5 ~ 3.5 秒 |
| 基础内存开销 | 10 ~ 20 MB | 150 ~ 300 MB |
| JS 引擎与执行 | QuickJS (带基线 JIT + SLJIT) | V8 |
核心子系统实现拆解
1. GPU 渲染管线与字形系统
向量命令缓冲:借鉴现代游戏引擎设计,渲染阶段先录制所有绘制命令,帧末统一刷新。通过对材质与着色器状态预排序,极大减少
glUseProgram和glBindTexture的上下文切换开销。字形与图集:基于
stb_truetype实现动态字形图集,支持多达 8 级字体回退链(Fallback Chain)。CPU 镜像合成直接上传纹理,杜绝 GL 回读造成的管线停顿。抗锯齿与裁剪:Scissor + 基于 Stencil 缓冲的层叠圆角裁剪,配合 16 槽 LRU 渐变光栅化缓存。
2. HTML5 解析器与 DOM / 布局引擎
标准 HTML5 状态机:严格遵循 WHATWG 规范,实现 Tokenizer 状态机及插入模式栈,完整支持 Adoption Agency Algorithm (AAA) 处理错位嵌套标签与表格 Foster-parenting。
增量渲染门控:DOM 节点指针设计覆盖主流前端框架(如 Vue 3 / React 18)的 vDOM Diff 需求。通过
dirty、layout_dirty、paint_dirty三级脏标记门控,页面无属性变化或处于静态时,CPU 占用自动归零。流式排版:支持 Block 流式布局、Flexbox、Grid 以及基础 Web Components (Shadow DOM / Slots)。
3. CSS 属性计算与复杂文本
计算器与变量:内置 CSS Variables 作用域递归解析,数学计算引擎完整支持
calc()多层嵌套及三角函数、区间限制函数(clamp()、min()、max()等)。国际化排版:纯 C 实现 Unicode UAX #9 双向排版算法(Bidi),支持阿拉伯语形态连接(Connecting Forms)与天城文预基字重排。
4. JS 运行时与 Node 风格原生扩展
脚本引擎:内嵌 QuickJS 核心,开启基线 JIT 与 SLJIT 机器码生成。
模块系统:在 JS 端通过 CommonJS 包装,C 端暴露
fs、path、os、child_process等原生模块,子进程通过非阻塞 Pipe 进行事件调度。WebGL 桥接:完整实现 WebGL 1.0/2.0 基础上下文映射,支持索引绘制与零拷贝纹理直接喂入,可正常驱动 Three.js 核心渲染。
5. 开发者工具与安全性
CDP 调试服务:内置 Chrome DevTools Protocol 独立服务(默认端口 9222),开发者可直接使用 Chrome 浏览器的
chrome://inspect连接调试自研 DOM 树、控制台输出及性能分析。ChaCha20-Poly1305 VFS:支持将前端代码预编译为 QuickJS 字节码,并通过 RFC 8439 加密打包为
app.pak。运行时仅在内存中解密执行,杜绝明文源码泄漏。
项目代码骨架
项目代码遵循纯 C99 规范,无多余外部臃肿依赖:
TinyFramework/ ├── include/ # 模块接口头文件 (mini_dom.h, mini_renderer.h 等) ├── src/ │ ├── main.c # 运行时主循环与生命周期管理 │ ├── mini_renderer.c # 向量命令缓冲与 OpenGL 渲染管线 │ ├── mini_dom.c # DOM 树构建与布局引擎 │ ├── mini_css.c # CSS 解析、变量计算与媒体查询 │ ├── mini_html5.c # WHATWG 规范分词与树构造器 │ └── mini_js_bridge.c # QuickJS 桥接绑定与 WebGL Polyfill ├── libs/ # 第三方微型依赖 (QuickJS, mbedTLS, stb, sljit) ├── CMakeLists.txt # 工程构建配置 └── build.py # 自动化编译与加密打包脚本快速编译与运行验证
1. 克隆与环境准备
支持 C99 的编译器(GCC / Clang / MSVC)
CMake $\ge$ 3.16
GLFW 3.4 动态/静态库
git clone https://github.com/tzdwindows/TinyFramework.git cd TinyFramework2. CMake 编译与测试
# 生成构建工程 (默认开启 JIT、TLS 与 CDP 调试支持) cmake -B build -S . \ -DGLFW_ROOT=/path/to/glfw-3.4 \ -DENABLE_CDP=ON \ -DMINI_JIT=ON \ -DMINI_TLS=ON # 编译生成可执行二进制 cmake --build build --config Release # 运行页面 ./build/tiny_app.exe src/index.html3. 生产加密打包
# 源码转 QuickJS 字节码并经 ChaCha20 加密打包为单文件 python build.py \ --in src/ \ --out dist/ \ --bytecode \ --key 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \ --jit --jit-codegen --upx总结与展望
手写浏览器引擎并不意味着要完全复刻 Chromium 千万行代码的全部复杂特性。针对桌面应用场景,裁剪掉冗余的遗留兼容包袱,聚焦于高效的排版算法、轻量级 JS 虚拟机与精简渲染器,完全可以在4MB的极小空间内实现流畅可靠的 Web 运行时环境。
后续将继续完善 CSS Grid 复杂轨道排版与 WebAudio 规范的对齐,欢迎大家 Star 与提 PR 交流探讨!
项目开源地址:https://github.com/tzdwindows/TinyFramework