查看原文
其他

Bun 1.0 正式发布,爆火的前端运行时,速度遥遥领先!

CUGGZ 前端充电宝 2023-10-06

9 月 8 日,前端运行时 Bun 1.0 正式发布,如今,Bun 已经稳定并且适用于生产环境。Bun 不仅是一个专注性能与开发者体验的全新 JavaScript 运行时,还是一个快速的、全能的工具包,可用于运行、构建、测试和调试JavaScript和TypeScript代码,无论是单个文件还是完整的全栈应用。

2022 年 7 月,Bun 发布,随即爆火,成为年度最火的前端项目:
Bun 的流行程度伴随着在去年夏天发布的第一个 Beta 版而爆炸性增长:仅一个月内,就在 GitHub 上获得了超过两万颗 Star。

Bun 不仅仅是一个运行时。它也是:

  • 一个包管理器 (类似 Yarn、 NPM、 PNPM)

  • 一个构建工具 (类似 Webpack、 ESBuild、 Parcel)

  • 一个测试运行器

  • ...

所以 Bun 可以通过读取 package.json 来安装依赖项。Bun 还可以运行脚本。不管它做什么都比其他工具更快。Bun 在 JavaScript 生态系统的许多方面都有新的尝试,其中的重点是性能。它优先支持标准的 Web API,如 Fetch。它也支持许多 Node.js APIs,使其能与大多数 NPM 包兼容。

安装 Bun:

// npm
npm install -g bun

// brew
brew tap oven-sh/bun
brew install bun

// curl
curl -fsSL https://bun.sh/install | bash

// docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun

更新 Bun:

bun upgrade

下面就来看看 Bun 是什么,1.0 版本带来了哪些更新!

Bun:全能的工具包

JavaScript 成熟、发展迅速,并且有着充满活力和激情的开发者社区。然而,自14年前Node.js发布以来,JavaScript 的工具链变得越来越庞大和复杂。这是因为在发展过程中,各种工具被逐渐添加进来,但没有一个统一的集中规划,导致工具链缺乏整体性和效率,变得运行缓慢和复杂。

Bun 为什么会出现?

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

为了实现这个目标,可能需要放弃一些在使用Bun之后变得不再必要的工具:

  • Node.js:Bun 的一个可以直接替代的工具,因此不再需要以下工具:

    • node

    • npx:Bun 的 bunx 命令比 npx 快5倍。

    • nodemon:Bun 内置了监听模式,无需使用 nodemon

    • dotenvcross-env:Bun 默认支持读取.env文件的配置。

  • 转译器:Bun 可以运行.js.ts、``.cjs.mjs.jsx.tsx文件,因此不再需要以下工具:

    • tsc:仍然可以保留它用于类型检查!

    • babel.babelrc@babel/preset-*:不再需要使用 Babel 进行转译。

    • ts-nodets-node-esm:Bun 可以直接运行 TypeScript 文件。

    • tsx:Bun可以直接运行 TypeScript 的 JSX 文件。

  • 构建工具:Bun 具有一流的性能和与esbuild兼容的插件API,因此不再需要以下工具:

    • esbuild

    • webpack

    • parcel, .parcelrc

    • rollup, rollup.config.js

  • 包管理器:Bun 是一个与 npm 兼容的包管理器,可以使用熟悉的命令。它可以读取 package.json文件并将依赖写入node_modules目录,与其他包管理器的行为类似,因此可以替换以下工具:

    • npm, .npmrc, package-lock.json

    • yarn,yarn.lock

    • pnpm, pnpm.lock, pnpm-workspace.yaml

    • lern

  • 测试库:Bun是一个支持Jest的测试运行器,具有快照测试、模拟和代码覆盖率等功能,因此不再需要以下测试相关的工具:

    • jest, jest.config.js

    • ts-jest, @swc/jest, babel-jest

    • jest-extended

    • vitest, vitest.config.ts

尽管这些工具都有自己的优点,但使用它们时往往需要将它们全部集成在一起,这会导致开发过程变得缓慢和复杂。而Bun通过成为一个单一的工具包,提供了最佳的开发者体验,从性能到API设计都力求做到最好。

Bun:JavaScript 运行时

Bun是一个快速的JavaScript运行时。旨在提供出色的性能和开发体验。它的设计旨在解决开发过程中的各种痛点,使开发者的工作更加轻松和愉快。

与Node.js兼容

Bun 是可以直接替代 Node.js 的。这意味着现有的 Node.js 应用和 npm 包可以在 Bun 中正常工作。Bun 内置了对 Node.js 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中运行。

速度

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

Bun在运行一个简单的"Hello World" TypeScript文件时,比在Node.js中使用esbuild运行速度快5倍。

Bun使用的是Apple的WebKit引擎,而不是像Node.js和其他运行时一样使用Google的V8引擎。WebKit引擎是Safari浏览器的核心引擎,每天被数十亿的设备使用。它经过了长时间的实际应用和测试,具备快速和高效的特性。

TypeScript 和 JSX 支持

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

// 运行 TS 文件
bun index.ts

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

ESM 和 CommonJS 兼容

从CommonJS到ES模块的过渡一直是缓慢而充满挑战的。在引入ESM之后,Node.js花了5年时间才在没有--experimental-modules标志的情况下支持它。尽管如此,生态系统仍然充斥着CommonJS。

Bun 同时支持这两种模块系统。无论是使用CommonJS的.js扩展名、.cjs扩展名,还是使用ES模块的.mjs扩展名,Bun都会进行正确的解析和执行,而无需额外的配置。

甚至可以在同一个文件中同时使用importrequire()

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

Web API

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

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

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

热重载

Bun提供了热重载功能,可以在开发过程中实现文件的自动重新加载。只需在运行Bun时加上--hot参数,当文件发生变化时,Bun 就会自动重新加载你的应用,从而提高开发效率。

bun --hot server.ts

与像nodemon这样完全重新启动整个进程的工具不同,Bun 在重新加载代码时不会终止旧进程。这意味着HTTP和WebSocket连接不会断开,并且状态不会丢失。

插件

Bun 被设计为高度可定制的。 可以定义插件来拦截导入操作并执行自定义的加载逻辑。插件可以添加对其他文件类型的支持,比如.yaml.png。插件API的设计灵感来自于esbuild,这意味着大多数esbuild插件在 sBun 中也可以正常工作。

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" };
});
},
});

Bun API

Bun内部提供了针对开发者最常用需求的标准库API,并对其进行了高度优化。与Node.js的API不同,Node.js的API存在着向后兼容的考虑,而Bun的原生API则专注于提供更快速和更易于使用的功能。

Bun.file()

使用Bun.file()可以懒加载位于特定路径的文件。

const file = Bun.file("package.json");
const contents = await file.text();

它返回一个扩展了 Web 标准FileBunFile对象。文件内容可以以多种格式进行懒加载。

Bun.serve({
port: 3000,
fetch(request) {
return new Response("Hello from Bun!");
},
});

Bun每秒可以处理的请求比 Node.js 多 4 倍。

也可以使用tls选项来配置TLS(传输层安全协议)。

Bun.serve({
port: 3000,
fetch(request) {
return new Response("Hello from Bun!");
},
tls: {
key: Bun.file("/path/to/key.pem"),
cert: Bun.file("/path/to/cert.pem"),
}
});

Bun内置了对WebSocket的支持,只需要在websocket中定义一个事件处理程序来实现同时支持HTTP和WebSocket。而Node.js没有提供内置的WebSocket API,所以需要使用第三方依赖库(例如ws)来实现WebSocket的支持。因此,使用Bun可以更加方便和简单地实现WebSocket功能。

Bun.serve({
fetch() { ... },
websocket: {
open(ws) { ... },
message(ws, data) { ... },
close(ws, code, reason) { ... },
},
});

Bun 每秒可以处理的消息比在 Node.js 上使用 ws 库多 5 倍。

bun:sqlite

Bun内置了对 SQLite 的支持。它提供了一个受到better-sqlite3启发的API,但是使用本地代码编写,以达到更快的执行速度。

import { Database } from "bun:sqlite";

const db = new Database(":memory:");
const query = db.query("select 'Bun' as runtime;");
query.get(); // => { runtime: "Bun" }

在 Node.js 上,Bun 执行 SQLite 查询操作的速度比better-sqlite3快 4 倍。

Bun.password

Bun 还支持一些常见但复杂的API,不用自己去实现它们。

例如,可以使用Bun.password来使用bcryptargon2算法进行密码哈希和验证,无需外部依赖。

const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password);
// => $argon2id$v=19$m=65536,t=2,p=1$tFq+9AVr1bfPxQdh...

const isMatch = await Bun.password.verify(password, hash);
// => true

Bun:包管理器

Bun是一个包管理器。即使不使用Bun作为运行时环境,它内置的包管理器也可以加速开发流程。以前在安装依赖项时需要盯着npm的加载动画,现在可以通过Bun的包管理器更高效地进行依赖项的安装。

Bun可能看起来像你熟悉的包管理器:

bun install
bun add <package> [--dev|--production|--peer]
bun remove <package>
bun update <package>

安装速度

Bun的安装速度比 npm、yarn 和 pnpm 快好几个数量级。它利用全局模块缓存来避免从npm注册表中重复下载,并使用每个操作系统上最快速的系统调用。

运行脚本

很可能你已经有一段时间没有直接使用 Node 来运行脚本了。相反,通常使用包管理器(如npm、yarn等)与框架和命令行界面(CLI)进行交互,以构建应用。

npm run dev

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

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

而使用bun run则感觉几乎瞬间完成:
并不只是针对npm进行比较。实际上,bun run <command>的速度比yarn和pnpm中相应的命令更快。
脚本运行平均时间
npm run176ms
yarn run131ms
pnpm run259ms
bun run7ms 🚀

Bun:测试运行器

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

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或Vite迁移很简单。@jest/globalsvitest的任何导入将在内部重新映射到bun:test,因此即使不进行任何代码更改,一切也将正常运行。

import { test } from "@jest/globals";

describe("test suite", () => {
// ...
});

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

Bun的匹配器由快速的原生代码实现,Bun中的expect().toEqual()比Jest快100倍,比Vite快10倍。

可以使用bun test命令来加快 CI 构建速度,如果在Github Actions中,可以使用官方的oven-sh/setup-bun操作来设置Bun

name: CI
on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: oven-sh/setup-bun@v1
- run: bun test

Bun会自动为测试失败的部分添加注释,以便在持续集成(CI)日志中更容易理解。这样,当出现测试失败时,可以直接从日志中读取Bun提供的注释,而不需要深入分析代码和测试结果,从而更方便地检查问题所在。

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.ts
export 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.ts
import { getRelease } from "./release.ts" with { type: "macro" };

// release的值是在打包时进行评估的,并且内联到打包文件中,而不是在运行时执行。
const release = await getRelease();
bun build index.ts
// index.ts
var release = await "bun-v1.0.0";

Bun:可以做更多事

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

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

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

Bun:面向未来

Bun 1.0 只是一个开始。Bun 团队正在开发一种全新的部署JavaScript和TypeScript到生产环境的方式,期待 Bun 未来更好的表现!

往期推荐

图解 60 个 CSS 选择器,一网打尽!

Facebook出品的前端工具链凉了!

主流浏览器都支持原生 CSS 嵌套了!

htmx:增强版 HTML 来了!

Astro 3.0 正式发布,爆火的现代化前端框架

Node.js 终于原生支持 .env 文件了!

10个极大提高开发效率的 VS Code 技巧!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存