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.jsonnpm 等效命令,以及 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,比如 fetchJSONsetTimeout 和事件等。
  • 兼容 Node API,比如 consolehttppath 等,以及全局变量,包括 __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,比如 fspathconsole 等等
  • 全局变量和对象,比如 __dirnameprocess
  • 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" 属性,我们可以在任何文件中无缝切换 importrequire()

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

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

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

Web API

Bun 内置了对浏览器中可用的 Web 标准 API 的支持,比如 fetchJSONsetTimeout 等。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/globalsvitest 导入在内部重新映射到 bun:test,不需要更改代码。

脚本打包

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

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

基准测试表明,Bun 的速度是 Go 编译的 esbuild2 倍,并且具有类似的压缩节省。与 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 点半更新,坚持阅读,自律打卡,每天一次,进步一点

相关推荐
吃杠碰小鸡几秒前
commitlint校验git提交信息
前端
虾球xz31 分钟前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇37 分钟前
HTML常用表格与标签
前端·html
疯狂的沙粒40 分钟前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员1 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐1 小时前
前端图像处理(一)
前端
程序猿阿伟1 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒1 小时前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪1 小时前
AJAX的基本使用
前端·javascript·ajax
力透键背1 小时前
display: none和visibility: hidden的区别
开发语言·前端·javascript