JavaScript 运行时 Bun 发布了 1.3.12 版本。这次更新的分量远超一般的补丁发布——内置无头浏览器自动化、终端 Markdown 渲染、原生进程内 Cron 调度、JavaScriptCore 引擎大幅升级……Bun 团队用一个小版本号,塞进了足以撑起多个独立项目的功能密度。
最抢眼的新特性:Bun 现在自带浏览器了
毫无疑问,本次更新最引人注目的特性是 Bun.WebView——一个直接内置于运行时的无头浏览器自动化 API。过去,JavaScript 开发者要做浏览器自动化,必须引入 Playwright 或 Puppeteer,它们背后往往需要下载独立的浏览器二进制文件,初始化时间长、依赖链重。Bun 的做法更为激进:直接在运行时层面提供两套后端,在 macOS 上默认使用系统内置的 WKWebView,无需任何外部依赖;在跨平台场景下则通过 Chrome DevTools Protocol 对接本地已安装的 Chrome 或 Chromium。
更值得关注的是其交互层的设计哲学。所有输入事件——点击、滚动、键盘输入——均以操作系统级别的原生事件分发,isTrusted 属性为 true,网页无法通过 JavaScript 检测出这是自动化操作还是真人行为。选择器方法则采用 Playwright 风格的“可操作性等待”机制:元素必须已挂载、可见、静止且未被遮挡,动作才会触发,省去了开发者手动编写等待逻辑的繁琐。此外,Bun.WebView 实现了 EventTarget 接口,CDP 事件可以像普通 DOM 事件一样监听,API 设计保持了 Bun 一贯的现代感。
终端里的 Markdown 渲染:直接运行 .md 文件
本次更新还带来了一个颇具实用价值的特性:直接运行 bun ./file.md,终端将输出经过 ANSI 着色、格式化的 Markdown 渲染结果,且没有 JavaScript VM 启动开销。这背后还附带了一套编程式 API Bun.markdown.ansi(),支持关闭颜色输出、启用可点击超链接、自定义行宽,以及通过 Kitty 图形协议在兼容终端中渲染内联图片。
Bun.cron():告别第三方依赖的定时任务
Bun.cron() 在本次更新中新增了进程内回调重载,允许开发者直接在应用进程内注册定时任务,共享数据库连接池、缓存和模块状态,无需借助 node-cron 等第三方库。其设计细节体现了相当的工程成熟度:任务不会并发堆叠——只有上一次执行(包括异步操作)完成后,下一次才会调度;时间以 UTC 为准,避免时区陷阱;支持 using 语法自动清理;热重载(--hot)时旧任务自动清除,不会泄漏定时器。这些设计决策表明 Bun 团队在构建这个特性时,充分考虑了生产环境的实际痛点。
JavaScriptCore 引擎:1650+ 提交的技术红利
Bun 底层的 JavaScriptCore 引擎(来自 WebKit)此次一口气合入了超过 1650 个上游提交。其中最值得关注的是对 TC39“显式资源管理”提案的原生支持——using 和 await using 声明现在可以在 JavaScriptCore 中直接运行,无需转译。
性能层面的改进也不是泛泛而谈。JIT 编译器的“快速升级”机制让稳定函数能更早进入优化编译;Array.isArray 成为 JIT 内建函数;String#includes 对单字符搜索引入快速路径;Promise 解析链路得到微优化,新增了 PerformPromiseThen DFG/FTL 优化节点。WebAssembly 方面,SIMD shuffle 优化和 ARM64/x64 额外指令支持同步落地。
URLPattern.test() 和 URLPattern.exec() 的速度提升尤为直观——通过让内部正则匹配直接调用已编译的正则引擎,跳过为每个 URL 组件分配临时 JavaScript 对象的过程,单次调用消除了最多 24 次 GC 分配,test() 方法在多个场景下实现了 1.7 倍到 2.3 倍的性能提升。
一系列务实的基础设施改进
除了面向用户的新特性,本次更新也在基础设施层面做了大量扎实的工作。Linux 上的独立可执行文件构建(bun build --compile)从使用 /proc/self/exe 改为嵌入 ELF 专用节(.bun),启动时零文件 I/O,且不再要求二进制文件具备读权限,chmod 111 场景下也能正常运行。
网络层面,HTTPS 代理的 CONNECT 隧道现在支持复用,不再为每个请求重新握手,显著降低了通过代理发送多个 HTTPS 请求的延迟。Bun.serve() 在 Linux 上启用了 TCP_DEFER_ACCEPT,与 nginx 采用相同的优化策略——内核等到客户端实际发送数据后再触发 accept,将两次事件循环唤醒合并为一次。
Bun.Glob.scan() 对 **/X/... 边界模式消除了重复目录读取,深层目录树下速度最高翻倍;Windows 上还将通配符过滤下推到内核层(NtQueryDirectoryFile),不匹配的条目在进入用户空间前即被丢弃,简单模式最快提升 2.4 倍。容器环境下,availableParallelism 和 hardwareConcurrency 现在能正确读取 cgroup 的 CPU 配额,而非盲目报告宿主机的全部核心数。
值得关注的 bug 修复
本次修复涵盖范围较广,其中几处影响较大:一个导致 Bun.serve() 并发吞吐从约 19 万 req/s 骤降至约 2.2 万 req/s 的 cork 缓冲区争用问题被修复;一个在 ARM64 平台(Apple Silicon、ARM Linux)上可能导致文件 I/O、加密操作及包管理器无限挂起的线程池唤醒竞争问题被修复;HTTP 服务器现在正确拒绝含有冲突重复 Content-Length 头的请求,防范请求走私攻击;Windows 上的 tar 解压路径穿越漏洞得到修补。
MySQL 适配器修复了对 StarRocks、TiDB、SingleStore 等兼容数据库返回空结果的问题,并堵上了多处导致内存无限增长直至 OOM 的原生内存泄漏。此外,一个涉及 bun install 在某些私有 registry 场景下偶发的证书验证问题也已完成补丁。
不过在 Windows 平台上,一个困扰多方的 bin 脚本映射问题(#22422)目前仍未完全解决——带有 #!/usr/bin/env -S 这类复杂 shebang 的包在安装后无法正确生成可执行入口,报出 interpreter executable "-S" not found 错误。该问题的影响范围随生态中采用 env -S 模式的包数量增加而持续扩大,除早期报告的 quartz、MikroORM、react-email 外,近期也波及了 Google 的 Gemini CLI 等工具。考虑到 Anthropic 已将 Bun 深度集成进 Claude Code 开发栈,而 Gemini CLI 恰为直接竞品,这一遗留问题在微妙的时间节点上,显得颇耐人寻味。
结语
Bun v1.3.12 在新特性、引擎升级与 bug 修复三条线上同步推进,展示了这个运行时项目当前的迭代节奏。内置浏览器自动化和 Markdown 渲染等特性,在传统 Node.js 生态中向来属于第三方库的领地;而大量的性能优化和 bug 修复表明团队并未只顾添砖加瓦,地基同样在被持续夯实。对于一个仍在快速演进中的全栈 JavaScript 运行时而言,能在保持高速功能输出的同时将稳定性推到当前水位,本身就是一个值得关注的技术信号。