Bun v1.1.9 is here! This release fixes 67 bugs (addressing 150 👍), and includes fixes to workspaces in bun install
, sourcemaps in bun build
, IPv6 & VPN connectivity issues, loading UNC paths, junctions, symlinks, and pnpm on Windows. fetch()
gets faster. A new dns.prefetch()
API is introduced. atob()
gets 8x faster. buffer.toString('base64url')
gets 5x faster. expect().toBeReturned()
matcher is introduced. We've also made Node.js compatibility improvements and added Bun Shell fixes. Oh, and lots more bugfixes.
We're hiring systems engineers in San Francisco to build the future of JavaScript!
Previous releases
v1.1.8
fixes 54 bugs (addressing 184 👍). Support forprocess.on("uncaughtException")
andprocess.on("unhandledRejection")
,JSON.parse
gets faster, Brotli support innode:zlib
,[Symbol.dispose]
in Bun APIs, fixes lots of crashes on Windows, and many other bugfixes.v1.1.7
fixes 28 bugs (addressing 11 👍). Glob workspace names in bun install. Asymmetric matcher support in expect.extends() equals. bunx --version. Bugfixes to JSX transpilation, sourcemaps, cross-compilation of standalone executables, bun shell, RegExp, Worker on Windows, and Node.js compatibility improvements.v1.1.0
Bundows. Windows support is here!
To install Bun
curl -fsSL https://bun.sh/install | bash
npm install -g bun
powershell -c "irm bun.sh/install.ps1|iex"
scoop install 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
Workspace fixes
This release includes several fixes to workspaces in bun install
.
If you run into any more issues with workspaces, please open an issue and we'll investigate it!
Fixed: Workspace dependency "..." not found
We fixed a bug where running bun add
to the workspace root, it would fail to add the dependency.
In the next version of Bun
— Bun (@bunjavascript) May 21, 2024
Several bugs in workspaces are fixed pic.twitter.com/uxAhJFi0nx
Fixed: Script not found "..."
We fixed a bug when running bun run
in the script of a workspace would not resolve other scripts properly.
{
"name": "monorepo",
"workspaces": ["foo"]
}
{
"name": "foo",
"scripts": {
"prepare": "bun run start",
"start": "echo 'Starting...'"
}
}
Previously, bun add
would fail with:
bun add bar
bun add
⚙️ bar [1/1] error: Script not found "start"
error: prepare script from "start" exited with 1
Now, bun add
will work as expected:
bun add bar
bun add
⚙️ bar [1/1] success
Fixed: Incorrect number of Removed
packages reported
A bug in the lockfile caused Bun to report an incorrect and sometimes inconsistent number of packages removed when running bun install/add/remove
.
Fixed: Crash when non-existent --cwd
is given to bun install
A bug where bun install --cwd=i-dont-exist
would crash with an unhelpful error message has been fixed.
Big thanks to @dylan-conway for fixing these issues!
Fixed: Crash with different versions of bun install
We fixed a crash when it was possible to run bun install
using a newer version of Bun, then running bun add
with an older version of Bun.
# Run `bun install` using a newer version of Bun
bun upgrade --canary
bun install
# Run `bun add` with an older version of Bun
bun upgrade --stable
bun add lodash
This has now been fixed thanks to @dylan-conway.
Improved IPv4, IPv6, & VPN connectivity
A longstanding issue where Bun would fail to connect due to the server only broadcasting on either IPv4 or IPv6 has been fixed.
When your computer is connected to a dual-stack network, it is possible for DNS queries to return both IPv4 and IPv6 addresses. This often happened when using a VPN or connecting to localhost
.
Previously, Bun would not handle this case and would fail to connect to the socket.
For the following input code:
using server = Bun.serve({
hostname: "127.0.0.1",
port: 0,
fetch() { return new Response("👀😊👀"); }
});
const response = await fetch("http://localhost:" + server.port);
console.log(await response.text());
Bun now outputs:
❯ bun happy-eyeballs.js # New
👀😊👀
Previously, Bun would output:
❯ bun-1.1.8 happy-eyeballs.js # Old
ConnectionRefused: Unable to connect. Is the computer able to access the url?
path: "http://localhost:64836/"
Bun v1.1.8 (macOS arm64)
Now, Bun implements a subset of the IETF standard "Happy Eyeballs" algorithm. If Bun receives multiple IP addresses for a single hostname, it will attempt to simultaneously connect to each address, then select the first successful connection.
Thanks to @gvilums for implementing this feature!
fetch()
gets faster DNS resolution
Bun now supports asynchronous DNS resolution in fetch()
requests.
This means that fetch()
is faster in scenarios where your operating system does not use a DNS cache, or if you are sending requests to lots of different subdomains. Bun caches these DNS records in-memory, so that they are not re-resolved every time you make a fetch()
request.
yOu cAnT mAkE fEtCh fAsTeR pic.twitter.com/Ie8a6YM8Js
— Bun (@bunjavascript) May 18, 2024
Thanks to @gvilums for implementing this feature!
Asynchronous DNS & Caching
Bun now automatically caches up to 255 DNS records in-memory for a maximum of 30 seconds. This reduces latency when making multiple requests to the same domain over a short period of time.
This applies to:
fetch()
requestsnode:http
requestsnode:https
requestsBun.connect
requestsnode:net
requestsnode:tls
requests
This cache applies to both in-flight DNS requests and completed DNS requests. This means that if you make 50 fetch()
requests to example.com
at the same time, it will only resolve the DNS record once. If you wait 31 seconds and make another request, it will ask the operating system for the DNS record again.
This is useful for Docker Containers and environments where the operating system may not have an effective DNS cache.
New: dns.prefetch()
API
You can also use the new dns.prefetch()
API to prefetch DNS records before they are needed. This is useful if you want to pre-warm the DNS cache on startup.
import { dns } from "bun";
// ...on startup
dns.prefetch("example.com");
// ...later on
await fetch("https://example.com/");
This will prefetch the DNS record for example.com
and make it available for use in fetch()
requests.
New: dns.getCacheStats()
API
To observe the DNS cache, you can use the new dns.getCacheStats()
API.
import { dns } from "bun";
console.log(dns.getCacheStats());
//
// {
// cacheHitsCompleted: 0,
// cacheHitsInflight: 0,
// cacheMisses: 0,
// size: 0,
// errors: 0,
// totalCount: 0,
// }
//
await fetch("https://example.com/");
console.log(dns.getCacheStats());
// {
// cacheHitsCompleted: 0,
// cacheHitsInflight: 0,
// cacheMisses: 1,
// size: 1,
// errors: 0,
// totalCount: 1,
// }
atob()
gets 8x faster
Thanks to @lemire's simdutf library, atob()
is now 8x faster in Bun.
In the next version of Bun
— Bun (@bunjavascript) May 15, 2024
atob() gets 8x faster, thanks to @lemire's simdutf library pic.twitter.com/5iL1zrZS5d
New: Added bytes()
API to Web streams
Bun now supports the bytes()
property on Web streams, which returns a Uint8Array
of the stream's data. This is available on Request
, Response
, Blob
, and Bun.file()
objects.
const response = await fetch("https://example.com/");
const bytes = await response.bytes();
console.log(bytes); // Uint8Array(1256) [ 60, 33, ... ]
bytes()
is a recent addition to the fetch()
standard.
Thanks to @nektro for implementing this feature!
New: bun --no-clear-screen --watch
You can now use bun --no-clear-screen
to disable the clearing of the screen when Bun is running in --watch
or --hot
mode. This is useful if you want to keep the terminal history after a file reloads.
In the next version of Bun
— Jarred Sumner (@jarredsumner) May 15, 2024
The "--no-clear-screen" flag disables clearing the terminal on --watch or --hot
left: --hot --no-clear-screen
right: --hot pic.twitter.com/TDsTcGx7hh
You can also configure this using the BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOAD
environment variable.
BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOAD=1 bun --watch src/index.ts
New: expect().toHaveReturned()
matchers
Bun now supports the expect().toHaveReturned()
and expect().toHaveReturnedTimes(n)
matchers, which are implemented by Jest.
import { expect } from "bun:test";
test("expect().toHaveReturned()", () => {
const fn = jest.fn(() => "foo");
fn();
expect(fn).toHaveReturned();
fn();
expect(fn).toHaveReturnedTimes(2);
});
This has now been added thanks to @nektro.
Sourcemap improvements
Bun now loads sourcemaps after bun build --target=bun --sourcemap
When you build for production with bun build --target=bun --sourcemap
, Bun will now load sourcemaps at runtime & use them to map stack traces to the original source code.
❯ bun out/sourca.js
1 | function mySource(hello: string) {
2 | throw new Error("woopsie!!");
^
error: woopsie!!
at mySource (/Users/jarred/Desktop/sourca.ts:2:9)
at /Users/jarred/Desktop/sourca.ts:5:1
Bun v1.1.9 (macOS arm64)
Previously:
❯ bun-1.1.8 out/sourca.js
1 | // @bun
2 | // sourca.ts
3 | var mySource = function(hello) {
4 | throw new Error("woopsie!!");
^
error: woopsie!!
at mySource (/Users/jarred/Desktop/out/sourca.js:4:9)
at /Users/jarred/Desktop/out/sourca.js:6:1
Bun v1.1.8 (macOS arm64)
Thanks to @paperdave.
Fixed: Sourcemaps off-by-24-bytes error
At runtime, Bun reserves the first 24 bytes of the internal source map buffer for metadata about the sourcemap.
This behavior was only meant to occur at runtime, but it was mistakenly enabled in bun build
too. This caused sourcemaps to be off by 24 bytes when using bun build --target=bun --sourcemap
.
This has now been fixed thanks to @paperdave.
Bundows improvements
Fixed: "Unexpected" reading junctions & symlinks in Windows
In the module resolver code, Bun thought that junctions and symlinks were regular files instead of directories. This caused issues when using monorepos on Windows or when using the pnpm
package manager with Bun.
The following code now works as expected on Windows:
import { version } from "lodash";
console.log(version); // 4.17.21
Previously:
error: Unexpected reading 'C:\\abcd\\node_modules\\lodash'
Thanks to @paperdave.
Fixed: Loading UNC paths in Windows
When a UNC path was used in various parts of Bun such as require("\\wsl.local\\path")
, it would fail with an assertion failure about storing posix paths in Windows. This assertion failure was an internal error in Bun, and has now been fixed.
This bug impacted:
bun install
bun run <file.ts>
bun <file.ts>
And more.
Thanks to @paperdave.
Node.js compatiblity improvements
Fixed: msw
seems to work now
We fixed a bug in node:http
where the statusCode
property was read-only, which could cause an error when trying to set the status code. This was done by packages, such as msw
, which now work in Bun.
import axios from "axios";
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
const server = setupServer(
...[
http.get("https://example.com/", () => {
return HttpResponse.json({ msw: "works!" });
}),
],
);
server.listen();
const response = await axios.get("https://example.com/");
console.log(response.data.msw); // "works!"
This has now been fixed thanks to @nektro.
New: Added shake128
and shake256
algorithms to node:crypto
Bun now supports the shake128
and shake256
algorithms in node:crypto
.
import { createHash } from "node:crypto";
const hash = createHash("shake256");
hash.update("hello");
console.log(hash.digest());
This has now been fixed thanks to @nektro.
buffer.toString("base64url")
gets 5x faster
Again, thanks to the simdutf library, toString("base64url")
is now 5x faster in Bun.
The fast JavaScript runtime Bun is going to get 5x faster base64 encoding (toString("base64url")).https://t.co/BO4PDSOgkS
— Daniel Lemire (@lemire) May 15, 2024
work by @jarredsumner
Relies on the simdutf library https://t.co/8L5xwdvzKs
Node.js already relies on simdutf for these tasks.
Fixed: http.Agent
not working without new
We fixed a bug where you could not construct an http.Agent
without using the new
keyword. Some older Node.js APIs, such as http.Agent
existed before JavaScript introduced classes, and so they did not require the new
keyword.
import { Agent } from "node:http";
const agent = Agent();
This has now been fixed thanks to @nektro.
Fixed: newListener
event is emitted in correct order
We fixed an issue where the newListener
event was being emitted in the wrong order, which could cause issues with some libraries. Previously, the newListener
event was emitted after the listener was added, but now it is emitted before the listener is added.
import { expect, mock } from "bun:test";
import { Stream } from "node:stream";
test("newListener event is emitted in correct order", () => {
const stream = new Stream();
const cb = mock((event) => {
expect(stream.listenerCount(event)).toBe(0);
});
stream.on("newListener", cb);
stream.on("foo", () => {});
expect(cb).toHaveBeenCalled();
});
Fixed: Improved argument parsing in net.connect()
We fixed various bugs where the argument parsing in net.connect()
would not match the behavior of Node.js. For example, when a port
and host
are provided, or only an options
object is provided, the port
and host
arguments would be ignored.
import { connect } from "node:net";
const socket = connect({
port: 443,
host: "localhost",
rejectUnauthorized: false,
});
socket.on("secureConnect", () => {
console.log("Connected!");
socket.end();
});
Fixed: Promisified child_process.execFile()
returned wrong value
We fixed a bug where the execFile()
function was not returning the correct value when using the util.promisify()
function.
import { execFile } from "node:child_process";
import util from "node:util";
const execFileAsync = util.promisify(execFile);
const result = await execFileAsync("ls");
console.log(result);
// Before: 'src\n'
// After: { stdout: 'src\n', stderr: '' }
Fixed: Crash using which
with long path
We fixed a bug where Bun.which()
would crash when given a long path. Instead of crashing, it now throws an error: bin path is too long
.
import { which } from "bun";
which("a".repeat(100000));
// Before: <crash>
// After: <error: bin path is too long>
Thanks to @zackradisic for fixing this issue.
Fixed: Alias debuglog
to debug
We fixed a bug where util.debuglog()
was not being aliased to util.debug()
. Thanks to @gaurishhs for fixing this issue.
import { debuglog } from "node:util";
debuglog("foo");
Fixed: fs.Dirent
now has path
& parentPath
properties
We fixed a bug where the path
property and the new parentPath
properties were not being set on fs.Dirent
objects. This could cause issues when using fs.Dirent
objects in conjunction with fs.readdir()
.
import { readdirSync } from "node:fs";
readdirSync("src").forEach((dirent) => {
console.log(dirent.path);
// Before: undefined
// After: 'src'
});
This has now been fixed thanks to @nektro.
Fixed: must be a number or a Date
We fixed a bug where certain APIs that interpret arguments as double would throw an error due to incorrect integer coercion.
import { utimesSync } from "node:fs";
const atime = Math.floor(Date.now() / 1000);
const mtime = Math.floor(Date.now() / 1000);
utimesSync("hello.txt", atime, mtime);
// Before: Error: Argument must be a number or a Date
// After: <no error>
This has now been fixed thanks to @dylan-conway.
Bun Shell improvements
Escaping more characters
We fixed bugs where special characters, such as |
, &
, and ;
, that need to be escaped when used in a shell, but were not being escaped.
bun shell 'echo "Hello, world!" | grep "world"'
# Hello, world!
bun shell 'echo "Hello, world!" | grep "world"'
# Hello, world!
Thanks to @zackradisic for fixing these issues.
Tilde expansion in Bun shell
The Bun shell now supports tilde expansion, which means you can use ~
(aka. tilde) to refer to your home directory. For example, ~/Documents
will expand to the path of $HOME/Documents
.
This is supported on all platforms, including Windows.
echo ~
# /Users/bun
echo ~/Documents
# /Users/bun/Documents
Thanks to @zackradisic for implementing this feature.
Fixed: cd
would return the wrong exit code
We fixed a bug where cd
would return the wrong exit code run in the Bun shell. This would happen when there was an error changing directories.
cd /not/a/directory
echo $?
0
Fixed: Crash when pasting very large input in argv0
A bug where pasting too large input into the first argument of the Bun shell would crash has been fixed.
bun exec ${"a".repeat(100_000_000)}
The bug was caused by a missing bounds check in which
. Operating systems have a maximum length of 512, 1024, or 4096 bytes for file paths and when that limit is exceeded Bun would crash.
This has now been fixed thanks to @zackradisic.