Bun 的 Windows 稳定版即将公布,重温 Bun 运行时

大家好,这里是大家的林语冰。

Bun 是一个新型 JS 运行时,去年就提供了 Windows 实验版。据最新消息,今年最新的 Windows 稳定版即将发布,敬请期待。

本期共享的是 ------ Bun 是 Node 和 Deno 的 JS 运行时竞品。在本文中,我们会科普 Bun 1.0,以及它可能诱使我们放弃当前最爱的 Node 的若干原因。

免责声明

本文属于是语冰的直男翻译了属于是,略有删改,仅供粉丝参考。英文原味版请传送 An Introduction to the Bun JavaScript Runtime。

运行时简史:Bun vs Node vs Deno

"Node 之父" R.D. 于 2009 年发布了 Node。Node 并不是首个服务端 JS 运行时,但 Node 找到了"流量密码"。Node 20 于 2023 年发布,它拥有最大的开发生态系统,拥有 320 万个模块,根据 npmjs.com 的数据,其周下载量高达 5_000 亿次。

2020 年,"Node 之父"发布了 Deno,意思是"noDe"的重新组合,旨在实现 JS 现代化开发,并解决 Node 安全性、API 兼容性、工具和模块管理方面的遗留问题。尽管 Deno 尚未将 Node 拉下神坛,但社区反响还是元气满满。

2022 年,J.S. 在开发 Next 项目时对 Node 的速度感到头大,于是发布了 Bun。

Bun 使用 JSC(JavaScriptCore)引擎,JSC 为苹果 Safari 等 WebKit 浏览器提供支持,而不是 Node、Deno 和谷歌 Chrome 中使用的 V8 引擎。

Bun 运行时注重性能和开发体验,其目的是消除缓慢和复杂性,同时又不放弃 JS 的所有优点。

Bun 的发展速度比 Node 更快 ------ 它必须尽量保持与现有 JS 和 npm 生态系统的向后兼容。

与 Deno 一样,Bun 原生支持 JS/TS,无需第三方转译器或配置。

Bun 正在成为 Node、Deno、无服务器运行时(serverless runtimes)、构建和测试工具的直接替代品。Bun 可以替代 npm、TS 编译器、nodemon、Webpack、Babel 和 Jest,提供完整的功能全家桶 ------ 用于在单一平台上开发 App 的完备工具箱。

Bun 最初的运行时是稳定的,但由于近 300 名开发者的无私贡献,Bun 1.0 版本于 2023 年 9 月发布。这将不可避免地吸引更多开发者迁移到 Bun,在这里它们可以享受下面描述的好处。

Bun 的由来

"Bun"这个名字的由来尚不清楚,而且标志也无济于事!Bun 可能与食物、毛茸茸的小兔子、"bundle"(打包器)有关,或者可能是一个简短、令人难忘的名称,并且 Bun.sh 域名可用。

Bun 的优势

Node 和 Deno 使用谷歌 Chrome 的 V8 JS 引擎。Bun 选择了 JSC 引擎,该引擎为苹果 Safari 等 WebKit 浏览器提供支持。Bun 本身是用 Zig 编写的,Zig 是一种低级编程语言,具有手动内存管理和原生线程来处理并发。结果是轻量级运行时具有更小的内存占用、更快的启动时间,并且在某些基准测试条件下性能比 Node 和 Deno 快 4 倍。

与 Deno 一样,Bun 原生支持 JS/TS,无需第三方转译器或配置。Bun 还支持 .jsx/.tsx 文件,这会将类似 HTML 的标记转换为原生 JS。Bun 提供了对运行 WebAssembly 编译的 .wasm 文件的实验性支持。

Bun 支持 Node 的 package.json、npm 等效命令,以及 Bunx --- 一个类似 npx 的选项,可在单个命令中自动安装和运行包。举个栗子:

bash 复制代码
bunx cowsay "Hello, world!"

bun init 脚手架通过与 npm init 相同的方式构建空项目,但我们也可以使用 bun create <template> <destination> 模板化新项目,其中 <template> 是官方包、Github 存储库或本地包。举个栗子,要创建一个新的 Next 项目:

bash 复制代码
bun create next ./myapp

Bun 包含一个打包器,用于将所有依赖导入到单个文件中,且可以针对 Bun、Node 和客户端 JS。这减少了使用 esbuild 或 Rollup 等工具的需要:

bash 复制代码
bun build ./index.ts ---outdir ./out

大多数命令行界面选项都可以通过 JS API 获得,因此无需专用的任务运行程序就可以创建复杂的构建脚本。这是与上面命令相同的构建:

js 复制代码
await Bun.build({
  entrypoints: ['./index.ts'],
  outdir: './out'
})

项目 .env 文件中包含的环境变量会自动加载和解析,使其在 Bun App 中可用,因此无需使用 dotenv 等包。

除了 Bun 自己用于网络、文件访问、子进程等的 Bun API 之外,Bun 还支持:

  • Web API,比如 fetch、JSON、setTimeout 和事件等。
  • 兼容 Node API,比如 console、http、path 等,以及全局变量,包括 __dirname 和 __filename 。Bun 声称 90% 最常用的 API 都已完全实现,尽管我们应该仔细检查特定于自己项目的 API。

安装 Bun

Bun 可以通过 Node 包管理器安装:

bash 复制代码
npm install -g bun

安装后,我们可以使用以下命令升级 Bun:

bash 复制代码
bun upgrade

或者可以通过删除 ~/.bun 二进制文件和缓存目录来卸载 Bun:

bash 复制代码
rm -rf ~/.bun

然后更新 shell 配置文件(.bashrc 或类似文件),以从 $PATH 变量中删除 ~/.bun/bin 引用。

使用 Bun

如果我们从项目起步就使用 Bun,那么 Bun 是可靠的。速度比 Node 更快,但除非我们的 App 正在执行特定的密集型任务,比如繁重的 SQLite 处理或 WebSocket 消息传递,否则我们不太可能感知到性能的显著提升。

Node 的兼容性对于更短小精悍的项目好处多多,我成功地使用 bun start 启动了某些脚本,且无需进行任何更改。更复杂的 App 可能"试试就逝世",并在 node_modules 层次结构深处生成了模糊的错误消息。

Bun vs Deno vs Node

Deno 解决了 Node 的许多缺陷,但开发者不一定觉得有必要切换到 Deno:

  • Deno 不支持 Node 的第三方模块。
  • 从 Node 迁移到 Deno 需要学习成本。
  • 虽然 Deno 提供了更好的开发体验,但 Node 也差强人意。

Deno 现在添加了 Node 兼容性选项。这是让开发者过渡到 Deno 的最简单方案,但与此同时,Node 采用了 Deno 的某些功能,包括 ESM 模块、原生测试运行器和 ---watch 模式。

Bun 采取了不同的方案,旨在成为一个比肩 Deno、与 Node 兼容的快速引擎。理想很丰满,但还没有实现:

  • 性能爆棚,但很少有开发者抱怨 Node 的速度。
  • 兼容性很好,但在不同的 JS 引擎中支持所有 Node 模块是一个挑战。JSC 能否以更少的投资跟上 V8 的发展?
  • Bun 有潜力取代我们的工具套件,但它尚未提供 Deno 中的全部功能。

Bun 与 Node 的兼容性

Node 兼容性通常适合短小精悍的项目。我们也许可以使用 bun start 而不是 npm start 来启动某些脚本,而无需进行任何更改。

Bun 支持:

  • 内置 Node 模块和 API,比如 fs、path、console 等等
  • 全局变量和对象,比如 __dirname 和 process
  • Node 模块解析算法来定位 node_modules 中的文件

Bun 1.0 声称可以运行"几乎任何 Node App"。我信你个大头鬼;复杂的 App 可能遭遇滑铁卢,并在第三方模块深处生成模糊的错误消息。

ESM 和 CJS 模块兼容性

Bun 支持具有顶层 await 的 ESM 和 CJS 模块系统。ESM 花了几年时间才进入 Node,并且生态系统仍然由 CJS 主导。使用 Bun,不需要特定的文件扩展名,比如 .js/.cjs/.mjs,或者在 package.json 中配置 "type": "module" 属性,我们可以在任何文件中无缝切换 import 或 require()!

在内部,Bun 将所有模块翻译为 CJS 并实现 Node 的 node_modules 解析算法。这是否能如期工作是另一回事:

  • ESM 模块经过预解析,以便在执行代码之前解决进一步的导入问题。动态导入是可能的,但只能被视为最后的手段。
  • CJS 模块在执行代码时按需加载依赖。动态导入的问题较少。

执行顺序在某些 App 中兹事体大,这就是 Node 限制我们在单个文件中使用 ESM 或 CJS 的原因。

Web API

Bun 内置了对浏览器中可用的 Web 标准 API 的支持,比如 fetch、JSON 和 setTimeout 等。Deno 将这些 API 引入其服务器运行时,使 Web 编码更加一致。Node 正在迎头赶上,但诸如 fetch 等功能最近才在 Node 18 中推出。

Bun API

Bun 附带了高度优化的标准 API,用于常见操作,比如文件读取、文件写入、HTTP 服务、SQLite 查询和密码哈希。

WebSocket 与 HTTP 同时支持,无需 ws 等第三方模块:

js 复制代码
Bun.serve({
  port: 8000,
  fetch(request) {
    return new Response('Hello from the Bun server!');
  },
  websocket: {
    open(ws) { ... },
    message(ws, data) { ... },
    close(ws, code, reason) { ... },
  }
});

TS 和 JSX 支持

与 Deno 一样,Bun 也有一个内置于运行时的 JS 转译器。我们可以运行 JS、TS、JSX 或 TSX 文件,而无需第三方依赖项。举个栗子:

bash 复制代码
bun index.ts
bun index.jsx
bun index.tsx

包管理器

我们可以在任意 Node 项目中直接使用 Bun 作为 npm 替代品。举个栗子:

bash 复制代码
bun install
bun add <package> [--dev|--production|--peer]
bun remove <package>
bun update <package>

Bun 将模块缓存在 ~/.bun/install/cache/ 中,并使用硬链接将它们拷贝到项目的 node_modules 目录中。因此,系统上的所有项目都引用同一库的单个实例。这可以减少磁盘空间,并将安装性能提高 30 倍。

实时重载

我们不需要类似 nodemon 的工具,因为 bun 可执行文件具有 -watch 标志,可以在修改文件时重启脚本或测试。

我们可以使用类似的 ---hot 模式,Bun 会监视更改,并软重载模块。所有文件都会重新评估,但全局状态仍然存在。

测试

Bun 提供了一个与 Jest 兼容的 bun:test 测试运行器,支持快照测试、模拟和代码覆盖率。举个栗子:

js 复制代码
import { test, expect } from 'bun:test'

test('2 + 2', () => {
  expect(2 + 2).toBe(4)
})

从 Jest 或 Vitest 迁移很简单,因为从 @jest/globals 或 vitest 导入在内部重新映射到 bun:test,不需要更改代码。

脚本打包

Bun 是一个 JS/TS 打包器和压缩器,可以针对浏览器、Node 和其他平台的代码。Bun 受到 esbuild 的启发,并提供了兼容的插件 API:

js 复制代码
// 简单构建
Bun.build({
  entrypoints: ['index.js'],
  outdir: 'build'
})

基准测试表明,Bun 的速度是 Go 编译的 esbuild 的 2 倍,并且具有类似的压缩节省。与 esbuild 不同,Bun 不支持 CSS 打包,但考虑到有一个通用的插件 API,这可能会实现。

启动和执行速度

使用 bun run <script> 而不是 npm run <script> 通常会比 npm run <script> 启动 App 快 150 毫秒。这可能是一个小改进,但速度比 Node 快 4 倍,并且在运行许多命令和构建脚本时会很明显。使用 TS 时性能提升会更大,因为没有转译步骤。

Windows 实验性版本

Bun 的原生版本很快就会推出适用于 Windows 的版本,目前它是高度实验性的,能且仅能支持 JS 运行时,没有进行性能优化。包管理器、测试运行器和打包器等功能均被禁用,直到它们稳定为止。

目前,Windows 用户可以在适用于 Linux 的 Windows 子系统上安装 Bun ------ 如果您正在执行任何繁重的 JS 工作,这仍然是最佳选择。

高潮总结

Bun 是一个成熟的 JS 运行时,但 Node 仍然是关键任务项目或遗留 App 的冠军。我们应该尝试使用 bun start 运行 App,但是我们的代码库越大,它在无需修改的情况下顺利执行的机会就越小。

对于新项目而言,Deno 可能是比 Bun 更好的选择,因为它更成熟且功能更完整。

Bun 很棒,并且正在积极开发,但它初出茅庐。运行时是稳定的,但现阶段很少有人会押注它的长期未来。

Deno 最初朝着自己的方向发展,但不得不后退。对于许多 Node 开发者而言,Deno 过于激进且不兼容。

Bun 从一开始就提供了兼容性和速度 ------ 鉴于 Bun 使用不同的 JS 引擎,这是一项相当大的成就。Bun 是否能实现接近 100% 的 Node 兼容性还有待观察,但我们可以将其视为遗留项目中某些工具集的直接替代品。

Bun 声称的速度令人印象深刻,但很少有人抱怨 Node 的原始性能,尤其是当 Node 随着每个版本的发布而改进时。有些框架很慢,但这通常是由于膨胀而不是运行时的固有错误。

目前,Node 仍然是无可争议的 JS 运行时霸主。很少有人会因为选择 Node 而被解雇,但 Bun 避免了 Deno 的一些失误,并迅速成为一个有吸引力的选择。

本期话题是 ------ 你开始体验 Bun 了吗?

欢迎在本文下方自由言论,文明共享。谢谢大家的点赞,掰掰~

《前端猫猫教》每日 9 点半更新,坚持阅读,自律打卡,每天一次,进步一点。

相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋4 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁4 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄4 天前
JavaScript 隐式全局变量解析
javascript
汉堡大王95274 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大4 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师4 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端