github oven-sh/bun bun-v0.0.79
bun v0.0.79

latest releases: bun-v1.1.34, bun-v1.1.33, bun-v1.1.32...
2 years ago

To upgrade:

bun upgrade
If you run into any issues with upgrading

Try running this:

curl https://bun.sh/install | bash

Highlights

  • "bun:ffi" is a new bun.js core module that lets you use third-party native libraries written in languages that support the C ABI (Zig, Rust, C/C++ etc). It's like a foreign function interface API but faster
  • Buffer (like in Node.js) is now a global, but the implementation is incomplete - see tracking issue. If you import "buffer", it continues to use the browser polyfill so this shouldn't be a breaking change
  • 2x faster TextEncoder & TextDecoder thanks to some fixes to the vectorization (SIMD) code
  • Faster TypedArray.from. JavaScriptCore's implementation of TypedArray.from uses the code path for JS iterators when it could instead use an optimized code path for copying elements from an array, like V8 does. I have filed an upstream bug with WebKit about this, but I expect to do a more thorough fix for this in Bun and upstream that. For now, Bun reuses TypedArray.prototype.set when possible
  • 17x faster Uint8Array.fill
  • Bun.Transpiler gets an API for removing & replacing exports
  • SHA512, SHA256, SHA128, and more are now exposed in the "bun" module and the Bun global. They use BoringSSL's optimized hashing functions.
  • Fixed a reliability bug with new Response(Bun.file(path))
  • Bun's HTTP server now has a stop() function. Before, there was no way to stop it without terminating the process 😆
  • @evanwashere expose mmap size and offset option
  • @jameslahm [node] Add more fs constants

The next large project for bun is a production bundler Tracking issue

New Contributors

bun:ffi

The "bun:ffi" core module lets you efficiently call native libraries from JavaScript. It works with languages that support the C ABI (Zig, Rust, C/C++, C#, Nim, Kotlin, etc).

Get the locally-installed SQLite version number:

import { dlopen, CString, ptr, suffix, FFIType } from "bun:ffi";

const sqlite3Path = process.env.SQLITE3_PATH || `libsqlite3.${suffix}`;
const {
  symbols: { sqlite3_libversion },
} = dlopen(sqlite3Path, {
  sqlite3_libversion: {
    returns: "cstring",
  },
});
console.log("SQLite version", sqlite3_libversion());

FFI is really exciting because there is no runtime-specific code. You don't have to write a Bun FFI module (that isn't a thing). Use JavaScript to write bindings to native libraries installed with homebrew, with your linux distro's package manager or elsewhere. You can also write bindings to your own native code.

FFI has a reputation of being slower than runtime-specific APIs like napi – but that's not true for bun:ffi.

image

Bun embeds a small C compiler that generates code on-demand and converts types between JavaScript & native code inline. A lot of overhead in native libraries comes from function calls that validate & convert types, so moving that to just-in-time compiled C using engine-specific implementation details makes that faster. Those C functions are called directly – there is no extra wrapper in the native code side of things.

Some bun:ffi usecases:

  • SQLite client
  • Skia bindings so you can use Canvas API in bun.js
  • Clipboard api
  • Fast ffmpeg recording/streaming
  • Postgres client (possibly)
  • Use Pythons "ndarray" package from JavaScript (ideally via ndarray's C API and not just embedding Python in bun)

Later (not yet), bun:ffi will be integrated with bun's bundler and that will enable things like:

  • Use hermes to strip Flow types for code transpiled in bun
  • .sass support

Buffer

A lot of Node.js' Buffer module is now implemented natively in Bun.js, but it's not complete yet.

Here is a comparison of how long various functions take.

image

Replace & eliminate exports with Bun.Transpiler

For code transpiled with Bun.Transpiler, you can now remove and/or replace exports with a different value.

const transpiler = new Bun.Transpiler({
  exports: {
    replace: {
      // Next.js does this
      getStaticProps: ["__N_SSG", true],
    },
    eliminate: ["localVarToRemove"],
  },
  treeShaking: true,
  trimUnusedImports: true,
});

const code = `
import fs from "fs";
export var localVarToRemove = fs.readFileSync("/etc/passwd");
import * as CSV from "my-csv-parser";

export function getStaticProps() {
  return {
    props: { rows: CSV.parse(fs.readFileSync("./users-list.csv", "utf8")) },
  };
}

export function Page({ rows }) {
  return (
    <div>
      <h1>My page</h1>
      <p>
        <a href="/about">About</a>
      </p>
      <p>
        <a href="/users">Users</a>
      </p>
      <div>
        {rows.map((columns, index) => (
          <span key={index}>{columns.join(" | ")} </span>
        ))}
      </div>
    </div>
  );
}
`;

console.log(transpiler.transformSync(code));

Which outputs (this is the automatic react transform)

export var __N_SSG = true;

export function Page({ rows }) {
  return jsxDEV("div", {
    children: [
      jsxDEV("h1", {
        children: "My page"
      }, undefined, false, undefined, this),
      jsxDEV("p", {
        children: jsxDEV("a", {
          href: "/about",
          children: "About"
        }, undefined, false, undefined, this)
      }, undefined, false, undefined, this),
      jsxDEV("p", {
        children: jsxDEV("a", {
          href: "/users",
          children: "Users"
        }, undefined, false, undefined, this)
      }, undefined, false, undefined, this),
      jsxDEV("div", {
        children: rows.map((columns, index) => jsxDEV("span", {
          children: [
            columns.join(" | "),
            " "
          ]
        }, index, true, undefined, this))
      }, undefined, false, undefined, this)
    ]
  }, undefined, true, undefined, this);
}

More new stuff

Hashing functions powered by BoringSSL:

import {
  SHA1,
  MD5,
  MD4,
  SHA224,
  SHA512,
  SHA384,
  SHA256,
  SHA512_256,
} from "bun";

// hash the string and return as a Uint8Array
SHA1.hash("123456");
MD5.hash("123456");
MD4.hash("123456");
SHA224.hash("123456");
SHA512.hash("123456");
SHA384.hash("123456");
SHA256.hash("123456");
SHA512_256.hash("123456");

// output as a hex string
SHA1.hash(new Uint8Array(42), "hex");
MD5.hash(new Uint8Array(42), "hex");
MD4.hash(new Uint8Array(42), "hex");
SHA224.hash(new Uint8Array(42), "hex");
SHA512.hash(new Uint8Array(42), "hex");
SHA384.hash(new Uint8Array(42), "hex");
SHA256.hash(new Uint8Array(42), "hex");
SHA512_256.hash(new Uint8Array(42), "hex");

// incrementally update the hashing function value and convert it at the end to a hex string
// similar to node's API in require('crypto')
// this is not wired up yet to bun's "crypto" polyfill, but it really should be
new SHA1().update(new Uint8Array(42)).digest("hex");
new MD5().update(new Uint8Array(42)).digest("hex");
new MD4().update(new Uint8Array(42)).digest("hex");
new SHA224().update(new Uint8Array(42)).digest("hex");
new SHA512().update(new Uint8Array(42)).digest("hex");
new SHA384().update(new Uint8Array(42)).digest("hex");
new SHA256().update(new Uint8Array(42)).digest("hex");
new SHA512_256().update(new Uint8Array(42)).digest("hex");

Reliability improvements

Don't miss a new bun release

NewReleases is sending notifications on new releases.