Bun v1.0.34

Ashcon Partovi ยท March 22, 2024

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

Bun v1.0.34 fixes 7 bugs, bunx uses less memory, bun install gets faster on Docker & WSL, a conflicting devDependency hoisting bug is fixed, a cyclical CommonJS & ESM import crash is fixed, cross-mount fs.cp & fs.copyFile get 50% faster on Linux, and reliability improvements for bun install & bun's runtime.

Previous releases

  • v1.0.33 fixes 2 bugs, including a bug with the mv command in Bun Shell and in node:crypto creating & verifying signatures
  • 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.
  • 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.

To install Bun:

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

To upgrade Bun:

bun upgrade

Runtime improvements

50% faster cross-mount fs.cp & fs.copyFile on Linux

We've optimized system calls used in fs.cp and fs.copyFile to make copying files across filesystems 50% faster on Linux. Bun now adds sendfile to its repertoire of system calls used to copy files.

This will likely have the most impact for Docker users and Windows Subsystem for Linux users.

Fixed: CommonJS <> ESM cylical import crash

A crash that sometimes occurred involving cyclical ESM & CommonJS imports has been fixed.

Here's what went wrong:

  1. You run bun foo.ts

foo.ts looks something like this:

import "./boop"; // <-- concurrently fetch "boop"
import "./baz"; // <-- concurrently fetch "baz"
  1. baz.ts is a CommonJS module that requires boop. It loads synchronously.
require("./boop"); // <-- we already started fetching "boop"
  1. boop is an ES module that imports foo.ts. Boop began loading asynchronously, but now it must load synchronously.
import "./foo";

CommonJS and ES Modules have different rules for cyclical imports. In CommonJS, the module is evaluated twice with exports memoized. In ES Modules, the module is only evaluated once but you can run into "Uninitialized variable" errors.

A crash sometimes occurred when the ES module finished loading after the CommonJS version had already been evaluated. We were missing a check to prevent the ES module from evaluating after the reference to it was stale. This caused a crash because the Promise was freed immediately after there were no longer any strong references to it. The strong reference gets cleared immediately before the Promise is fulfilled. The fix was to check if we had already evaluated the module and choose not to evaluate it again.

Fixed: Crash when asset import has a query parameter

A crash that sometimes occurred when importing modules with query string parameters in the specifier has been fixed.

The following is an example that could reproduce the crash:

for (let i = 0; i < 100_000; i++>) {
  const {default: MyIcon} = await import(`./MyIcon-${i}.svg?foo=${i}`);

Fixed: Bun.sleep not handling negative values

We fixed a bug where Bun.sleep would not handle negative values correctly. This would cause Bun to hang, when it should have exited immediately.

for (const timeout of [
  -0, -0.1, -0.0000000000000001, -999999999999999,
]) {
  await Bun.sleep(timeout);

The cause of this bug was an incorrect integer conversion to i32.

Module imports coalescing

When possible, Bun transpiles CommonJS & ES module imports concurrently on another thread. Previously, when you import 1,000 modules in Bun and they finish fetching, Bun would allocate 1,000 individual event loop tasks to tell the event loop to to tell JavaScriptCore to parse the imports. Each task costs memory and CPU time. Instead of doing that, Bun now coalesces fetched modules into a single task that drains all of the fetched imports at once.

For example, if you were to send 100 fetch() requests to localhost and 100 imports in parallell, previously those 100 fetch() requests and 100 imports would potentially finish 1 by 1 and each would allocate a task internally. Now the completed imports would be executed sooner than the completed fetch() requests. This is similar to timers in Bun, which are also coalesced.

This is unlikely to have much impact on your application, but it felt worth mentioning.

bun install improvements

on macOS, bunx now replaces the current process

When you run bunx <package> on macOS, it will now replace the current process with the executable for the package. This saves you memory and CPU time because the bunx process stops running as soon as the new process is started instead of waiting for the old process to exit first.

bun installs gets a little faster on Docker & WSL

We've applied the same optimization for copying files across filesystems used in fs.cp and fs.copyFile to make copying files in bun install faster.

This mostly applies to Docker and WSL, where a remote filesystem is used or a filesystem like overlayfs where renameat(2) is not supported.

Fixed: Conflicting devDependency + dependency hoisting bug

We introduced a regression in Bun v1.0.32 where devDependencies would be hoisted above regular dependencies, to better support when a package was present in both. However, this caused issued with packages like eslint.

Now, devDependencies are only hoisted if the dependency to hoist is from the same dependency tree. This prevents bugs where a dependency is hoisted, but the parent node_modules has a dev dependency with the same name but a different version.

Fixed: bun pm trust could hang in some cases

We found a bug where bun pm trust could hang if there were enough lifecycle scripts were being run. This has been fixed thanks to @dylan-conway.

Fixed: High CPU usage with lifecycle scripts on some Linux systems

A bug where bun install would use up to 100% CPU and block execution when running lifecycle scripts on some Linux systems has been fixed. This was caused by a missing check.

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.

Here's a summary of the changes we've made to Bun for Windows in this release:

Fixed: process.stdout is synchronous on Windows

We fixed a bug where process.stdout and process.stderr were asynchronous on Windows. This would cause issues where Bun would exit before all output was written to the terminal. To match the behavior of Node.js, we have made both synchronous on Windows.

Fixed: Default trustedDependencies not working on Windows

We fixed a bug where the default trustedDependencies were not working on Windows. This was because Bun was not properly checking for \r carriage returns in bun.lockb.

Thanks to @dylan-conway for fixing this bug!

Fixed: Various bun install bugs on Windows

  • bunx was not locating bin files properly, causing it to not find executables
  • bun install would not always detect tarballs correctly
  • bun install would not always format relative paths correctly

Thanks to @dylan-conway for fixing these bugs!

Thank you to 6 contributors!

Full Changelog