大家好,这里是大家的林语冰。
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 点半更新,坚持阅读,自律打卡,每天一次,进步一点。