Bun

Bun v1.0.13


Jarred Sumner · November 18, 2023

Bun v1.0.13 fixes 6 bugs (addressing 317 👍 reactions), adds support for the "node:http2" module (unblocking gRPC in Bun). Vite 5 & Rollup 4 work now. Implements process.report.getReport(), improves support for ES5 with statements, fixes a regression in bun install, and fixes a crash when printing exceptions.

Bun is an incredibly fast JavaScript runtime, bundler, transpiler, and package manager — all in one. In case you missed it, here are some of the recent changes to Bun:

  • v1.0.8 - Fixes 138 bugs (addressing 257 👍 reactions), makes require() use 30% less memory, adds module mocking to bun test, fixes more bun install bugs
  • v1.0.9 - Fixes a glibc symbol version error, illegal instruction error, a Bun.spawn bug, an edgecase with peer dependency installs, and a JSX transpiler bugfix
  • v1.0.10 - Fixes 14 bugs (addressing 102 👍 reactions), node:http gets 14% faster, stability improvements to Bun for Linux ARM64, bun install bugfix, and node:http bugfixes
  • v1.0.11 - Fixes 5 bugs, adds Bun.semver, fixes a bug in bun install and fixes bugs impacting astro and @google-cloud/storage
  • v1.0.12 - Adds bun -e for evaluating scripts, bun --env-file for loading environment variables, server.url, import.meta.env, expect.unreachable(), improved CLI help output, and more

To install Bun:

curl
npm
brew
docker
curl
curl -fsSL https://bun.sh/install | bash
npm
npm install -g bun
brew
brew tap oven-sh/bun
brew install bun
docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun

To upgrade Bun:

bun upgrade

http2 client support

You can now use the node:http2 module's client functions in Bun!

import { connect } from "node:http2";
const client = connect("https://example.com");

const req = client.request({ ":path": "/" });

req.on("response", (headers, flags) => {
  for (const name in headers) {
    console.log(`${name}: ${headers[name]}`);
  }
});

Thanks to @cirospaciari

gRPC works now

Our node:http2 implementation unblocks gRPC.js in Bun. @grpc/grpc-js is a popular gRPC client and server library for Node.js.

import { loadPackageDefinition } from "@grpc/grpc-js";
import { join } from "path";

const protoPath = join(__dirname, "protos/helloworld.proto");
const packageDefinition = loadPackageDefinition(protoPath);

const client = new packageDefinition.helloworld.Greeter(
  "localhost:50051",
  credentials.createInsecure(),
);

client.sayHello({ name: "world" }, (err, response) => {
  console.log("Greeting:", response.message);
});

To prevent regressions, we've ported much of grpc's test suite to run on every commit to Bun.

Thanks to @cirospaciari

Vite 5 & Rollup 4 work now

There were two bugs in Bun that prevented Vite 5 and Rollup 4 from working out of the gate. Both of these bugs have been fixed in Bun v1.0.13.

process.report.getReport() is now implemented

The Node.js API process.report.getReport is now implemented in Bun. Native addons frequently use this to get the current libc version and whether it is using glibc or musl on Linux.

That particular usecase - detecting libc - is what was blocking Rollup 4 (which Vite 5 depends on) from working in Bun. Now that process.report.getReport() is implemented, Rollup 4 works in Bun.

To prevent regressions, we've added an integration test that runs Rollup 4 in Bun on every commit.

Transpiler bug involing require and ternaries is fixed

A transpiler bug when statically-known pure constants were used in ternaries that call require() was fixed. This bug was blocking Vite 5 from working in Bun. Thanks to @dylan-conway for the fix.

Improved support for ES5 with statements

Before the days of destructuring, the with statement was a popular way to avoid typing out long object names.

For example, instead of writing

import { join } from "path";
join(__dirname, "foo");

You could write

with (require("path")) {
  join(__dirname, "foo");
}

Today, a lot of developers would get mad at you for using with. But it is a part of JavaScript, and Bun must support it. Importantly, there are popular libraries people depend on that use with, and those must work in Bun.

Using with now makes the file CommonJS

with statements are not supported in strict mode. ES Modules are strict mode-only.

Previously, Bun would throw an error like this when you used with without any other CommonJS syntax:

SyntaxError: 'with' statements are not valid in strict mode.

Now, Bun will automatically convert the file to CommonJS if you use with:

with (require("path")) {
  join(__dirname, "foo");
}

Bun.spawn better errors

Previously, Bun.spawn would silently fail on macOS when errors like the current working directory did not exist:

Bun.spawn({
  cwd: "/i/dont/exist!",
  cmd: ["ls"],
});

Now, it (correctly) will throw an error:

ENOENT: No such file or directory
   path: "/opt/homebrew/opt/coreutils/libexec/gnubin/ls"
 syscall: "posix_spawn"
   errno: -2

This is fixed thanks to @Electroid.

Why did this happen?

Most C system call wrappers return -1 and then expect the developer to check errno. posix_spawn is a little unusual. Instead, any non-zero value is an error, and the errno is returned directly. We were checking for errno, errno was reporting that everything was fine, and so we were not throwing an error.

We have added a test to check posix_spawn throws accordingly.

Regression in bun install fixed

A regression that caused "FileNotFound" errors to appear in bun install in certain cases has been fixed, thanks to @dylan-conway.

A peer dependencies determinism issue is fixed

A bug sometimes caused bun install to non-deterministically choose which peer dependency version to install. This bug has been fixed, thanks to @dylan-conway.

Fixed: The Stats.atime getter can only be used on instances of Stats

The following error was fixed:

const { Stats } = require("node:fs");
const stat = Object.create(Stats.prototype);
stat.atime; // previously: threw "The Stats.atime getter can only be used on instances of Stats"

Some libraries create Stats objects using Object.create(Stats.prototype). Previously, Bun would throw an error when you tried to access atime on a Stats object created this way (it is implemented as a class currently). Now, Bun will return undefined instead of throwing an error and allow the fields to be set.

This unblocks certain libraires.

Fixed: new Server in node:http

The following error was fixed:

import { Server } from "http";
new Server({ key: "123" });

Previously, this would throw the following error:

TypeError: key argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile

This error was incorrect. It no longer errors.

Thanks to @HK-SHAO for the fix.

Fixed: napi_get_value_string_utf8 behaves like Node.js now

Bun's implementation of napi_get_value_string_utf8 now more closely matches the behavior of Node.js, thanks to @oguimbal.

Slightly fewer strings are allocated in CommonJS modules

CommonJS modules have require and require.resolve functions.

In Bun, these are implemented as the native code equivalent of a .bind call. Bound functions by default change the name, but code expects require.name to return "require" and require.resolve.name to return "resolve" - so we must manually set the name.

It turns out, the way we were manually setting the name caused the name to be a new string created every time any CommonJS module was loaded. These two strings are small, but if you load hundreds of modules, it adds up.

require("discord.js");
const { heapStats } = require("bun:jsc");
const { strings } = heapStats().objectTypeCounts;

console.log(strings, "+ strings allocated");
BeforeAfter
10,397 strings9,628 strings

That's a 7.9% reduction in strings allocated when loading Discord.js

Does this make a performance difference? Probably not. But it's a nice cleanup.

Thanks to 9 contributors!