Bun

Bun v1.0.32


Jarred Sumner · March 17, 2024

Bun is an incredibly fast JavaScript runtime, bundler, transpiler, and package manager — all in one.

Bun v1.0.32 fixes 13 bugs and improves Node.js compatibility. 'ws' package can now send & receive ping/pong events. util.promisify'd setTimeout setInterval, setImmediate work now. FileHandle methods have been implemented.

Previous releases

  • v1.0.31 fixes 54 bugs (addresses 113 👍 reactions), introduces bun --print, <stdin> | bun run -, bun add --trust, fetch() with Unix sockets, fixes macOS binary size regression, fixes high CPU usage bug in spawn() on older linux, adds util.styleText, Node.js compatibiltiy improvements, bun install bugfixes, and bunx bugfixes
  • v1.0.30 fixes 27 bugs (addressing 103 👍 reactions), fixes an 8x perf regression to Bun.serve(), adds a new --conditions flag to bun build and Bun's runtime, adds support for expect.assertions() and expect.hasAssertions() in Bun's test runner, fixes crashes and improves Node.js compatibility.
  • v1.0.29 fixes 8 bugs. Bun.stringWidth(a) is a ~6,756x faster drop-in replacement for the popular 'string-width' package. bunx checks for updates more frequently. Adds expect().toBeOneOf() in bun:test. Memory leak impacting Prisma is fixed. Shell now supports advanced redirects like '2>&1', '&>'. Reliability improvements to bunx, bun install, WebSocket client, and Bun Shell
  • v1.0.28 fixes 6 bugs (addressing 26 👍 reactions). Fixes bugs impacting Prisma and Astro, node:events, node:readline, and node:http2. Fixes a bug in Bun Shell involving stdin redirection and fixes bugs in bun:test with test.each and describe.only.

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

Fixed: GitHub actions timeout with bun install

In Bun v1.0.31, we rewrote how a lot of I/O works in Bun in preparation for Windows support. This has led to a few regressions.

When more than 16 lifecycle scripts were invoked at the very end of the install process, bun install could potentially hang. To prevent system instability, bun install sets a maximum number of lifecycle scripts to execute concurrently. Due to a bug, the counter which increments the number of active lifecycle scripts was never decremented. This has been fixed.

Thanks to @farreldarian for providing an easy reproduction.

Fixed: bun install --production regression

Bun v1.0.31 incorrectly changed the order of how --frozen-lockfile and --production flags were handled.

These flags are supposed to block installs that change the lockfile, but in v1.0.31, the install process would still occur. The exit code would still be correct (causing CI to fail), but the packages were still installed.

Now it correctly verifies the lockfile and does not install packages when --frozen-lockfile is passed before installing packages.

We've expanded our test suite to prevent this from regressing.

Fixed: Shell hanging with || &&

In certain cases the following command would hang:

import { $ } from "bun";
await $`echo 1 && echo 1`;

This was a regression caused by our I/O rewrite. We were not closing a file descriptor. This has been fixed, thanks to @zackradisic. We have expanded our test suite to prevent this from regressing.

Fixed: Using bun shell instead of system shell

In Bun v1.0.31, we unintentionally enabled the bun shell as the package.json script runner for posix. This was only meant to be enabled for Windows. We have written tests to prevent this from happening again.

We've also added the --shell flag that lets you opt-in to using either the "bun" shell or the "system" shell:

bun --shell=bun run my-package-json-script

Fixed: import.meta.url query string parameters

Bun was returning the encoded query string params in import.meta.url instead of the decoded query string params.

For the following code:

index.mjs
import './test?param=value'
test.mjs
console.log(import.meta.url);

Previously, Bun would return the following incorrect string:

run.sh
bun-1.0.31 ./index.mjs
file:///Users/jarred/test.mjs%3Fparam=value

Now Bun returns the correct string:

run.sh
bun ./index.mjs
file:///Users/jarred/test.mjs?param=value

Thanks to @paperdave for fixing this.

Fixed: Subprocess.kill(undefined)

The argument-coercion code for Bun.spawn().kill has been tweaked to match the behavior of Node.

Previously, this snippet would hang forever:

import { spawn } from "bun";

const proc = spawn({
  cmd: ["sleep", "infinity"],
});
proc.kill(undefined);

Now undefined will coerce to the equivalent of not passing it any arguments -- SIGTERM. Similarly, null, "", false coerce to SIGTERM. This aligns the behavior with Node's child_process.kill and honestly feels more like JavaScript.

Node.js compatiblity improvements

This release also includes a few Node.js compatiblity improvements

"ws" module can send & receive ping and pong

The "ws" WebSocket client & server can now send and receive "ping" and "pong" events when using Bun.

output
ping.mjs
output
bun ping.mjs
Server is listening
Ping received on server side hello
Pong received on client side hello
Pong received on client side hello
bun-1.0.31 ping.mjs # Before
Server is listening
Pong received on client side hello
node ping.mjs # Node, for comparison
Server is listening
Ping received on server side hello
Pong received on client side hello
Pong received on client side hello
ping.mjs
import WebSocket, { WebSocketServer } from "ws";

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (ws) => {
  ws.on("ping", (data) => {
    console.log("Ping received on server side", data.toString());
    ws.pong(data);
  });
});

// test client
const ws = new WebSocket("ws://localhost:8080");

ws.on("pong", (data) => {
  console.log("Pong received on client side", data.toString());
});

ws.on("open", () => {
  ws.ping(Buffer.from("hello"));
});

// listen for the server
wss.on("listening", () => {
  console.log("Server is listening");
});

FileHandle read & write methods

The Node FileHandle class implementation in Bun is implemented more correctly. You can call .read or .write and it returns the expected result instead of just a number.

We've also fixed a bug that could cause it to not call close on the file descriptor when it should have.

Thanks to @eventualbuddha for their help with this

util.promisify + setTimeout, setInterval, setImmediate

When using util.promisify on timers in Bun, they now behave like they do in Node.js. This includes:

  • setTimeout
  • setInterval
  • setImmediate
import { promisify } from "util";

const setTimeoutAsync = promisify(setTimeout);

await setTimeoutAsync(1000);
// await Bun.sleep(1000)

Windows support is close

We are close to shipping Windows support with Bun v1.1. Once Bun for Windows passes 95% of Bun's test suite, we will announce the release date.

Thank you to 8 contributors!

Full Changelog