Bun

Bun v1.0.30


Jarred Sumner ยท March 4, 2024

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

This release 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.

Previous releases

  • 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.
  • v1.0.27 fixes 72 bugs (addressing 192 ๐Ÿ‘ reactions), Bun Shell supports throwing on non-zero exit codes, stream Response bodies using async generators, improves reliability of fetch(), http2 client, Bun.Glob fixes. Fixes a regression with bun --watch on Linux. Improves Node.js compatibility

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: 8x performance regression in Bun.serve() in certain cases

A performance regression when using streams to write exactly one chunk of data to the response body in a single tick of the event loop has been fixed in Bun.serve(). This regression was introduced in v1.0.4.

The following code sometimes reproduces the issue:

Bun.serve({
  async fetch(req) {
    return new Response(
      new ReadableStream({
        type: "direct",
        async pull(controller) {
          controller.write("hello");
          await controller.end();
        },
      }),
    );
  },
});

Tip: when using nginx with Bun, make sure to set proxy_http_version 1.1 in your nginx configuration. HTTP Keep-Alive is important for performance, and nginx by default disables it.

New flag: --conditions

The --conditions flag allows you to specify a list of conditions to use when resolving packages from package.json "exports".

This flag is supported in both bun build and Bun's runtime.

# Use it with bun build:
bun build --conditions="react-server" --target=bun ./app/foo/route.js

# Use it with bun's runtime:
bun --conditions="react-server" ./app/foo/route.js

Bun already supported package.json "exports", this release adds support for adding additional conditions to target.

You can also use conditions programmatically with Bun.build:

await Bun.build({
  conditions: ["react-server"],
  target: "bun",
  entryPoints: ["./app/foo/route.js"],
});

This CLI flag is also supported by Node.js with the same syntax.

Thanks to @igorwessel for implementing this feature!

expect.assertions() and expect.hasAssertions() are now supported

expect.assertions() and expect.hasAssertions() are now supported in Bun's test runner.

test("expect.assertions()", () => {
  expect.assertions(1);
  expect(true).toBe(true);
});

test("expect.hasAssertions()", () => {
  expect.hasAssertions();
  expect(true).toBe(true);
});

Thanks to @Yash-Singh1 for implementing this feature!

Bun.fileURLToPath(url) now supports strings

Bun.fileURLToPath(url) now supports strings as well as URL objects.

// new:
Bun.fileURLToPath("file:///path/to/file.txt");

// old (still works):
Bun.fileURLToPath(new URL("file:///path/to/file.txt"));

Bun Shell better stacktraces on error

Bun Shell now provides better stacktraces on error.

Previously, Bun Shell would not include the full stacktrace when an error occurred. This has been fixed, thanks to @zackradisic.

Fixed: potential crash in Bun.serve() with delayed request bodies

A crash that could potentially occur when sending a buffered response after receiving a request body has been fixed.

The following code sometimes reproduces the issue:

Bun.serve({
  development: true,
  async fetch(request: Request): Promise<Response> {
    await Bun.sleep(200 + Math.random() * 100);
    const body = await (async function () {
      return await request.json();
    })();
    return new Response(JSON.stringify(body));
  },
});

This crash occurred because Bun will automatically reject pending Promises that consume requests when the request aborts, and Bun's code was not checking that the Promise to read the request body was still pending before attempting to reject the Promise. Rejecting the Promise triggered an assertion failure internally, which led to the crash.

Fixed: Headers with underscores and uppercase names in Bun.serve()

Bun v1.0.28 added support for receiving headers with underscores in Bun.serve(). For several reasons, Bun.serve() automatically lowercases all incoming header names (HTTP headers are case insensitive by the spec). A bug in the HTTP server's code for lowercasing header names caused the underscore to be invalid in the header name, leading to unexpected behavior. This has been fixed.

Fixed: textEncoder.encode() JIT bug under certain conditions

A bug in the side effects configuration in TextEncoder.prototype.encode caused it to potentially return unexpected results when called thousands of times in a short loop when no allocations occur between calls. This has been fixed.

Fixed: Crash when printing error stacks with mocked functions

A bug in Bun's implementation of mock functions caused a crash when printing error stack traces that contain an anonymous mock function. This has been fixed.

The following test reproduces the crash:

test("#8794", () => {
  const target = {
    a() {
      throw new Error("a");
      return 1;
    },
    method() {
      return target.a();
    },
  };
  spyOn(target, "method");

  for (let i = 0; i < 20; i++) {
    try {
      target.method();
      expect.unreachable();
    } catch (e) {
      e.stack;
      expect(e.stack).toContain("at method ");
      expect(e.stack).toContain("at a ");
    }
    Bun.gc(false);
  }
});

Fixed: crash in expect(undefined).toContainKeys(a)

expect(undefined).toContainKeys(array) no longer crashes the test runner. This crash occurred due to missing a check for an object-like expect() value in the toContainKeys matcher.

Thanks to @dylan-conway for fixing this bug.

Fixed: Potential crash with timers in event loop

An uninitialized memory access in the event loop library used by Bun could lead to a crash after about 16 minutes in certain cases. This crash could be reproduced most frequently on Linux ARM64 builds of Bun. Thanks to @argosphil for fixing this bug.

Node.js compatiblity improvements

This release includes several Node.js compatibility improvements.

isKeyObject in util/types is implemented

The isKeyObject function in node:util/types is implemented. This function returns true if the input is a KeyObject.

import { isKeyObject } from "node:util/types";
import { generateKeyPairSync } from "node:crypto";
isKeyObject({}); // false
isKeyObject(generateKeyPairSync("ed25519").publicKey); // true

fdatasync in node:fs is implemented

Bun now implements fdatasync in node:fs. This function synchronously writes all changes made to the file to disk.

import { fdatasync } from "node:fs";

fdatasync(fd);

Bun now behaves like Node.js when using require.main with symlinks.

ln -s /path/to/real.js /path/to/symlink.js
// symlink.js
console.log(require.main === module); // true

This helps address a compatibility issue when running prisma generate using Bun.

Fixed: crash in napi_get_buffer_info

When using the napi_get_buffer_info function in a native addon and passing a null pointer for the size argument, Bun no longer crashes.

Fixed: Emit end-of-file correctly in Node.js Readable

A bug in our node:stream implementation caused the readable event to be emitted in a microtask instead of process.nextTick. This has been fixed, thanks to @camero2734.

This bug impacted prisma generate and other tools that use Node.js streams.

Fixed: missing event in node:streams impacting node-fetch

A bug in our node:streams implementation where we called destroy on the stream on the next tick after calling this.push(null) led to node:streams not destroying the stream correctly. This bug caused node-fetch to never finish reading the response body. This bug impacted prisma generate and other tools that bundle node-fetch into their package.

Bun internally overrides node-fetch to use the fetch global provided by Bun, so packages using node-fetch directly were not impacted by this bug.

Thanks to @camero2734 for fixing this bug.

Fixed: 'request.endsWith is not a function' error in Next.js

When using Bun to run a Next.js app, after a large number of requests you might run into an error like this:

57 | }).bind(null, resolveFilename, hookPropertyMap);
58 | // This is a hack to make sure that if a user requires a Next.js module that wasn't bundled
59 | // that needs to point to the rendering runtime version, it will point to the correct one.
60 | // This can happen on `pages` when a user requires a dependency that uses next/image for example.
61 | mod.prototype.require = function(request) {
62 |     if (request.endsWith(".shared-runtime")) {
             ^
TypeError: request.endsWith is not a function. (In 'request.endsWith(".shared-runtime")', 'request.endsWith' is undefined)
      at node_modules/next/dist/server/require-hook.js:62:9
      at getMiddleware (node_modules/next/dist/server/next-server.js:904:26)
      at node_modules/next/dist/server/base-server.js:173:32
      at node_modules/next/dist/server/base-server.js:172:50
      at node_modules/next/dist/server/base-server.js:275:34

This bug has been fixed. Our implementation of require was incorrectly using the tailcall intrinsic in JavaScriptCore which sometimes led to arguments in the function being forwarded to bound functions incorrectly.

Fixed: cp function in node:fs with relative paths

A regression in v1.0.27 intended for Windows support caused the cp function in node:fs to not handle relative paths correctly. This bug has been fixed, thanks to @argosphil.

Fixed: process.stdin ends too early

Given a large enough input, the following code would incorrectly lose one of the last chunks of data:

const { Transform } = require("node:stream");

let totalChunkSize = 0;
const uppercase = new Transform({
  transform(chunk, _encoding, callback) {
    totalChunkSize += chunk.length;
    callback(null, "");
  },
});

process.stdin.pipe(uppercase).pipe(process.stdout);
process.stdin.on("end", () => console.log(totalChunkSize));

This impacted prisma generate, amongst others. Thanks to @camero2734 for fixing it.

Windows support is coming in Bun v1.1.0

We are still working on Windows support. We are making progress, but it's not ready yet. You will see a release with Windows support soon.

Thanks to 14 contributors!