new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Bun · Bundler · all subjects

bun.build/macros

14 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Macros are bundle-time JavaScript functions

Macros are JavaScript functions that run at bundle-time. Their return values are inlined directly into your bundle. The source code of the macro function does not appear in the bundle; instead, it runs during bundling and the function call is replaced with its result.

Macro import syntax with type: macro

Macros are imported using import attribute syntax with either `with { type: 'macro' }` (Stage 3 ECMAScript proposal) or `assert { type: 'macro' }` (earlier incarnation, now abandoned but still supported). The import attribute syntax is the recommended approach.

Macros must be explicitly called to execute

Macros must be explicitly called with `{ type: 'macro' }` to run at bundle-time. These imports have no effect if they are not called, unlike regular JavaScript imports which may have side effects.

Disable macros with --no-macros flag

You can disable macros entirely with the `--no-macros` flag. When macros are disabled and attempted, it produces a build error with the message 'Macros are disabled'.

Macros cannot be invoked from node_modules

For security reasons, macros cannot be invoked from inside `node_modules/**/*`. If a package attempts to invoke a macro from node_modules, a build error is raised with the message 'For security reasons, macros cannot be run from node_modules.' However, application code can import macros from `node_modules` and invoke them.

Macro export condition in package.json

When shipping a library containing a macro to npm or another package registry, use the 'macro' export condition in package.json to provide a version of your package exclusively for the macro environment. Example: `"exports": { "import": "./index.js", "require": "./index.js", "default": "./index.js", "macro": "./index.macro.js" }`. With this configuration, users can consume the package at runtime or at bundle-time using the same import specifier.

Macro execution timing and order

Macros run synchronously in the transpiler during the visiting phase, before plugins and before the transpiler generates the AST. They run in the order they are imported. The transpiler waits for each macro to finish before continuing, and awaits any Promise a macro returns. Bun's bundler is multi-threaded, so macros execute in parallel in multiple spawned JavaScript workers.

Dead code elimination after macro inlining

The bundler performs dead code elimination after running and inlining macros. For example, if a macro returns false and it is used in an if statement, the dead code inside that if block is eliminated, provided that the minify syntax option is enabled.

Macro return value serializability requirements

Bun's transpiler must be able to serialize the result of the macro to inline it into the AST. All JSON-compatible data structures are supported, including objects, arrays, strings, numbers, and nested structures. Macros can be async or return Promise instances, which the transpiler awaits before inlining the result. Functions and instances of most classes (except Response and Blob) are not serializable.

Special serialization for Response and Blob

The transpiler implements special logic for serializing Response and Blob objects. For Response: Bun reads the Content-Type header and serializes accordingly—for example, a Response with type `application/json` is parsed into an object and `text/plain` is inlined as a string. Responses with unrecognized or undefined type are base64-encoded. For Blob: serialization depends on the `type` property in the same way.

Macro arguments must be statically known

Macros can accept inputs, but only in limited cases where the value is statically known at bundle-time. Values that cannot be statically known (such as results from Math.random() or runtime decisions) are not allowed as macro arguments. However, if the value is a constant or the result of another macro, it is allowed.

Embed git commit hash with macro example

Example macro that embeds the latest git commit hash: `export function getGitCommitHash() { const { stdout } = Bun.spawnSync({ cmd: ["git", "rev-parse", "HEAD"], stdout: "pipe", }); return stdout.toString(); }`. When imported with `with { type: "macro" }` and called, the function call is replaced with the actual commit hash string at bundle-time.

Fetch and parse HTML at bundle-time with macro example

Example macro that makes an HTTP request and parses HTML: `export async function extractMetaTags(url: string) { const response = await fetch(url); const meta = { title: "" }; new HTMLRewriter().on("title", { text(element) { meta.title += element.text; } }).on("meta", { element(element) { const name = element.getAttribute("name") || element.getAttribute("property") || element.getAttribute("itemprop"); if (name) meta[name] = element.getAttribute("content"); } }).transform(response); return meta; }`. When called at bundle-time, the fetch happens during bundling and the result is embedded in the bundle, with unreachable code eliminated.

Use macros for small bundle-time code

Macros are useful for small things you would otherwise write a one-off build script for. Bundle-time code execution with macros is easier to maintain because it lives with the rest of your code, runs with the rest of the build, is automatically parallelized, and if it fails, the build fails too. If you find yourself running a lot of code at bundle-time, consider running a server instead.

Give your agent this brain