We're hiring systems engineers in San Francisco to build the future of JavaScript!
This release fixes 57 bugs (addressing 150 👍). Bun's CSS bundler is here (and very experimental). bun publish
is a drop-in replacement for npm publish
. bun build --bytecode
compiles to bytecode leading to 2x faster start time. Bun.color() formats and normalizes colors. bun pm whoami
prints your npm username. bun install
reads $HOME/.npmrc
. bun build --format=cjs
outputs CommonJS modules. bun build --target=node
now supports Node.js native addons. 30x faster crypto.privateEncrypt()
& crypto.publicDecrypt()
. Zombie process killer in bun test. --banner
and --footer
options in bun build
. Bun.serve().stop()
returns a promise. Bun.CryptoHasher
now supports HMAC. Bugfixes for node:zlib, node:module, and node:buffer. Lots more bugfixes and Node.js compatibility improvements
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
Experimental: CSS Parsing & bundling
Over the last two months, @zackradisic built a CSS parser and bundler for Bun.
It's based on @devongovett's excellent LightningCSS parser, rewritten from Rust to Zig to vertically integrate into Bun's JavaScript & TypeScript parser, bundler, and runtime.
You can try it out today via bun build
(CLI) or Bun.build
(API) with the --experimental-css
flag.
CSS bundling
Bun's CSS bundler concatenates multiple CSS files and any assets referenced via url
, @import
, @font-face
, etc into a single CSS file you can send to browsers, avoiding a waterfall of network requests.
@import "foo.css";
@import "bar.css";
To try it out with bun build
via CLI:
bun build --experimental-css ./index.css
Those two CSS files become a single bundled CSS file:
/** foo.css */
.foo {
background: red;
}
/** bar.css */
.bar {
background: blue;
}
Import .css files in JavaScript & TypeScript
Bun's CSS parser integrates with our JavaScript & TypeScript parser & bundler.
You can import .css files in JavaScript & TypeScript and an additional css entrypoint will be created that combines all the css files imported from a JavaScript/TypeScript module graph, along with any @import
rules.
import "./style.css";
import Component from "./MyComponent.tsx";
// ... rest of your app
Then, if MyComponent.tsx
imports a CSS file, instead of adding extra .css files to the bundle, all the CSS imported per entrypoint is flattened into a single CSS file.
bun build --experimental-css ./index.ts --outdir=dist
index.js 0.10 KB
index.css 0.10 KB
[5ms] bundle 4 modules
This outputs the following css file, which came from TypeScript imports:
/* style.css */
.hello {
background: red;
}
/* MyComponent.css */
.MyComponent {
color: green;
}
Bundle CSS with Bun.build
:
We've also added support for programmatically bundling CSS with the Bun.build
API. You can bundle both CSS and JavaScript in the same build with the same API.
import { build } from "bun";
const results = await build({
entrypoints: ["./index.css"],
outdir: "./dist",
experimentalCss: true,
});
console.log(results);
How fast can it parse & bundle CSS?
We will release benchmarks once it's more stable, but I think you will be satisfied with the performance.
Huge thanks to @zackradisic for building this, and for @devongovett for his excellent LightningCSS library.
bun publish
: drop-in replacement for npm publish
You can use bun to publish npm packages via bun publish
bun publish
bun publish v1.1.30 (ecad797a)
packed 108B package.json
packed 3B README.md
packed 19B index.js
Total files: 3
Shasum: abd73b91b21057f0b07a58472077f5a3bbfb3e89
Integrity: sha512-aWkWikXiSXyR[...]Ubll4PQcEEoNw==
Unpacked size: 130B
Packed size: 254B
Tag: latest
Access: default
Registry: http://localhost:4873
+ lodash-2@1.0.0
bun publish
is intended as a drop-in replacement for npm publish
, and supports many of the same features like:
- Reading .npmrc files for authentication
- Packing tarballs, accounting for
.gitignore
and.npmignore
files in multiple directories - OTP / Two-factor authentication
- Handling various edgecases with package.json fields like
"bin"
,"files"
, etc - Handling missing README files carefully
Additionally, when using workspaces, bun publish
will automatically rewrite dependency versions of workspace packages to point to the published version so that you can publish packages correctly that internally use workspace:
dependencies.
Thanks to @dylan-conway for implementing this!
bun pm whoami
The new bun pm whoami
command will print the current user's npm username.
bun pm whoami
bun
Thanks to @dylan-conway for implementing this!
Compile to bytecode for 2x faster startup time
bun build
now supports bundling JavaScript & TypeScript to bytecode for a 2x faster startup time.
bun build --bytecode --compile ./index.ts
Single-file bytecode executables
bun build --bytecode --compile makes eslint start 2x faster pic.twitter.com/kFQ1KUJj2Z
— Jarred Sumner (@jarredsumner) September 30, 2024
Bytecode bundles
You can also use this without --compile
if you would prefer individual files without the standalone executable.
bun build --bytecode --outdir=./dist ./index.ts
This will output .jsc
files alongside .js
files. These .jsc
contain the bytecode version of the file. Both are necessary to run in Bun, as the bytecode compilation doesn't currently compile async functions, generators, eval, and a handful of other edge cases.
The bytecode can be 8x larger than the source code, so this makes startup faster at a cost of increased disk space.
CommonJS bundle output format
bun build
now supports --format=cjs
to output CommonJS bundles. Preivously, only --format=esm
was supported.
This makes it easier to use bun build
to build libraries & applications meant for Node.js in situations where CommonJS modules are easier to work with.
bun build --format=cjs index.js
// index.js
export default "Hello, world!";
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __moduleCache = /* @__PURE__ */ new WeakMap;
var __toCommonJS = (from) => {
var entry = __moduleCache.get(from), desc;
if (entry)
return entry;
entry = __defProp({}, "__esModule", { value: true });
if (from && typeof from === "object" || typeof from === "function")
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
get: () => from[key],
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
}));
__moduleCache.set(from, entry);
return entry;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, {
get: all[name],
enumerable: true,
configurable: true,
set: (newValue) => all[name] = () => newValue
});
};
// index.js
var exports_site = {};
__export(exports_site, {
default: () => site_default
});
module.exports = __toCommonJS(exports_site);
var site_default = "Hello, world!";
Zombie process killer in bun test
On Linux and macOS, when a spawned process is not waited on, it's called a "zombie process".
Bun now automatically kills zombie processes from test timeouts in bun test
.
When a test that spawns process(es) times out in bun test
, if the process is not accessible outside of the test, then you would end up with a process that potentially never gets cleaned up if bun test
were to exit soon after. This was especially noticable with tools like Puppeteer that spawn a browser instance. Lingering Chromium processes can cost you 100s of MBs of RAM and cause all sorts of issues.
Bun now internally tracks all processes spawned inside tests and if a test times out, Bun will automatically kill the process.
Bundle .node
files with --target=node
You can now bundle Node.js native modules using Bun and run those Node.js native modules in Node.js.
We fixed a bug that prevented --target=node
from correctly bundling .node
files, which are Node.js native modules. Previously, this was only supported with --target=bun
, and now it's supported with --target=node
as well.
--banner and --footer options in bun build
You can now add a banner and footer above and below bundled output with --banner
and --footer
options in bun build
and Bun.build
.
Input:
bun build --banner "/* Hello, world! */" --footer "/* Goodbye! */" index.ts
await Bun.build({
entrypoints: ["./index.ts"],
outdir: "./dist",
banner: "/* Hello, world! */",
footer: "/* Goodbye! */",
});
Output:
/**
* Hello, world!
*/
export default "Hello, world!";
/**
* Goodbye!
*/
Huge thanks to @versecafe for implementing this!
--registry
flag in bun install
You can now specify a custom registry from the command line when installing packages with bun install
. You can use this flag by itself or with packages you want to add to your project.
# Install packages from a custom local registry instead of the default npm registry.
bun install --registry=http://localhost:4873/
# With packages
bun install zod --registry=http://localhost:4873/
You can continue to set the registry in .npmrc
files, bunfig.toml
, or via NPM_CONFIG_REGISTRY
environment variable. This extra CLI flag is useful if you want to globally install a package from a private registry without having to set the registry in your .npmrc
file or use a scoped package name.
Bun.color() formats and normalizes colors
In the next version of Bun
— zack (in SF) (@zack_overflow) September 26, 2024
Bun.color(input, outputFormat) leverages Bun's new CSS parser to parse, normalize, and convert colors into a variety of formats pic.twitter.com/ffULyAVxHb
stop()
in Bun.serve() returns a Promise
Bun's HTTP server API Bun.serve()
now returns a Promise from server.stop()
which resolves when all connections are closed.
This lets you use await server.stop()
to wait for all the connections to close without abruptly closing them.
const server = Bun.serve({
port: 3000,
async fetch(req) {
return new Response("Hello, world!");
},
});
await server.stop();
HMAC in Bun.CryptoHasher
Bun.CryptoHasher
can now be used to compute HMAC digests. To do so, pass the key to the constructor.
import { CryptoHasher } from "bun";
const hasher = new CryptoHasher("sha1", "secret-key");
const hash = hasher
.update("message")
// This creates the HMAC signature
.digest("hex");
console.log(hash); // 48de2656eac2c9c21b04faeec4f1be9672ef53c1
bun install reads $HOME/.npmrc now
bun install
now reads $HOME/.npmrc
files for authentication if no other registry is specified.
Previously, only .npmrc
in the current directory was read. Now, $HOME/.npmrc
is also read if no .npmrc
is found in the current package.json directory.
Thanks to @robertshuford for implementing this!
Bundler fixes
Fixed: top-level await
bug in bun build
A bug that could cause spurious top-level await
errors in bun build
has been fixed, thanks to @snoglobe!
Fixed: importing JSON with unicode characters in bun build
Importing JSON with unicode characters now works correctly with bun build
. Bun was previously incorrectly converting the encoding of strings from JSON, causing unicode characters to be interpreted in the wrong encoding.
// test.json
{
"测试a": "b"
}
// test.js
import data from "./test.json";
console.log(data["测试" + "a"]); // b
Thanks to @snoglobe!
Node.js compatibility improvements
30x faster crypto.privateEncrypt() & crypto.publicDecrypt()
crypto.privateEncrypt()
and crypto.publicDecrypt()
in Bun are now powered by BoringSSL, which leads to a 30x performance improvement to these functions over the previous JavaScript polyfill implementation.
After:
benchmark time (avg) (min … max) p75 p99 p999
----------------------------------------------------------------------------- -----------------------------
RSA sign RSA_PKCS1_PADDING round-trip 832 µs/iter (816 µs … 915 µs) 834 µs 893 µs 915 µs
Before:
benchmark time (avg) (min … max) p75 p99 p999
----------------------------------------------------------------------------- -----------------------------
RSA sign RSA_PKCS1_PADDING round-trip 26'997 µs/iter (26'657 µs … 27'551 µs) 27'119 µs 27'551 µs 27'551 µs
Thanks to @wpaulino for the fix!
require("cluster")
gets 6ms faster
The time it takes to require("cluster")
has been reduced by 6ms, thanks to @nektro
Previously:
bun-1.1.29 --print 'console.time("require(`cluster`)");require(`cluster`);console.timeEnd("require(`cluster`)");' # Old
[7.62ms] require(`cluster`)
Now:
bun --print 'console.time("require(`cluster`)");require(`cluster`);console.timeEnd("require(`cluster`)");' # New
[1.39ms] require(`cluster`)
Fixed: Buffer.alloc bug with 2nd argument bug
A bug when Buffer.alloc was passed an empty string as the second argument has been fixed.
Thanks to @nektro for the fix!
Fixed: Several node:zlib issues
Bun's node:zlib implementation now passes many more Node.js tests, thanks to @nektro! This addresses issues with Sharp/Jimp, Zip.js, some GPRC libraries, pubnub, and more.
Thanks to @nektro for the fix!
Fixed: Prisma not waiting for promises before exiting
A bug in our NAPI implementation could cause Prisma to not wait for promises in queries before the Bun process exits.
Thanks to @190n for the fix!
Fixed: Missing exports in node:module
A handful of missing exports in node:module
have been added:
_preloadModules
was previously undefined. Now it does nothing_debug
&_pathCache
was previouslyundefined
enableCompileCache
andgetCompileCache
were previously undefined__resolveFilename
and_resolveFilename
were previously both defined, now only_resolveFilename
is defined
Fixed: console.log on require.cache
Previously, console.log(require.cache)
would print an empty object. Now it prints the cache.
// Old
{}
// New
{
"/path/to/module": Module {
id: "/path/to/module",
exports: {},
parent: null,
filename: "/path/to/module.js",
loaded: false,
children: [],
paths: []
}
}
Fixed: process.cwd()
returning the wrong path on Windows for the root of a drive
A regression has been fixed where process.cwd()
would return an incorrect path on Windows if the current working directory was at the root of a drive. For example, if the current working directory was C:\
, process.cwd()
would return C:
instead of C:\
.
Fixed: 2 rare crashes in Bun.spawn()
Two rare crashes in Bun.spawn()
have been fixed. One was a regression from Bun v1.1.25. It sometimes happened when the subprocess was garbage collected before referencing stdin in certain cases.
Prototype pollution mitigation
To make prototype pollution more difficult to exploit in Bun's APIs, Bun APIs now ignore the Object
prototype when reading values from objects and functions in natively implemented Bun APIs (such as fetch
, Request
, Response
, etc).
Previously, the following code would cause glob.scanSync
to follow symlinks:
import { Glob } from "bun";
const glob = new Glob("*.ts");
Object.defineProperty(Object.prototype, "followSymlinks", {
value: true,
writable: true,
configurable: true,
enumerable: true,
});
const second = glob.scanSync({
cwd: path.join(dir, "abc"),
onlyFiles: true,
});
Now, since the Object.prototype
is ignored, this attack is mitigated. We've done this for nearly all Bun APIs implemented in Zig.
This doesn't fully prevent prototype pollution attacks, but it does make them more difficult to exploit in Bun APIs. Thanks to @lirantal for the report!
Fixed: bun add
incorrectly adding relative paths to tarballs in workspaces
A bug was fixed causing bun add
to fail to add local tarball packages to workspaces. This would happen because bun was using the workspace root as the base path rather than the current workspace package the tarball would be added to.