bun - bun-v0.0.83


To upgrade:

bun upgrade
Having trouble upgrading? You can also try the install script.
curl https://bun.sh/install | bash

Thanks to:

  • @kriszyp for tons of helpful feedback on how to improve Node-API support in bun
  • @evanwashere for the idea & name for the CFunction abstraction
  • @adaptive for replacing "wrangler@beta" with "wrangler" in the examples for bun add
  • @littledivy for adding a couple missing packages to the build instructions

bun:sqlite

bun:sqlite is a high-performance builtin SQLite module for bun.js.

It tends to be around 3x faster than the popular better-sqlite3 npm package

image

Note: in the benchmark I tweeted earlier, better-sqlite3 always returned arrays of arrays rather than arrays of objects, which was inconsistent with what bun:sqlite & deno's x/sqlite were doing

Usage

import { Database } from "bun:sqlite";

const db = new Database("mydb.sqlite");
db.run(
  "CREATE TABLE IF NOT EXISTS foo (id INTEGER PRIMARY KEY AUTOINCREMENT, greeting TEXT)"
);
db.run("INSERT INTO foo (greeting) VALUES (?)", "Welcome to bun!");
db.run("INSERT INTO foo (greeting) VALUES (?)", "Hello World!");

// get the first row
db.query("SELECT * FROM foo").get();
// { id: 1, greeting: "Welcome to bun!" }

// get all rows
db.query("SELECT * FROM foo").all();
// [
//   { id: 1, greeting: "Welcome to bun!" },
//   { id: 2, greeting: "Hello World!" },
// ]

// get all rows matching a condition
db.query("SELECT * FROM foo WHERE greeting = ?").all("Welcome to bun!");
// [
//   { id: 1, greeting: "Welcome to bun!" },
// ]

// get first row matching a named condition
db.query("SELECT * FROM foo WHERE greeting = $greeting").get({
  $greeting: "Welcome to bun!",
});
// [
//   { id: 1, greeting: "Welcome to bun!" },
// ]

There are more detailed docs in Bun's README

bun:sqlite's API is loosely based on @joshuawise's better-sqlite3

New in bun:ffi

CFunction lets you call native library functions from a function pointer.

It works like dlopen but its for cases where you already have the function pointer so you don't need to open a library. This is useful for:

  • callbacks passed from native libraries to JavaScript
  • using Node-API and bun:ffi together
 import {CFunction} from 'bun:ffi';

 const myNativeLibraryGetVersion: number | bigint = /* Somehow you got this function pointer */

 const getVersion = new CFunction({
   returns: "cstring",
   args: [],
   // ptr is required
   // this is where the function pointer goes!
   ptr: myNativeLibraryGetVersion,
 });
 getVersion();
 getVersion.close();

linkSymbols is like CFunction except for when there are multiple functions. It returns the same object as dlopen except ptr is required and there is no path

import { linkSymbols } from "bun:ffi";

const [majorPtr, minorPtr, patchPtr] = getVersionPtrs();

const lib = linkSymbols({
  // Unlike with dlopen(), the names here can be whatever you want
  getMajor: {
    returns: "cstring",
    args: [],

    // Since this doesn't use dlsym(), you have to provide a valid ptr
    // That ptr could be a number or a bigint
    // An invalid pointer will crash your program.
    ptr: majorPtr,
  },
  getMinor: {
    returns: "cstring",
    args: [],
    ptr: minorPtr,
  },
  getPatch: {
    returns: "cstring",
    args: [],
    ptr: patchPtr,
  },
});

const [major, minor, patch] = [
  lib.symbols.getMajor(),
  lib.symbols.getMinor(),
  lib.symbols.getPatch(),
];

new CString(ptr) should be a little faster due to using a more optimized function for getting the length of a string.

require.resolve()

Running require.resolve("my-module") in Bun.js will now resolve the path to the module. Previously, this was not supported.

In browsers, it becomes the absolute filepath at build-time. In node, it's left in without any changes.

Internally, Bun's JavaScript transpiler transforms it to:

// input:
require.resolve("my-module");

// output
import.meta.resolveSync("my-module");

You can see this for yourself by running bun build ./file.js --platform=bun

"node:module" module polyfill

Node's "module" module lets you create require functions from ESM modules.

Bun now has a polyfill that implements a subset of the "module" module.

Normally require() in bun transforms statically at build-time to an ESM import statement. That doesn't work as well for Node-API (napi) modules because they cannot be statically analyzed by a JavaScript parser (since they're not JavaScript).

For napi modules, bun uses a dynamic require function and the "module" module exports a way to create those using the same interface as in Node.js

import { createRequire } from "module";
// this also works:
//import {createRequire} from 'node:module';

var require = createRequire(import.meta.url);

require.resolve("my-module");

// dynamic require is supported for:
// - .json files
// - .node files (napi modules)
require("my-napi-module");

This is mostly intended for improving Node-API compatibility with modules loaded from ESM.

As an extra thing, you can also use require() this way for .json files.

Bun.Transpiler – pass objects to macros

Bun.Transpiler now supports passing objects to macros.

import { Transpiler } from "bun";
import { parseCookie } from "my-cookie-lib";
import { Database } from "bun:sqlite";

const transpiler = new Transpiler();
const db = new Database("mydb.sqlite");

export default {
  fetch(req) {
    const transpiled = transpiler.transformSync(
      `
import {getUser} from 'macro:./get-user';
export function Hello({name}) {
    return <div>Hello {name}</div>;
}

export const HelloCurrentUser = <Hello {...getUser()} />;
`,
      // passing contextual data to Bun.Transpiler
      {
        userId: parseCookie(req.headers.get("Cookie")).userId,
        db: db,
      }
    );
    return new Response(transpiled, {
      headers: { "Content-Type": "application/javascript" },
    });
  },
};

Then, in get-user.js:

// db, userId is now accessible in macros
export function getUser(expr, { db, userId }) {
  // we can use it to query the database while transpiling
  return db.query("SELECT * FROM users WHERE id = ? LIMIT 1").get(userId);
}

That inlines the returned current user into the JavaScript source code, producing output equivalent to this:

export function Hello({ name }) {
  return <div>Hello {name}</div>;
}

// notice that the current user is inlined rather than a function call
export const HelloCurrentUser = <Hello name="Jarred" />;

Bug fixes

  • Buffer.from(arrayBuffer, byteOffset, length) now works as expected (thanks to @kriszyp for reporting)

Misc

  • Receiving and sending strings to Node-API modules should be a little faster

Details

date
May 17, 2022, 4:23 a.m.
name
bun v0.0.83
type
Patch
👇
Register or login to:
  • 🔍View and search all bun releases.
  • 🛠️Create and share lists to track your tools.
  • 🚨Setup notifications for major, security, feature or patch updates.
  • 🚀Much more coming soon!
Continue with GitHub
Continue with Google
or