为什么 Bun 会成为 Node.js 的热门替代品?

发表时间: 2023-10-27 20:20

2022年,不经意发现,广场、公园、球场、甚至小区空地上空,都有飞盘飞舞。似乎一夜之间,飞盘成了年轻人的“时尚新宠”。

2023年4月,万万没想到,一座小城突然杀出了重围,谁能想到,每个城市随处可见的烧烤,让淄博这座小城,彻底火了。

2022年7月,Bun v0.1.1发布,随即 Star数成指数级增长,成为年度最火的前端项目。随着2023年9月 v1.0版本的发布,Bun彻底火爆,被前端开发者圈粉。

Bun为什么会火?能持续多久?是否持续被开发者所喜爱?

1.Bun 为什么会火?

引用官方的解释:

Bun is a fast, all-in-one toolkit for running, building, testing, and debugging JavaScript and TypeScript, from a single file to a full-stack application.

Bun 是一个快速的全能工具包,用于运行、构建、测试和调试 JavaScript 和 TypeScript(从单个文件到全栈应用程序)。Bun 的核心是一个快速的 JavaScript 运行时,旨在取代 Node.js。它是用 Zig 语言编写的,并在底层由 JavaScriptCore 提供支持,大大减少了启动时间和内存使用。

2.Bun 为什么会出现?

Javascript 是一个成熟且发展迅速,被广大开发者所喜爱,其开发者社区充满活力和激情。然而,自从 14 年前 Node.js 首次亮相以来,Javascript 的工具链变得臃肿和复杂。就像任何系统在没有集中规划的情况下成长和发展一样,JavaScript 工具变得缓慢而复杂。

Bun 的目标很简单,就是要消除JavaScript工具链的缓慢和复杂性,但同时保留JavaScript本身的优点。Bun希望让开发者继续使用喜欢的库和框架,并且无需放弃已经熟悉的规范和约定。

然而,你需要忘记很多工具,因为这些工具是 Bun 没有必要使用的:

  • Node.js:Bun 可直接替代 Node.js,因此您无需使用它:
  • node
  • npx:Bun 的 bunx 命令比 npx 快5倍。
  • nodemon:Bun 内置了监听模式。
  • dotenvcross-env:Bun 默认支持读取.env文件的配置。
  • Transpilers:Bun 可以运行 .js.ts.cjs.mjs.jsx.tsx文件,不再需要以下工具:
  • tsc(但你可以保留它以进行类型检查!)
  • babel.babelrc@babel/preset-*
  • ts-nodets-node-esm
  • tsx
  • Bundlers:Bun 是一个 JavaScript 打包器,具有一流的性能和与 esbuild 兼容的插件 API,不再需要以下工具:
  • esbuild
  • webpack
  • parcel, .parcelrc
  • rollup, rollup.config.js
  • Package managers:Bun 是一款与 npm 兼容的软件包管理器,使用熟悉的命令。它能读取你的 package.json,并写入 node_modules,就像其他软件包管理器一样,你可以替换如下工具:
  • npm, .npmrc, package-lock.json
  • yarn, yarn.lock
  • pnpm, pnpm.lock, pnpm-workspace.yaml
  • lerna
  • Testing libraries:Bun 是一个兼容 Jest 的测试运行器,支持快照测试、模拟和代码覆盖,因此您不再需要以下工具:
  • jest, jest.config.js
  • ts-jest, @swc/jest, babel-jest
  • jest-extended
  • vitest, vitest.config.ts

虽然这些工具各有千秋(大部分情况下),但同时使用它们不可避免地会造成脆弱性和缓慢的开发体验。它们会执行大量冗余工作;当你运行 jest 时,你的代码会被各种工具解析 3 次以上!而且,将所有工具拼接在一起所需的胶带、插件和适配器最终总会磨损。

Bun 是一个单一的集成工具包,可以避免这些集成问题。从性能到 API 设计,该工具包中的每个工具都能为开发人员提供一流的体验。

3.Bun 的运行时环境?

Bun 是一种快速 JavaScript 运行时。它的目标是让构建软件的体验更快、更省力、更有趣。

3.1.与Node.js兼容

Bun 是可以直接替代 Node.js 的。这意味着现有的 Node.js 应用和 npm 包可以在 Bun 中正常工作。Bun 内置了对 Node.js API 的支持,包括:

Bun 可以直接替代 Node.js。这意味着现有的 Node.js 应用程序和 npm 包可以在 Bun 中正常运行。Bun 内置支持 Node API,包括

  • 内置模块,如 fspathnet
  • 全局对象,如 __dirnameprocess
  • Node.js 模块解析算法(例如node_modules)

尽管与 Node.js 完全兼容是不可能的,特别是一些依赖于v8版本的特性,但 Bun 几乎可以运行任何现有的 Node.js 应用

Bun经过了与最受欢迎的Node.js包的兼容性测试,支持与Express、Koa、Hapi等服务端框架以及其他流行的全栈框架的无缝集成。开发者可以放心地在Bun中使用这些库和框架,并享受到更好的开发体验。

使用Next.js、Remix、Nuxt、Astro、SvelteKit、Nest、SolidStart和Vite构建的全栈应用可以在Bun中运行。

3.2.速度

Bun的速度非常快,启动速度比 Node.js 快 4 倍。当运行TypeScript文件时,这种差异会更加明显,因为在Node.js中运行TypeScript文件需要先进行转译才能运行。

与使用 Google V8 引擎构建的 Node.js 和其他运行时不同,Bun 是使用 Apple 的 WebKit 引擎构建的。WebKit 是为 Safari 提供动力的引擎,每天有数十亿台设备在使用它。它速度快、效率高,经历过数十年的实战检验。

3.3.TypeScript 和 JSX 支持

Bun内置了JavaScript转译器,因此可以运行JavaScript、TypeScript甚至JSX/TSX文件,无需任何依赖。

// 运行 TS 文件bun index.ts// 运行 JSX/TSX 文件bun index.tsx

3.4.ESM 和 CommonJS 兼容

从 CommonJS 到 ES 模块的过渡缓慢而充满恐惧。在引入 ESM 之后,Node.js 花了 5 年时间才在没有 --experimental-modules 标志的情况下支持它。无论如何,生态系统中仍然充满了 CommonJS。

Bun 可同时支持两种模块系统。无需担心文件扩展名 .js vs .cjs vs .mjs,也无需在 package.json 中包含 "type": "module"

你甚至可以在同一个文件中使用 importrequire() 来导入文件,它可以正常工作。

import lodash from "lodash";const _ = require("underscore");

3.5.Web API

Bun 内置支持浏览器中可用的Web标准API,如 fetchRequestResponseWebSocketReadableStream等。

const response = await fetch("https://example.com/");const text = await response.text();

开发者不再需要安装像 node-fetchws 这样的包。Bun 内置的 Web API 是使用原生代码实现的,比第三方替代方案更快速和可靠。

3.6.热重载

作为一名开发人员,Bun 能让你更轻松地提高工作效率。在运行 Bun 时,你可以使用 --hot 来启用热重载,当文件发生变化时,它会重新加载你的应用程序。

bun --hot server.ts

与硬重启整个进程的工具(如 nodemon)不同,Bun 会在不终止旧进程的情况下重新加载代码。这意味着 HTTP 和 WebSocket 连接不会断开,状态也不会丢失。

3.7.插件

Bun 被设计为高度可定制的。

您可以定义插件来拦截导入并执行自定义加载逻辑。插件可以添加对其他文件类型的支持,如 .yaml.png。Plugin API 的灵感来自 esbuild,这意味着大多数 esbuild 插件都能在 Bun 中运行。

import { plugin } from "bun";plugin({  name: "YAML",  async setup(build) {    const { load } = await import("js-yaml");    const { readFileSync } = await import("fs");    build.onLoad({ filter: /.(yaml|yml)$/ }, (args) => {      const text = readFileSync(args.path, "utf8");      const exports = load(text) as Record<string, any>;      return { exports, loader: "object" };    });  },});

4.Bun 是一个包管理器

即使你不把 Bun 用作运行时,Bun 内置的软件包管理器也能加快你的开发工作流程。再也不用盯着 npm 旋转器安装你的依赖项了。

Bun 看起来和你习惯的软件包管理器没什么两样。

bun installbun add <package> [--dev|--production|--peer]bun remove <package>bun update <package>
  1. 安装速度

Bun的安装速度比 npmyarnpnpm 快好几个数量级。它使用全局模块缓存,以避免从 npm 注册表进行冗余下载,并使用每个操作系统上可用的最快系统调用

  1. 运行脚本

很有可能,您已经有一段时间没有直接使用 node 运行脚本了。相反,我们经常使用包管理器与框架和 CLI 接口来构建应用程序。

npm run dev

可以用 bun run 来替换 npm run,每次运行命令都能节省 150 毫秒的时间。

这些数字可能看起来很小,但在运行命令行界面(CLI)时,感知上的差异是巨大的。使用 npm run 会明显感到延迟:

而使用bun run则感觉几乎瞬间完成:

并不只是针对npm进行比较。实际上,bun run <command> 的速度比 yarnpnpm 中相应的命令更快。

Script runner Avg. time npm run 176ms yarn run 131ms pnpm run 259ms bun run 7ms

如果你以前在 JavaScript 中写过测试,可能了解 Jest,它开创了“expect”风格的API。

5.Bun 是一个测试运行器

Bun有一个内置的测试模块 bun:test,它与Jest完全兼容。

import { test, expect } from "bun:test";test("2 + 2", () => {  expect(2 + 2).toBe(4);});

可以使用bun test命令来运行测试:

bun test

将会获得 Bun 运行时的所有优势,包括TypeScript和JSX支持。

从 Jest 或 Vitest 迁移非常简单。任何从 @jest/globals 或 Vitest 导入的内容都将在内部重新映射到 bun:test,因此即使不修改代码,一切也能正常工作。

import { test } from "@jest/globals";describe("test suite", () => {  // ...});

在与 zod 的测试套件进行基准测试中,Bun比Jest快13倍,比Vite快8倍。

6.Bun 是一个构建工具

Bun是一个JavaScript和TypeScript的构建工具和代码压缩工具,可用于将代码打包成适用于浏览器、Node.js和其他平台的形式。

bun build ./index.tsx --outdir ./build

Bun 受到了 esbuild 的启发,并提供了兼容的插件API。

import mdx from "@mdx-js/esbuild";Bun.build({  entrypoints: ["index.tsx"],  outdir: "build",  plugins: [mdx()],});

Bun 的插件 API 是通用的,这意味着它适用于打包工具和运行时。所以前面提到的.yaml插件可以在这里使用,以支持在打包过程中导入.yaml文件。

根据esbuild的基准测试,Bun比esbuild快1.75倍,比Parcel 2快150倍,比Rollup + Terser快180倍,比Webpack快220倍。

由于Bun的运行时和打包工具是集成在一起的,这意味着Bun可以做其他打包工具无法做到的事情。

Bun引入了JavaScript宏机制,可以在打包时运行JavaScript函数。这些函数返回的值会直接内联到打包文件中。

// release.tsexport async function getRelease(): Promise<string> {  const response = await fetch(    "https://api.github.com/repos/oven-sh/bun/releases/latest"  );  const { tag_name } = await response.json();  return tag_name;}// index.tsimport { getRelease } from "./release.ts" with { type: "macro" };// release的值是在打包时进行评估的,并且内联到打包文件中,而不是在运行时执行。const release = await getRelease();bun build index.ts// index.tsvar release = await "bun-v1.0.0";

7.Bun 可以做更多的事

Bun 为 macOS 和 Linux 提供原生构建,但有一个明显的缺失:Windows以前,要在 Windows 上运行 Bun,在 Windows 上运行 Bun 需要安装 Windows 子系统来运行Linux系统,但现在不用了。

Bun 首次发布了一个实验性的、专为Windows平台的本地版本的 Bun。这意味着Windows用户现在可以直接在其操作系统上使用 Bun,而无需额外的配置。

尽管Bun的macOS和Linux版本已经可以用于生产环境,但Windows版本目前仍然处于高度实验阶段。目前只支持JavaScript运行时,而包管理器、测试运行器和打包工具在稳定性更高之前都将被禁用。性能方面也还未进行优化。

8.未来已来

Bun 1.0 只是一个开始。Bun 团队正在开发一种全新的部署JavaScript和TypeScript到生产环境的方式,让我们一起期待 Bun 的未来有更好的表现,被更多的开发者所喜爱!

关注「FED实验室」获取更多前端热点资讯、工程架构、技术实践、工具资源、岗位招聘等内容。