Skip to content

Releases: oven-sh/bun

Bun v0.0.40

29 Oct 04:09
Compare
Choose a tag to compare

It's been a busy couple weeks.

Important: the bun-cli npm package is deprecated. It will not receive updates.

Please upgrade Bun by running:

# Remove the npm version of bun
npm uninstall -g bun-cli

# Install the new version
curl https://bun.sh/install | bash

For future upgrades:

bun upgrade

Now the fun part.

bun run

~35x faster package.json "scripts" runner, powered by Bun. Instead of npm run, try bun run.

Like npm run, bun run reads "scripts" in your package.json and runs the script in a shell with the same PATH changes as npm clients. Unlike npm clients, it's fast.

CleanShot 2021-10-28 at 19 29 21@2x

You can use bun run in projects that aren't using Bun for transpiling or bundling. It only needs a package.json file.

When scripts launch a Node.js process, bun run still beats npm run by 2x:

CleanShot 2021-10-28 at 19 37 43@2x

Why? Because npm clients launch an extra instance of Node.js. With npm run, you wait for Node.js to boot twice. With bun run, you wait once.

For maximum performance, if nested "scripts" run other npm tasks, bun run automatically runs the task with Bun instead. This means adding many tasks won't slow you down as much.

bun run supports lifecycle hooks you expect like pre and post and works when the package.json file is in a parent directory.

Two extra things:

  • bun run also adds any node_modules/.bin executables to the PATH, so e.g. if you're using Relay, you can do bun run relay-compiler and it will run the version of relay-compiler for the specific project.
  • bun run has builtin support for .env. It reads: .env.local, then .env.development || .env.production (respecting your NODE_ENV), and .env in the current directory or enclosing package.json's directory

Oh and you can drop the run:

CleanShot 2021-10-28 at 20 27 30@2x

Reliability

Lots of work went into improving the reliability of Bun over the last couple weeks.

Here's what I did:

  • Rewrote Bun's filesystem router for determinism and to support catch-all + optional-catch-all routes. This is an oversimplification, but the routes are sorted now
  • Improved testing coverage. Bun now has integration tests that check a simple Next.js app bundles & server-side prerenders successfully. If JavaScriptCore's JIT is not enabled while server-side rendering, the tests fail. Another integration test checks that a simple Create React App loads. It uses bun create to bootstrap the projects.
  • Fix all known unicode encoding & decoding bugs. Part of what makes parsing & printing JavaScript complicated is that JavaScript officially uses UTF-16 for strings, but the rest of the files on your computer likely use UTF-8. This gets extra complicated with server-side rendering because JavaScriptCore expects either a UTF-16 string for source code or a UTF-8 string. UTF-16 strings use about twice as much memory as UTF-8 strings. Instead of wasting memory, Bun escapes the strings where necessary (but only for server-side rendering)
  • Fixed several edgecases with the .env loader. .env values are now parsed as strings instead of something JSON-like

There's still a lot of work ahead, but Bun is getting better.

Sometimes, speed and reliability is a tradeoff. This time, it's not. Bun seems to be about 3% faster overall compared to the last version (v0.0.36). Why? Mostly due to many small changes to the lexer. Inlining iterators is good.

Bun v0.0.36

17 Oct 12:03
Compare
Choose a tag to compare

bun create

bun create is a new subcommand that lets you quickly create a project from a template.

this

To create a new React project (based on Create React App)

bun create react ./app

11x faster than yarn create react app on my Macbook Pro (both installing dependencies via yarn)

CleanShot 2021-10-15 at 23 37 07@2x

To create a new Next.js project (based on Create Next App)

bun create next ./app

To create from a GitHub repository:

bun create jarred-sumner/calculator calc

To see a list of templates:

bun create

Right now, there are only two "official" templates (and they're mostly empty) – but you can add more. bun create fetches from packages published in the examples folder of Bun's GitHub repo. PRs are very welcome!

CleanShot 2021-10-15 at 23 45 49@2x

Local templates

Many developers have boilerplate code copied for new projects.

That's why bun create also searches $HOME/.bun-create for local templates.

Add a folder with a package.json in $HOME/.bun-create/my-local-template and then you can run:

bun create my-local-template ./foo

This copies the contents of my-local-template, initializes a git repository, runs any preinstall steps, installs dependencies (if any exist), runs any postinstall steps and rewrites the name field in package.json to foo.

It uses the fastest system calls available for copying files. bun create copies files faster than cp. Here is a stupid microbenchmark

CleanShot 2021-10-17 at 05 00 12@2x

Performance

The slowest part is running your NPM client to install node_modules. The second slowest part is downloading the tarball from GitHub (or NPM if it's from Bun's examples folder). Third is git.

Other stuff

  • fetch now supports gzip
  • https support in fetch was completely rewritten to be more reliable. TLS is now powered by s2n-tls
  • fetch now supports Transfer-Encoding: chunked. It didn't before, which was embarrassing.
  • Set self to globalThis in Bun.js. This improves compatibility with some npm packages
  • There are two new test binaries in misctools/, tgz and fetch. tgz is like gunzip except harder to use and fetch is sort of like curl? These are really just to help me test some things in isolation from the rest of Bun

Bun v0.0.34

07 Oct 02:57
Compare
Choose a tag to compare

Features

Slightly better tsconfig.json handling:

  • jsxImportSource support – if you set jsxImportSource to "@emotion/react", JSX will auto-import from "@emotion/react/jsx-dev-runtime" instead of "react/jsx-dev-runtime"
  • jsxFragmentFactory support – this lets you override what <> transforms into. By default it's "Fragment", since <> becomes React.Fragment normally.
  • jsxFactory support – if you set jsxFactory to "h", when using the classic JSX runtime, it will run h instead of createElement

This makes it easier to use @emotion/react, preact, and other JSX runtimes with Bun.

Bug fixes

  • [fetch] Fix bug with HTTP request bodies for http (not https) requests
  • Fix JSX transform edgecase with static children to match Babel's behavior (static === children.length > 1)
  • Fix node_module resolver edgecase when resolving from the dev server (not bun bun) that happened when resolving workspace packages above the project root that expect dependencies from the project. This applied to pnpm

Other:

  • Add a small end-to-end test for emotion JSX
  • Add a small end-to-end test for React Context.Provider & Context.Consumer
  • Add analytics

Bun v0.0.32

05 Oct 03:59
Compare
Choose a tag to compare

Bug fixes

  • [Linux] Fix Bun failing to start when the system-installed version of ICU didn't match the dynamically linked version. The fix here is to statically link ICU. This unfortunately doubles the binary size of Bun on Linux
  • Fix running bun bun on a networked filesystem. This is particularly relevant to WSL. The normal posix C function for moving files doesn't work if the source file is on a different mounted filesystem than the target. This fix detects the error and attempts to use sendfile() so that it copies the file faster than it would by reading the memory manually.

Bun v0.0.29

04 Oct 10:51
Compare
Choose a tag to compare

5% end-to-end performance improvement by reducing allocations for Identifiers in the JavaScript/TypeScript parser.

image

Also, bun-cli wasn't installing on Linux correctly. Now it is!

Bun v0.0.28

04 Oct 06:34
Compare
Choose a tag to compare

Bun on Linux x64

Bun is now available for Linux x64. That includes a filesystem watcher leveraging inotify, Linux's API for watching files as well as macros and SSR/SSG.

When bundling 20 copies of Three.js on Linux x64, Bun performed:

  • 1.6x faster than esbuild
  • 13.5x faster than Parcel 2
  • 19.5x faster than Webpack (without babel-loader)

I have done very little work on optimizing Bun for Linux. I'm not satisfied with these numbers, but it's a start.

CleanShot 2021-10-03 at 23 06 06@2x

Bun uses the GOMAXPROCS to control concurrency despite not being written in Go because I didn't want to think about what to name the variable

The runs with GOMAXPROCS=1 are single-threaded runs.

Bun single-threaded performed 2.2x faster than esbuild single-threaded. The relative gap between single-threaded and concurrent performance implies there's room for improvement in Bun's concurrency code. This machine has 6 cores (nproc returns 12) and 64 GB of memory.

Other

  • Bun's installed binary is now about 28% smaller

Bun v0.0.27

01 Oct 07:14
Compare
Choose a tag to compare

Features

Relay GraphQL client

You can now use Facebook's Relay GraphQL framework with Bun via bun-macro-relay.

bun-macro-relay implements the Bun equivalent of babel-plugin-relay.

Input:

const query = graphql`
  query Bacon {
  }
`;

Output:

import Bacon from '__generated__/Bacon.graphql';
const query = Bacon;

This macro is implemented entirely in TypeScript - not in native code. For install instructions, head over to bun-macro-relay.

Automatically remap macros

// Instead of having to change every import like this:
import { css } from "@emotion/react";

// To this:
import { css } from "macro:bun-macro-emotion-react";

// Now you don't have to change your code
import { css } from "@emotion/react";

note: @emotion/react is not implemented yet!

To use this, add this to your package.json (and remove the comments):

  "bun": {
    "macros": {
      // "react-relay" is the import path to rewrite
      "react-relay": {
       // rewrite the "graphql" import to instead point to "bun-macro-relay/bun-macro-relay.tsx"
        "graphql": "bun-macro-relay/bun-macro-relay.tsx"
      }
    }
  },

Remapping this way only applies to macros. To rewrite imports otherwise, Bun will read paths from tsconfig.json or jsconfig.json.

Bug fixes

  • Fix edgecase with cjs -> esm interop runtime code when the ESM export was marked as not extensible
  • Fix potential infinite loop on calling macros
  • Fix incorrect jsxDEV transform when source feature flag is off and a runtime error occurs in a component being rendered
  • Fix dead-code elimination edgecase with call expressions
  • Fix edgecase with parsing .env containing very short strings

More macro features

  • <import> lets you inject an import statement into a module. It accepts default, which is the default import alias and you can pass a namespace object where the object maps the import names to their names in the current file
  • <id> lets you reference an import (and eventually, other symbols too)
  • <inject> will insert each child element to the module scope. This currently only works with <import>, but it will work with other statements eventually.

Here's an example:

  const importStmt = (
    <import default="MyImportName" path="foo/bar" />
  );

  return (
    <>
      <inject>{importStmt}</inject>
      <id to={importStmt.namespace.MyImportName} />
    </>
  );

Bun v0.0.26

28 Sep 04:53
Compare
Choose a tag to compare

Features

Bun Macro

Bun Macros are a simple way to move code snippets from runtime to build-time.

Use them for:

  • Zero runtime CSS-in-JS (or a little runtime, up to you)
  • GraphQL parsing
  • Static data fetching without a library (similar to Next.js' getStaticProps but from any file instead of just pages)
  • you can come up with more use cases

This API (and implementation) is very new and I want to hear feedback on what to change.

How to use macros:

  • Any import that starts with macro: is imported as a macro. Macros can be npm packages, local files, or anything else resolvable. These imports are always removed from the final output.
  • Imports must be a named import, and are matched against call expressions (function calls) and template literals. JSX props may be added in a future release

Here's a quick example of using a macro:

// This import won't exist at runtime!
import { matchInFile } from "macro:./matchInFile";

export const IPAddresses = () => (
  <div>
    <h2>recent ip addresses</h2>
    <div className="Lines">
      {/* matchInFile gets inlined into an array at compile time */}
      {matchInFile("access.log", /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}/).map(
        (ipAddress, index) => (
          <div className="Line" key={index}>
            {ipAddress}
          </div>
        )
      )}
    </div>
  </div>
);

The transpiled output looks something like this:

export const IPAddresses = () => jsx("div", {
    children: [
      jsx("h2", {
        children: ["recent ip addresses"]
      }, undefined, true, {}, this),
      jsx("div", {
        className: "Lines",
        children: [[
          "98.210.28.6",
          "192.99.4.168",
           // ... rest of the array 
       ].map((ipAddress, index) => jsx("div", {
          className: "Line",
          children: [ipAddress]
        }, index, true, {}, this))]
      }, undefined, true, {}, this)
 // ...rest of code
    ]
});

There are a few examples of how to write macros in https://github.com/Jarred-Sumner/bun/tree/main/examples/macros, but I will write more docs once I'm a little more confident that the API isn't going to change. Once I write macros for Relay and Emotion, I'll have a better sense for if this API is good enough or if there are changes to make.

I might change the import prefix from macro: to bun: because it's shorter and slightly faster to check (one u32 instead of a u32 and then a u16)

Credits

Bun Macros are inspired by babel-plugin-macros, which was Sunil Pai's idea. They're also sort of similar to Zig's comptime feature.

Bun.js

  • Bun.readFileAsBytes and Bun.readFile now accept an array of paths to join. Both of these are valid:

Option A:

Bun.readFile(Bun.cwd + "file.txt");

Option B:

Bun.readFile([Bun.cwd, "./text/", "file.txt"]);

Unlike Node.js' path.join, it's an explicit array instead of arguments because someday, we might want to add extra options to this function.

Bug fixes

  • Thanks @alexkuz for adding a check to the Makefile that necessary dependencies are installed prior to compiling Bun.
  • Fixed an occasional UTF-8 decoding bug in Response.text() (from fetch)
  • Fixed an edgecase in the URL parser where it would sometimes erroneously report the pathname as /
  • Fixed a typo in the error thrown when you pass a blank string to fetch
  • fetch now includes a User-Agent header by default. This is overridable, but it defaults to Bun.js v0.0.version-number

Bun v0.0.24

25 Sep 09:14
Compare
Choose a tag to compare

Bug fixes

  • Fix crash when both JSX automatic and JSX classic imports are automatically imported and unbundled
  • Fix lexing bug with the \f form feed character (used in Emotion & Styled Components)
  • Fix bug with resolving "browser" field in package.json. In some cases, it was resolving from the parent directory of the result instead of the browser scope.

Stability

  • Add integration test that checks styled-components renders successfully and no incorrect unicode characters are present in the style tag

Bun v0.0.23

25 Sep 07:49
Compare
Choose a tag to compare

Fix bug with JSX transform when using a key prop, a {...spread} prop and a callback function as a prop in the same element. Thank you @alexkuz for the repro