Bun

Bun v1.0.8


Ashcon Partovi ยท November 2, 2023

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, and fixes more runtime bugs.

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.0 - First stable release!
  • v1.0.1 - Named imports for .json and .toml files, fixes to bun install, node:path, and Buffer
  • v1.0.2 - Make --watch faster and lots of bug fixes
  • v1.0.3 - emitDecoratorMetadata and Nest.js support, fixes for private registries and more
  • v1.0.4 - server.requestIP, virtual modules in runtime plugins, and more
  • v1.0.5 - Fixed memory leak with fetch(), KeyObject support in node:crypto module, expect().toEqualIgnoringWhitespace in bun:test, and more
  • v1.0.6 - Fixes 3 bugs (addressing 85 ๐Ÿ‘ reactions), implements overrides & resolutions in package.json, and fixes regression impacting Docker usage with Bun
  • v1.0.7 - Fixes 59 bugs (addressing 78 ๐Ÿ‘ reactions), implements optional peer dependencies in bun install, and makes improvements to 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

require() uses up to 30% less memory

We discovered a memory leak when using require(), which was introduced when some of Bun's built-in modules were refactored from ESM to CommonJS. We've also added a small performance optimization to Bun's JavaScript parser for large files that create many scopes.

Bun v1.0.7: (before)

โฏ bun discordy.js
[92.39ms] require("discord.js")
Memory: 73.5625 MB

Bun v1.0.8: (after)

โฏ bun discordy.js
[90.22ms] require("discord.js")
Memory: 55.1875 MB

Module mocking in bun test

bun test now supports module mocking.

  • Module mocks support both ESM and CJS.
  • Existing imports are updated in-place. This means module mocks work at runtime (unlike other test runners, which do it at build time).
  • You can override builtins, local files, and packages.
import { mock, test, expect } from "bun:test";
import { fn, iCallFn, variable } from "./mock-module-fixture";

test("mocking a local file", async () => {
  expect(fn()).toEqual(42);
  expect(variable).toEqual(7);

  mock.module("./mock-module-fixture.ts", () => {
    return {
      fn: () => 1,
      variable: 8,
    };
  });
  expect(fn()).toEqual(1);
  expect(variable).toEqual(8);

  mock.module("./mock-module-fixture.ts", () => {
    return {
      fn: () => 2,
      variable: 9,
    };
  });
  expect(fn()).toEqual(2);
  expect(variable).toEqual(9);

  mock.module("./mock-module-fixture.ts", () => {
    return {
      fn: () => 3,
      variable: 10,
    };
  });
  expect(fn()).toEqual(3);
  expect(variable).toEqual(10);

  expect(require("./mock-module-fixture").fn()).toBe(3);
  expect(require("./mock-module-fixture").variable).toBe(10);
  expect(iCallFn()).toBe(3);
});

bun install peer dependency duplicate version bugfix

Previously, bun install would always resolve the most recent version of a peer dependency, even if it was already installed. This could cause duplicate versions of the same package to be installed, which would increase the size of node_modules and potentially cause conflicts. This has been fixed thanks to @dylan-conway.


bar@1.0.1
foo@1.0.0
bar@^1.0.1

Bun v1.0.7: (before)


bar@1.0.1
bar@1.0.2

Bun v1.0.8: (after)


bar@1.0.1

bun install respects ordering of pre-release tags

A bug causing bun install to not respect the ordering of pre-release tags has been fixed, thanks to @dylan-conway. Previously, Bun would only sort the pre-release tag lexicographically, but now it also sorts by semver presedence, if one exists.

package.json
{
  "dependencies": {
    "foo": "^1.0.0-beta.0.0.1"
  }
}

Bug fixes

Fixed: Bun.spawn not working in Google Cloud, Vercel, and older Linux kernels

Bun.spawn is implemented using a syscall, pidfd_open, which is not implemented by gVisor (includes Google Cloud Platform and Vercel) and by older Linux kernels. We implemented a workaround where Bun spawns a thread, enqueue concurrent tasks, then calls waitpid on each pid. This workaround is loosely based on libuv's default behavior.

If you encountered this error, upgrade to Bun v1.0.7 and it should now work.

// This error is fixed:
error: "pidfd_open(2)" system call is not supported by your Linux kernel

Fixed: Bun.spawn on macOS sometimes not detecting process exit

A longstanding bug in Bun.spawn on macOS has been fixed. Previously, Bun.spawn() on macOS might fail to detect when the process exited when the event came shortly before a signal was sent. This was due to a race condition in event notifications from kqueue where the process might receive a notification from the operating system, but has not exited yet and then when we subscribe to notifications from the operating to detect when the process exits, it would tell us it exited.

In text-speak, the bug was this:

macOS: "hey something happened with process 123456"

bun: "cool, did process 123456 exit?"

macOS: "no"

bun: "ok...tell me when process 123456 exits"

macOS: "i can't tell u because it already exited"

bun: "???"

Now, we handle this case by recognizing when macOS reports it already exited after previously reporting it hadn't exited yet.

Fixed: process.stdin not sending close event

When Bun was done reading from process.stdin, it would not send a close event. This has been fixed, thanks to @liz3.

Fixed: setTimeout(cb, 0) behaved incorrectly

setTimeout now has a minimum duration of 1, which aligns with the behaviour of Node.js and browsers. Previously, setTimeout with 0 would cause weird behavior, such as infinite loops when the task queue was being drained before moving on to the next tick.

Fixed: setImmediate() behaved incorrectly

setImmediate now has a separate task queue, which aligns setImmediate with what Node.js does. Previously, setImmediate was similar to queueMicrotask which was incorrect.

Fixed: server.requestIP sometimes returning bad IP addresses

A bug causing server.requestIP to sometimes return malformed IP addresses has been fixed, thanks to @Hanaasagi.

Bun v1.0.7: (before)

{
  "address": "4294967232.4294967208.68.57",
  "family": "IPv4",
  "port": 40174
}

Bun v1.0.8: (after)

{
  "address": "192.168.68.57",
  "family": "IPv4",
  "port": 40174
}

Fixed: Edgecase with util.promisify and node:dns

A bug causing util.promisify to not work correctly with node:dns has been fixed, thanks to @antongolub.

Bun v1.0.7: (incorrect)

const { promisify } = require("node:util");
const { lookup } = require("node:dns");

await promisify(lookup)("example.com"); // "45.33.20.235"

Bun v1.0.8: (correct)

const { promisify } = require("node:util");
const { lookup } = require("node:dns");

await promisify(lookup)("example.com"); // { address: "45.33.20.235", family: 4 }

Fixed: Crash when calling Script or File without new

Thanks to @krk for fixing a crash when invoking certain classes without new. We have plans to mitigate this class of bug by improving our API bindings.

Bun v1.0.7: (before)

File(); // <crash>
Script(); // <crash>

Bun v1.0.8: (after)

File(); // "Class constructor File cannot be invoked without 'new'"
Script(); // "Class constructor Script cannot be invoked without 'new'"

Fixed: Minifier printing bug with case undefined

Thanks to @krk for fixing a bug where case undefined was minified to have a missing whitespace, causing invalid JavaScript syntax.

switch (true) {
  case undefined: {
  }
}

Bun v1.0.7: (before)

switch(true){caseundefined:{}} // SyntaxError: Unexpected token 'caseundefined'

Bun v1.0.8: (after)

switch(true){case undefined:{}}

Fixed: Edgecases with macros causing a crash

There were some edgecases when using macros that would cause a crash, instead of showing the underlying error. This has been fixed, thanks to @I-A-S.

Fixed: Incorrect behviour for Buffer.readUintBE

There was an decoding bug that caused Buffer.readUintBE to return incorrect values in certain cases. Thanks to @Hanaasagi for fixing this issue.

Fixed: fetch() not throwing an error for untrusted certificates

A bug in error handling code for BoringSSL in fetch led to Bun not throwing an error when server certificates in fetch() failed to verify and inadvertently ignoring some errors from BoringSSL.

Thanks to @ansg191 for discovering and reporting this issue. Thanks to @cirospaciari for implementing a fix and improving our test coverage.

New: Support for printing Map and Set iterators

Bun will now print Map and Set iterators in console.log, thanks to @liz3.

const set = new Set([1, "123", { a: [], str: "123123132", nr: 3453 }]);
console.log(set.keys());

SetIterator {
  1,
  "123",
  {
    a: [],
    str: "123123132",
    nr: 3453
  },
}

New Contributors

Thanks to 26 contributors

Thanks to the following 26 people for contributing to this release of Bun:

Full Changelog: https://github.com/oven-sh/bun/compare/bun-v1.0.7...bun-v1.0.8