diff --git a/docs/bundler/esbuild.mdx b/docs/bundler/esbuild.mdx index 04ef6295c6c9..cfffe2397d92 100644 --- a/docs/bundler/esbuild.mdx +++ b/docs/bundler/esbuild.mdx @@ -48,7 +48,7 @@ In Bun's CLI, boolean flags like `--minify` take no argument. Flags that take on | `--packages` | `--packages` | No differences | | `--platform` | `--target` | Renamed to `--target` for consistency with tsconfig. Does not support `neutral`. | | `--serve` | n/a | Not applicable | -| `--sourcemap` | `--sourcemap` | No differences | +| `--sourcemap` | `--sourcemap` | Supports `linked` (the default when no value is given), `external`, `inline`, and `none`. Does not support esbuild's `both`. | | `--splitting` | `--splitting` | No differences | | `--target` | n/a | Not supported. Bun's bundler performs no syntactic down-leveling. | | `--watch` | `--watch` | No differences | diff --git a/docs/bundler/executables.mdx b/docs/bundler/executables.mdx index 34271402ef21..c16a29d5512b 100644 --- a/docs/bundler/executables.mdx +++ b/docs/bundler/executables.mdx @@ -757,10 +757,12 @@ import styles from "./styles.css" with { type: "file" }; import { file, serve } from "bun"; serve({ + // Inside the compiled executable, file() on an embedded path returns an + // in-memory Blob, which routes only accepts wrapped in a Response. routes: { - "/favicon.ico": file(favicon), - "/logo.png": file(logo), - "/styles.css": file(styles), + "/favicon.ico": new Response(file(favicon)), + "/logo.png": new Response(file(logo)), + "/styles.css": new Response(file(styles)), }, fetch(req) { return new Response("Not found", { status: 404 }); @@ -875,7 +877,7 @@ const html = await Bun.file(path.join(publicDir, "index.html")).text(); Pass `--asset` multiple times to embed several directories (for example `--asset ./client --asset ./prerendered` for a SvelteKit build). Bun embeds only regular files; it skips symlinks and empty subdirectories inside the tree. -You can also embed individual files via the `with { type: "file" }` import attribute or by adding them as extra entry points. Bun renames imported assets according to `--asset-naming` (default `[name]-[hash].[ext]`): +You can also embed individual files via the `with { type: "file" }` import attribute or, for files that use the `file` loader (images, fonts, and so on) as well as `.wasm` and `.node` files, by adding them as extra entry points. Bun renames imported assets according to `--asset-naming` (default `[name]-[hash].[ext]`): ```ts import icon from "./public/assets/icon.png" with { type: "file" }; diff --git a/docs/bundler/fullstack.mdx b/docs/bundler/fullstack.mdx index 4be000e385fc..c5a45619d6a8 100644 --- a/docs/bundler/fullstack.mdx +++ b/docs/bundler/fullstack.mdx @@ -29,7 +29,7 @@ const server = serve({ }, async POST(req) { const { name, email } = await req.json(); - const [user] = await sql`INSERT INTO users (name, email) VALUES (${name}, ${email})`; + const [user] = await sql`INSERT INTO users (name, email) VALUES (${name}, ${email}) RETURNING *`; return Response.json(user); }, }, diff --git a/docs/bundler/hot-reloading.mdx b/docs/bundler/hot-reloading.mdx index ec924c89752c..d38a09a1a2ef 100644 --- a/docs/bundler/hot-reloading.mdx +++ b/docs/bundler/hot-reloading.mdx @@ -131,12 +131,12 @@ Indicates that a dependency's module can be accepted. When the dependency is upd ```ts title="index.ts" icon="/icons/typescript.svg" import.meta.hot.accept(["./foo", "./bar"], newModules => { - // newModules is an array where each item corresponds to the updated module - // or undefined if that module had a syntax error + // newModules holds the updated module at its index and + // undefined for the other dependencies }); ``` -This variant accepts an array of dependencies. The callback receives the updated modules, and `undefined` for any that had errors. +This variant accepts an array of dependencies. The callback receives an array with the updated module at its index and `undefined` for the other dependencies. ## import.meta.hot.data diff --git a/docs/bundler/index.mdx b/docs/bundler/index.mdx index aff65ac225ea..0857c513072c 100644 --- a/docs/bundler/index.mdx +++ b/docs/bundler/index.mdx @@ -507,10 +507,12 @@ When `true`, the bundler enables code splitting. When multiple entrypoints impor ```ts entry-a.ts icon="/icons/typescript.svg" import { shared } from "./shared.ts"; +console.log(shared); ``` ```ts entry-b.ts icon="/icons/typescript.svg" import { shared } from "./shared.ts"; +console.log(shared); ``` ```ts shared.ts icon="/icons/typescript.svg" @@ -538,7 +540,7 @@ To bundle `entry-a.ts` and `entry-b.ts` with code-splitting enabled: -Running this build results in the following files: +Running this build with the JavaScript API results in the following files: ```text title="file system" icon="folder-tree" . @@ -548,10 +550,10 @@ Running this build results in the following files: └── out ├── entry-a.js ├── entry-b.js - └── chunk-2fce6291bf86559d.js + └── chunk-dqmx6gc8.js ``` -The generated `chunk-2fce6291bf86559d.js` file contains the shared code. To avoid collisions, the file name includes a content hash by default. Customize this with [`naming`](#naming). +The generated `chunk-dqmx6gc8.js` file contains the shared code. To avoid collisions, the file name includes a content hash by default. The `bun build` CLI names this chunk `entry-a-t268ez5g.js` instead of `chunk-.js`. Customize this with [`naming`](#naming). ### plugins @@ -1099,7 +1101,7 @@ var logo = "https://cdn.example.com/logo-a7305bdef.svg"; ### define -A map of global identifiers to be replaced at build time. Keys of this object are identifier names, and values are JSON strings, identifiers, or property paths that are inlined. +A map of global identifiers to be replaced at build time. Keys of this object are identifiers or dotted property paths such as `process.env.NODE_ENV`, and values are JSON strings, identifiers, or property paths that are inlined. diff --git a/docs/bundler/macros.mdx b/docs/bundler/macros.mdx index c65ee91eb29d..c4becbccb82a 100644 --- a/docs/bundler/macros.mdx +++ b/docs/bundler/macros.mdx @@ -112,7 +112,7 @@ The first import resolves to `./node_modules/my-package/index.js`; Bun's bundler When Bun's transpiler sees a macro import, it calls the function using Bun's JavaScript runtime and converts the return value into an AST node. -Macros run synchronously in the transpiler during the visiting phase, after the transpiler parses the file into an 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. +Macros run synchronously in the transpiler during the visiting phase, after the transpiler parses the file into an AST. They run in the order their calls appear in the file; the transpiler does not load or run a macro module until it reaches a call to one of its exports. 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". diff --git a/docs/bundler/minifier.mdx b/docs/bundler/minifier.mdx index 992754412a86..3f5c0a58a971 100644 --- a/docs/bundler/minifier.mdx +++ b/docs/bundler/minifier.mdx @@ -685,15 +685,15 @@ function calculateSum(firstNumber, secondNumber) { ``` ```js Output -function a(b,c){const d=b+c;return d} +function n(t,u){const c=t+u;return c} ``` **Naming strategy:** -- Most frequently used identifiers get the shortest names (a, b, c...) -- Single letters: a-z (26 names) -- Double letters: aa-zz (676 names) -- Triple letters and beyond as needed +- Most frequently used identifiers get the shortest names; Bun orders the alphabet by how often each character appears in the source, so the first names are usually letters like t, e and n rather than a, b, c +- Single characters: a-z, A-Z and `_` (53 names; `$` alone is reserved) +- Two characters: the second character can also be a digit (up to 3,456 names) +- Three characters and beyond as needed **Preserved identifiers:** diff --git a/docs/bundler/plugins.mdx b/docs/bundler/plugins.mdx index 80d514931756..3b2f4e5b9612 100644 --- a/docs/bundler/plugins.mdx +++ b/docs/bundler/plugins.mdx @@ -109,16 +109,18 @@ onStart(callback: () => void | Promise): void; Registers a callback that runs when the bundler starts a new bundle. ```ts title="index.ts" icon="/icons/typescript.svg" -import { plugin } from "bun"; - -plugin({ - name: "onStart example", - - setup(build) { - build.onStart(() => { - console.log("Bundle started!"); - }); - }, +await Bun.build({ + entrypoints: ["./app.ts"], + plugins: [ + { + name: "onStart example", + setup(build) { + build.onStart(() => { + console.log("Bundle started!"); + }); + }, + }, + ], }); ``` @@ -234,7 +236,8 @@ import type { BunPlugin } from "bun"; const envPlugin: BunPlugin = { name: "env plugin", setup(build) { - build.onLoad({ filter: /env/, namespace: "file" }, args => { + build.onResolve({ filter: /^env$/ }, () => ({ path: "env", namespace: "env" })); + build.onLoad({ filter: /.*/, namespace: "env" }, args => { return { contents: `export default ${JSON.stringify(process.env)}`, loader: "js", diff --git a/docs/guides/ecosystem/neon-serverless-postgres.mdx b/docs/guides/ecosystem/neon-serverless-postgres.mdx index 1003df08f670..186175f350fa 100644 --- a/docs/guides/ecosystem/neon-serverless-postgres.mdx +++ b/docs/guides/ecosystem/neon-serverless-postgres.mdx @@ -38,7 +38,7 @@ const sql = neon(process.env.DATABASE_URL!); const rows = await sql`SELECT version()`; -console.log(rows[0].version); +console.log(rows[0]?.version); ``` --- diff --git a/docs/guides/test/todo-tests.mdx b/docs/guides/test/todo-tests.mdx index 5b6ef8488789..161996e263a7 100644 --- a/docs/guides/test/todo-tests.mdx +++ b/docs/guides/test/todo-tests.mdx @@ -7,10 +7,10 @@ mode: center To remind yourself to write a test later, use the `test.todo` function. An implementation isn't required. ```ts test.test.ts icon="/icons/typescript.svg" -import { test, expect } from "bun:test"; +import { test } from "bun:test"; // write this later -test.todo("unimplemented feature"); +test.todo("parses durations like 1h30m"); ``` --- @@ -23,29 +23,34 @@ bun test ```txt test.test.ts: -✎ unimplemented feature +✎ parses durations like 1h30m 0 pass 1 todo 0 fail -Ran 1 test across 1 file. [74.00ms] +Ran 1 test across 1 file. [6.00ms] ``` --- -You can provide a test implementation. +You can also write the test before the code it tests exists. Here `parseDuration` is still a stub, and the todo test records what it should eventually do. `bun test` reports this test as `todo` too, without running its body. -```ts +```ts test.test.ts icon="/icons/typescript.svg" import { test, expect } from "bun:test"; -test.todo("unimplemented feature", () => { - expect(Bun.isAwesome()).toBe(true); +// Not written yet; the todo test below says what it should do. +function parseDuration(input: string): number { + throw new Error("not implemented"); +} + +test.todo("parses durations like 1h30m", () => { + expect(parseDuration("1h30m")).toBe(5400); }); ``` --- -Bun doesn't run the implementation unless you pass the `--todo` flag. With `--todo`, the test runs and is _expected to fail_. If a todo test passes, `bun test` returns a non-zero exit code. +Pass `--todo` to run the bodies of todo tests. A todo test is _expected to fail_: while `parseDuration` is unimplemented, Bun prints the error, still counts the test as `todo`, and exits with code `0`. ```sh terminal icon="terminal" bun test --todo @@ -53,12 +58,36 @@ bun test --todo ```txt test.test.ts: -✗ unimplemented feature +1 | import { test, expect } from "bun:test"; +2 | +3 | // Not written yet; the todo test below says what it should do. +4 | function parseDuration(input: string): number { +5 | throw new Error("not implemented"); + ^ +error: not implemented + at parseDuration (/path/to/test.test.ts:5:36) + at (/path/to/test.test.ts:9:10) +✎ parses durations like 1h30m [0.16ms] + + 0 pass + 1 todo + 0 fail +Ran 1 test across 1 file. [5.00ms] +``` + +--- + +Once you implement `parseDuration` and the body passes, `bun test --todo` reports the test as a failure and exits with a non-zero code. That is the signal to remove `.todo` and turn it into a regular test. + +```txt +test.test.ts: +✗ parses durations like 1h30m [0.19ms] ^ this test is marked as todo but passes. Remove `.todo` if tested behavior now works 0 pass 1 fail 1 expect() calls +Ran 1 test across 1 file. [5.00ms] $ echo $? 1 # this is the exit code of the previous command ``` diff --git a/docs/pm/cli/install.mdx b/docs/pm/cli/install.mdx index 1815c609092a..bdf55958b896 100644 --- a/docs/pm/cli/install.mdx +++ b/docs/pm/cli/install.mdx @@ -488,7 +488,7 @@ rm -rf node_modules bun install --backend copyfile ``` -**`symlink`** is typically only used for `file:` dependencies internally. To prevent infinite loops, it skips symlinking the `node_modules` folder. +**`symlink`** is typically only used for `file:` dependencies internally (for example `file:../foo` and transitive `file:` dependencies). `link:` dependencies do not use this backend; Bun installs them as a single symlink to the linked directory. If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own node_modules folder or you pass `--preserve-symlinks` to `node` or `bun`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks). diff --git a/docs/pm/global-cache.mdx b/docs/pm/global-cache.mdx index 9016e8568c0b..4fb5fe4b5cff 100644 --- a/docs/pm/global-cache.mdx +++ b/docs/pm/global-cache.mdx @@ -58,7 +58,7 @@ Configure this with the `--backend` flag, which all of Bun's package management - **`clonefile`**: Default on macOS. - **`clonefile_each_dir`**: Similar to `clonefile`, except it clones each file individually per directory. It is only available on macOS and tends to perform slower than `clonefile`. - **`copyfile`**: The fallback used when any of the above fail. It is the slowest option. On macOS, it uses `fcopyfile()`; on Linux it uses `copy_file_range()`. -- **`symlink`**: Used only for `file:` dependencies. To prevent infinite loops, it skips symlinking the `node_modules` folder. +- **`symlink`**: Symlinks each file instead of copying it. Only hoisted installs use it: `--backend=symlink` applies it to every package (macOS and Linux; Windows ignores the flag); without the flag, Bun uses it only for `file:` dependencies outside the project directory (for example `file:../foo`) and for transitive `file:` dependencies. If you install with `--backend=symlink`, Node.js doesn't resolve node_modules of dependencies unless each dependency has its own `node_modules` folder or you pass `--preserve-symlinks` to `node`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks). diff --git a/docs/pm/isolated-installs.mdx b/docs/pm/isolated-installs.mdx index 2568b08ce2a4..c34d0cdf3c26 100644 --- a/docs/pm/isolated-installs.mdx +++ b/docs/pm/isolated-installs.mdx @@ -214,7 +214,7 @@ rm -rf node_modules pnpm-lock.yaml bun install --linker isolated ``` -The main difference is that Bun keeps its store inside the project's `node_modules/.bun/` by default, while pnpm uses a global store with symlinks. With [`install.globalStore`](#global-virtual-store) enabled, Bun uses a global store as well. +The layouts are close: Bun hardlinks (clones on macOS) packages from its [global cache](/pm/global-cache) into a per-project store, `node_modules/.bun/`, and symlinks top-level `node_modules` entries into it. With [`install.globalStore`](#global-virtual-store) enabled, those store entries become symlinks into a global virtual store instead. ## When to use isolated installs diff --git a/docs/project/bindgen.mdx b/docs/project/bindgen.mdx index aeb3f29dfa14..7593fe0f2ab4 100644 --- a/docs/project/bindgen.mdx +++ b/docs/project/bindgen.mdx @@ -64,9 +64,11 @@ declare function add(a: number, b: number = -1): number; The code generator emits a C++ thunk that validates and coerces the JS arguments, then calls the Rust implementation. On the Rust side bindgen emits -nothing: the matching module is hand-written in -`src/jsc/bindings/GeneratedBindings.rs` and is reachable as -`crate::r#gen::` (for `bindgen_test.bind.ts`, that's +nothing; both the dispatch shim the thunk calls +(`bindgen_Bindgen_test_dispatchAdd1` in `src/runtime/hw_exports.rs`, which +calls `add`) and the `create_*_callback` module in +`src/jsc/bindings/GeneratedBindings.rs` are hand-written. The module is +reachable as `crate::r#gen::` (for `bindgen_test.bind.ts`, that's `crate::r#gen::bindgen_test`). To construct a `JSFunction` wrapping the native implementation, use `generated::create_add_callback(global)`: @@ -77,7 +79,8 @@ let js_fn: JSValue = generated::create_add_callback(global); ``` In JS files in `src/js/`, `$bindgenFn("bindgen_test.bind.ts", "add")` returns -a handle to the implementation. +a handle to the implementation, through a hand-written +`js2native_bindgen__` export in `src/runtime/hw_exports.rs`. Exported bindgen functions are snake_cased on the Rust side (`requiredAndOptionalArg` → `required_and_optional_arg`). The hand-written diff --git a/docs/project/license.mdx b/docs/project/license.mdx index 526b9861b773..67dc787c9943 100644 --- a/docs/project/license.mdx +++ b/docs/project/license.mdx @@ -29,7 +29,7 @@ Bun statically links these libraries: | [`brotli`](https://github.com/google/brotli) | MIT | | [`libarchive`](https://github.com/libarchive/libarchive) | [several licenses](https://github.com/libarchive/libarchive/blob/master/COPYING) | | [`lol-html`](https://github.com/cloudflare/lol-html/tree/master/c-api) | BSD 3-Clause | -| [`ls-hpack`](https://github.com/litespeedtech/ls-hpack) | MIT | +| [`ls-hpack`](https://github.com/litespeedtech/ls-hpack) | MIT (bundled xxhash is BSD 2-Clause) | | [`ls-qpack`](https://github.com/litespeedtech/ls-qpack) | MIT | | [`lsquic`](https://github.com/litespeedtech/lsquic) | MIT (portions derived from Chromium proto-quic, BSD 3-Clause) | | [`mimalloc`](https://github.com/microsoft/mimalloc) | MIT | @@ -45,7 +45,7 @@ Bun statically links these libraries: | [`libuv`](https://github.com/libuv/libuv) (on Windows) | MIT | | [`libdeflate`](https://github.com/ebiggers/libdeflate) | MIT | | [`libjpeg-turbo`](https://github.com/libjpeg-turbo/libjpeg-turbo) | BSD 3-Clause / IJG / zlib | -| [`libspng`](https://github.com/randy408/libspng) | BSD 2-Clause | +| [`libspng`](https://github.com/randy408/libspng) | BSD 2-Clause (portions derived from libpng, PNG Reference Library License v2) | | [`libwebp`](https://github.com/webmproject/libwebp) | BSD 3-Clause | | [`highway`](https://github.com/google/highway) | Apache 2.0 | | [`HdrHistogram_c`](https://github.com/HdrHistogram/HdrHistogram_c) | dual-licensed under CC0 1.0 or the BSD 2-Clause License | diff --git a/docs/runtime/binary-data.mdx b/docs/runtime/binary-data.mdx index d7fee3d9d3cd..64b7099c8897 100644 --- a/docs/runtime/binary-data.mdx +++ b/docs/runtime/binary-data.mdx @@ -498,8 +498,7 @@ Array.from(arr); #### To `Blob` ```ts -// only if arr is a view of its entire backing ArrayBuffer -new Blob([arr.buffer], { type: "text/plain" }); +new Blob([arr], { type: "text/plain" }); ``` #### To `ReadableStream` @@ -736,7 +735,7 @@ blob.stream(); ```ts stream; // ReadableStream -const buffer = new Response(stream).arrayBuffer(); +const buffer = await new Response(stream).arrayBuffer(); ``` But this approach is verbose and adds unnecessary overhead. Bun implements optimized convenience functions for converting a `ReadableStream` to various binary formats. diff --git a/docs/runtime/bunfig.mdx b/docs/runtime/bunfig.mdx index eaf08f8eefbe..5927b01bf6d6 100644 --- a/docs/runtime/bunfig.mdx +++ b/docs/runtime/bunfig.mdx @@ -16,7 +16,7 @@ To configure Bun's package manager globally, you can also create a `.bunfig.toml - `$HOME/.bunfig.toml` - `$XDG_CONFIG_HOME/.bunfig.toml` -Only package manager commands (`bun install`, `bun add`, `bun remove`, `bun update`, `bun pm`, `bunx`, and so on) read the global file. If Bun finds both a global and a local `bunfig`, it shallow-merges them, with local overriding global. CLI flags override `bunfig` settings where applicable. +Only package manager commands (`bun install`, `bun add`, `bun remove`, `bun update`, `bun pm`, `bunx`, and so on) read the global file. If Bun finds both a global and a local `bunfig`, it loads both; keys set in the local file override the same keys in the global file. CLI flags override `bunfig` settings where applicable. ## Runtime @@ -230,11 +230,11 @@ The coverage threshold. By default, no threshold is set. If your test suite does coverageThreshold = 0.9 ``` -You can set separate thresholds for line, function, and statement coverage. +You can set separate thresholds for line and function coverage. Bun accepts a `statements` key but does not currently enforce it. ```toml title="bunfig.toml" icon="settings" [test] -coverageThreshold = { lines = 0.7, functions = 0.8, statements = 0.9 } +coverageThreshold = { lines = 0.7, functions = 0.8 } ``` ### `test.coverageSkipTestFiles` diff --git a/docs/runtime/c-compiler.mdx b/docs/runtime/c-compiler.mdx index c9f69c947955..9c9ac1ad1111 100644 --- a/docs/runtime/c-compiler.mdx +++ b/docs/runtime/c-compiler.mdx @@ -51,17 +51,18 @@ What is the answer to the universe? 42 ### Primitive types -`cc` supports the same `FFIType` values as [`dlopen`](/runtime/ffi). +`cc` supports the same `FFIType` values as [`dlopen`](/runtime/ffi), except `buffer_length`. Only `cc` supports `napi_env` and `napi_value`. | `FFIType` | C Type | Aliases | | ---------- | -------------- | --------------------------- | +| buffer | `char*` | | | cstring | `char*` | | | function | `(void*)(*)()` | `fn`, `callback` | | ptr | `void*` | `pointer`, `void*`, `char*` | | i8 | `int8_t` | `int8_t` | | i16 | `int16_t` | `int16_t` | | i32 | `int32_t` | `int32_t`, `int` | -| i64 | `int64_t` | `int64_t` | +| i64 | `int64_t` | `int64_t`, `isize` | | i64_fast | `int64_t` | | | u8 | `uint8_t` | `uint8_t` | | u16 | `uint16_t` | `uint16_t` | @@ -132,12 +133,12 @@ napi_value hello(napi_env env) { ### `cc` Reference -#### `library: string[]` +#### `library: string | string[]` -Use the `library` array to specify the libraries to link with the C code. +Use `library` to specify the libraries to link with the C code. ```ts -type Library = string[]; +type Library = string | string[]; cc({ source: "hello.c", diff --git a/docs/runtime/child-process.mdx b/docs/runtime/child-process.mdx index 60bf1a2e733b..cb154882a4cd 100644 --- a/docs/runtime/child-process.mdx +++ b/docs/runtime/child-process.mdx @@ -95,7 +95,7 @@ console.log(output); // "Hello from ReadableStream!" ## Output streams -Read the subprocess's output from the `stdout` and `stderr` properties. By default `stdout` is an instance of `ReadableStream`; `stderr` is inherited from the parent process, so `proc.stderr` is `undefined` unless you pass `stderr: "pipe"`. +Read the subprocess's output from the `stdout` and `stderr` properties. By default `stdout` is an instance of `ReadableStream`; `stderr` is inherited from the parent process, so `proc.stderr` is `undefined`. Pass `stderr: "pipe"` to get a `ReadableStream` for it as well. ```ts const proc = Bun.spawn(["bun", "--version"]); @@ -543,7 +543,7 @@ namespace SpawnOptions { killSignal?: string | number; maxBuffer?: number; cgroup?: string | number; // Linux only; cgroup directory path or open directory fd - terminal?: TerminalOptions | Terminal; // PTY (POSIX) / ConPTY (Windows) support + terminal?: TerminalOptions | Terminal; // Bun.spawn only (spawnSync throws); PTY (POSIX) / ConPTY (Windows) support } type Readable = diff --git a/docs/runtime/debugger.mdx b/docs/runtime/debugger.mdx index bb51d2d94797..d83684a0dca7 100644 --- a/docs/runtime/debugger.mdx +++ b/docs/runtime/debugger.mdx @@ -228,9 +228,9 @@ The output is a syntax-highlighted preview of the source code where the error oc ```ts icon="file-code" 1 | // Create an error 2 | const err = new Error("Something went wrong"); - ^ + ^ error: Something went wrong - at file.js:2:13 + at /path/to/file.js:2:17 ``` ### V8 Stack Traces diff --git a/docs/runtime/environment-variables.mdx b/docs/runtime/environment-variables.mdx index 2208316ec70e..aaf6d5beda5f 100644 --- a/docs/runtime/environment-variables.mdx +++ b/docs/runtime/environment-variables.mdx @@ -11,7 +11,7 @@ Bun reads the following files automatically (listed in order of increasing prece - `.env` - `.env.production`, `.env.development`, `.env.test` (depending on the value of `NODE_ENV`) -- `.env.local` +- `.env.local` (not loaded when `NODE_ENV=test`) - `.env.production.local`, `.env.development.local`, `.env.test.local` (depending on the value of `NODE_ENV`) ```ini .env icon="settings" diff --git a/docs/runtime/ffi.mdx b/docs/runtime/ffi.mdx index d22f2a5610ee..2cc5c8492ab7 100644 --- a/docs/runtime/ffi.mdx +++ b/docs/runtime/ffi.mdx @@ -138,7 +138,7 @@ The following `FFIType` values are supported. | i8 | `int8_t` | `int8_t` | | i16 | `int16_t` | `int16_t` | | i32 | `int32_t` | `int32_t`, `int` | -| i64 | `int64_t` | `int64_t` | +| i64 | `int64_t` | `int64_t`, `isize` | | i64_fast | `int64_t` | | | u8 | `uint8_t` | `uint8_t` | | u16 | `uint16_t` | `uint16_t` | @@ -341,7 +341,7 @@ When you're done with a `JSCallback`, call `close()` to free the memory. `JSCallback` has experimental support for thread-safe callbacks. You need this if you pass a callback function into a different thread from the one that created it. Enable it with the optional `threadsafe` parameter. -Thread-safe callbacks can be invoked from **any thread** — including threads spawned by your native library that Bun is not otherwise aware of. The engine copies the C arguments on the calling thread and marshals the invocation onto the JavaScript thread. There it converts the arguments (64-bit integers and pointers arrive as exact BigInts) and runs your function. Because the invocation is asynchronous from C's point of view, the value returned to the C caller is unspecified. You may declare a non-`void` `returns` (the example below uses `"bool"`), but the C side must treat a thread-safe callback as returning `void` and ignore its return value. +Thread-safe callbacks can be invoked from **any thread** — including threads spawned by your native library that Bun is not otherwise aware of. The engine copies the C arguments on the calling thread and marshals the invocation onto the JavaScript thread. There it converts the arguments exactly as for an ordinary callback (`i64`/`u64`/`usize` arguments arrive as BigInts; pointers arrive as numbers) and runs your function. Because the invocation is asynchronous from C's point of view, the value returned to the C caller is unspecified. You may declare a non-`void` `returns` (the example below uses `"bool"`), but the C side must treat a thread-safe callback as returning `void` and ignore its return value. ```ts const searchIterator = new JSCallback((ptr, length) => /hello/.test(new CString(ptr, 0, Number(length))), { diff --git a/docs/runtime/file-types.mdx b/docs/runtime/file-types.mdx index 9a7a94dc7cb9..fe54b922dfc2 100644 --- a/docs/runtime/file-types.mdx +++ b/docs/runtime/file-types.mdx @@ -337,6 +337,22 @@ export default "Hello, world!"; +### `md` + +**Markdown loader**. Default for `.md` and `.markdown`. + +Markdown files can be directly imported. Bun renders the file to HTML and returns the HTML as a string. + +```ts +import html from "./README.md"; +console.log(html); // => "

Title

\n" + +// via import attribute (`markdown` is an alias of `md`): +import notes from "./notes.txt" with { type: "md" }; +``` + +During bundling, Bun inlines the rendered HTML into the bundle as a string. + ### `napi` **Native addon loader**. Default for `.node`. @@ -457,7 +473,7 @@ The `html` loader behaves differently depending on how it's used: **CSS loader**. Default for `.css`. -CSS files can be directly imported. This is primarily useful for [full-stack applications](/bundler/fullstack) where CSS is bundled alongside HTML. +CSS files can be directly imported. This is primarily useful when [bundling HTML](/bundler/html-static#importing-css-in-javascript), where CSS is bundled alongside HTML. ```ts import "./styles.css"; diff --git a/docs/runtime/glob.mdx b/docs/runtime/glob.mdx index 0a76cb7b3626..541552217437 100644 --- a/docs/runtime/glob.mdx +++ b/docs/runtime/glob.mdx @@ -167,12 +167,14 @@ Bun also implements Node.js's `fs.glob()` functions: import { glob, globSync, promises } from "node:fs"; // Array of patterns -const files = await promises.glob(["**/*.ts", "**/*.js"]); +const files = await Array.fromAsync(promises.glob(["**/*.ts", "**/*.js"])); // Exclude patterns -const filtered = await promises.glob("**/*", { - exclude: ["node_modules/**", "*.test.*"], -}); +const filtered = await Array.fromAsync( + promises.glob("**/*", { + exclude: ["node_modules/**", "**/*.test.*"], + }), +); ``` All three functions (`fs.glob()`, `fs.globSync()`, `fs.promises.glob()`) support: diff --git a/docs/runtime/hashing.mdx b/docs/runtime/hashing.mdx index 0194de3ce384..07b4ede03c30 100644 --- a/docs/runtime/hashing.mdx +++ b/docs/runtime/hashing.mdx @@ -237,7 +237,7 @@ For strings, an optional second parameter specifies the encoding (default `'utf- ```ts hasher.update("hello world"); // defaults to utf8 -hasher.update("hello world", "hex"); +hasher.update("68656c6c6f", "hex"); hasher.update("hello world", "base64"); hasher.update("hello world", "latin1"); ``` diff --git a/docs/runtime/http/tls.mdx b/docs/runtime/http/tls.mdx index a11a722d6825..0722fd1b9dfc 100644 --- a/docs/runtime/http/tls.mdx +++ b/docs/runtime/http/tls.mdx @@ -14,7 +14,7 @@ Bun.serve({ }); ``` -The `key` and `cert` fields expect the _contents_ of your TLS key and certificate, _not a path to it_. Each can be a string, `BunFile`, `TypedArray`, `Buffer`, or an array of those. +The `key` and `cert` fields expect the _contents_ of your TLS key and certificate, _not a path to it_. Each can be a string, `BunFile`, `TypedArray`, `Buffer`, or an array of those. Bun uses only the last key/cert pair in an array; to serve several certificates, pass an array of `tls` objects, each with a `serverName` (see [SNI](#server-name-indication-sni) below). ```ts Bun.serve({ diff --git a/docs/runtime/module-resolution.mdx b/docs/runtime/module-resolution.mdx index 0738497122a2..0aa049e1fb4f 100644 --- a/docs/runtime/module-resolution.mdx +++ b/docs/runtime/module-resolution.mdx @@ -265,7 +265,7 @@ Multiple paths use the platform's delimiter (`:` on Unix, `;` on Windows): ```bash NODE_PATH=./packages:./lib bun run src/index.js # Unix/macOS -NODE_PATH=./packages;./lib bun run src/index.js # Windows +NODE_PATH="./packages;./lib" bun run src/index.js # Windows ``` ### Custom conditions diff --git a/docs/runtime/plugins.mdx b/docs/runtime/plugins.mdx index 0c7ef95ab459..24e13c182f88 100644 --- a/docs/runtime/plugins.mdx +++ b/docs/runtime/plugins.mdx @@ -105,16 +105,18 @@ onStart(callback: () => void | Promise): void; Registers a callback that runs when the bundler starts a new bundle. ```ts index.ts icon="/icons/typescript.svg" -import { plugin } from "bun"; - -plugin({ - name: "onStart example", - - setup(build) { - build.onStart(() => { - console.log("Bundle started!"); - }); - }, +await Bun.build({ + entrypoints: ["./app.ts"], + plugins: [ + { + name: "onStart example", + setup(build) { + build.onStart(() => { + console.log("Bundle started!"); + }); + }, + }, + ], }); ``` @@ -227,7 +229,10 @@ import type { BunPlugin } from "bun"; const envPlugin: BunPlugin = { name: "env plugin", setup(build) { - build.onLoad({ filter: /env/, namespace: "file" }, args => { + build.onResolve({ filter: /^env$/ }, args => { + return { path: args.path, namespace: "env" }; + }); + build.onLoad({ filter: /env/, namespace: "env" }, args => { return { contents: `export default ${JSON.stringify(process.env)}`, loader: "js", diff --git a/docs/runtime/redis.mdx b/docs/runtime/redis.mdx index ac3c570e59fd..815e37c0200e 100644 --- a/docs/runtime/redis.mdx +++ b/docs/runtime/redis.mdx @@ -194,7 +194,7 @@ import { RedisClient } from "bun"; const writer = new RedisClient("redis://localhost:6379"); await writer.connect(); -writer.publish("general", "Hello everyone!"); +await writer.publish("general", "Hello everyone!"); writer.close(); ``` diff --git a/docs/runtime/s3.mdx b/docs/runtime/s3.mdx index eef78b27a65d..51533740eb8c 100644 --- a/docs/runtime/s3.mdx +++ b/docs/runtime/s3.mdx @@ -710,7 +710,7 @@ This is equivalent to calling `new S3Client(credentials).presign("my-file.txt", To list some or all (up to 1,000) objects in a bucket, use the `S3Client.list` static method. -```ts s3.ts icon="/icons/typescript.svg" highlight={12, 15-20, 24-29} +```ts s3.ts icon="/icons/typescript.svg" highlight={12, 15-22, 27-35} import { S3Client } from "bun"; const credentials = { @@ -741,7 +741,7 @@ if (uploads.isTruncated) { { prefix: "uploads/", maxKeys: 500, - startAfter: uploads.contents!.at(-1).key, + startAfter: uploads.contents!.at(-1)!.key, fetchOwner: true, }, credentials, diff --git a/docs/runtime/sql.mdx b/docs/runtime/sql.mdx index 22f72bdc4405..82446660b136 100644 --- a/docs/runtime/sql.mdx +++ b/docs/runtime/sql.mdx @@ -1351,14 +1351,14 @@ Bun converts MySQL types to JavaScript types: | FLOAT, DOUBLE | number | | | DATE | Date | JavaScript Date object | | DATETIME, TIMESTAMP | Date | Decoded as UTC (see note below); `0000-00-00` becomes an Invalid Date | -| TIME | number | Total of microseconds | +| TIME | string | Formatted as `HH:MM:SS` (`HHH:MM:SS` above 99 hours); prepared queries drop fractional seconds | | YEAR | number | | | CHAR, VARCHAR, VARSTRING, STRING | string | | | TINY TEXT, MEDIUM TEXT, TEXT, LONG TEXT | string | | | TINY BLOB, MEDIUM BLOB, BLOB, LONG BLOB | Buffer | Same wire types as TEXT; Bun returns a Buffer when the column uses the binary character set | | JSON | object/array | Automatically parsed | | BIT(1) | boolean | BIT(1) in MySQL | -| GEOMETRY | string | Geometry data | +| GEOMETRY | Buffer | Binary character set; the bytes are a 4-byte SRID followed by WKB | `DATETIME` and `TIMESTAMP` values have no timezone on the wire, so Bun reads them back as **UTC**. The `Date` you get has the same UTC wall-clock that was stored, regardless of the machine's timezone. Reading as UTC matches how Bun writes values (a bound `Date` stores its UTC components). The same applies to PostgreSQL's `timestamp` (without time zone); `timestamptz` carries an explicit offset and is unaffected. diff --git a/docs/runtime/streams.mdx b/docs/runtime/streams.mdx index fddbdb793eb6..59f60a75f2b4 100644 --- a/docs/runtime/streams.mdx +++ b/docs/runtime/streams.mdx @@ -68,7 +68,7 @@ const stream = new ReadableStream({ }); ``` -When using a direct `ReadableStream`, the destination handles all chunk queueing. The consumer of the stream receives exactly what is passed to `controller.write()`, without any encoding or modification. +When using a direct `ReadableStream`, the destination handles all chunk queueing. The destination receives the bytes you pass to `controller.write()`. When the stream is read from JavaScript, Bun buffers the writes and delivers them as `Uint8Array` chunks (strings are UTF-8 encoded). ### Handling backpressure diff --git a/docs/runtime/templating/create.mdx b/docs/runtime/templating/create.mdx index 7c033a7dba04..55de47d8ea46 100644 --- a/docs/runtime/templating/create.mdx +++ b/docs/runtime/templating/create.mdx @@ -121,7 +121,7 @@ bun create remix bunx create-remix ``` -Refer to the `create-