initial commit
This commit is contained in:
@@ -0,0 +1,301 @@
|
||||
---
|
||||
title: Benchmarking
|
||||
description: How to benchmark Bun
|
||||
---
|
||||
|
||||
Bun is designed for speed. We profile and benchmark hot paths extensively. The source code for all of Bun's public benchmarks is in the [`/bench`](https://github.com/oven-sh/bun/tree/main/bench) directory of the Bun repo.
|
||||
|
||||
## Measuring time
|
||||
|
||||
To measure time precisely, Bun offers two runtime APIs:
|
||||
|
||||
1. The Web-standard [`performance.now()`](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) function
|
||||
2. `Bun.nanoseconds()`, which is like `performance.now()` except it returns the time since the application started in nanoseconds. Use `performance.timeOrigin` to convert this to a Unix timestamp.
|
||||
|
||||
## Benchmarking tools
|
||||
|
||||
- For microbenchmarks, we recommend [`mitata`](https://github.com/evanwashere/mitata).
|
||||
- For load testing, you _must use_ an HTTP benchmarking tool that is at least as fast as `Bun.serve()`, or your results will be skewed. Some popular Node.js-based benchmarking tools like [`autocannon`](https://github.com/mcollina/autocannon) are not fast enough. We recommend one of the following:
|
||||
- [`bombardier`](https://github.com/codesenberg/bombardier)
|
||||
- [`oha`](https://github.com/hatoo/oha)
|
||||
- [`http_load_test`](https://github.com/uNetworking/uSockets/blob/master/examples/http_load_test.c)
|
||||
- For benchmarking scripts or CLI commands, we recommend [`hyperfine`](https://github.com/sharkdp/hyperfine).
|
||||
|
||||
## Measuring memory usage
|
||||
|
||||
Bun has two heaps: one for the JavaScript runtime, and one for everything else.
|
||||
|
||||
### JavaScript heap stats
|
||||
|
||||
The `bun:jsc` module exposes a few functions for measuring memory usage:
|
||||
|
||||
```ts
|
||||
import { heapStats } from "bun:jsc";
|
||||
console.log(heapStats());
|
||||
```
|
||||
|
||||
<Accordion title="View example statistics">
|
||||
|
||||
```ts expandable icon="/icons/typescript.svg"
|
||||
{
|
||||
heapSize: 1657575,
|
||||
heapCapacity: 2872775,
|
||||
extraMemorySize: 598199,
|
||||
objectCount: 13790,
|
||||
protectedObjectCount: 62,
|
||||
globalObjectCount: 1,
|
||||
protectedGlobalObjectCount: 1,
|
||||
// A count of every object type in the heap
|
||||
objectTypeCounts: {
|
||||
CallbackObject: 25,
|
||||
FunctionExecutable: 2078,
|
||||
AsyncGeneratorFunction: 2,
|
||||
'RegExp String Iterator': 1,
|
||||
FunctionCodeBlock: 188,
|
||||
ModuleProgramExecutable: 13,
|
||||
String: 1,
|
||||
UnlinkedModuleProgramCodeBlock: 13,
|
||||
JSON: 1,
|
||||
AsyncGenerator: 1,
|
||||
Symbol: 1,
|
||||
GetterSetter: 68,
|
||||
ImportMeta: 10,
|
||||
DOMAttributeGetterSetter: 1,
|
||||
UnlinkedFunctionCodeBlock: 174,
|
||||
RegExp: 52,
|
||||
ModuleLoader: 1,
|
||||
Intl: 1,
|
||||
WeakMap: 4,
|
||||
Generator: 2,
|
||||
PropertyTable: 95,
|
||||
'Array Iterator': 1,
|
||||
JSLexicalEnvironment: 75,
|
||||
UnlinkedFunctionExecutable: 2067,
|
||||
WeakSet: 1,
|
||||
console: 1,
|
||||
Map: 23,
|
||||
SparseArrayValueMap: 14,
|
||||
StructureChain: 19,
|
||||
Set: 18,
|
||||
'String Iterator': 1,
|
||||
FunctionRareData: 3,
|
||||
JSGlobalLexicalEnvironment: 1,
|
||||
Object: 481,
|
||||
BigInt: 2,
|
||||
StructureRareData: 55,
|
||||
Array: 179,
|
||||
AbortController: 2,
|
||||
ModuleNamespaceObject: 11,
|
||||
ShadowRealm: 1,
|
||||
'Immutable Butterfly': 103,
|
||||
Primordials: 1,
|
||||
'Set Iterator': 1,
|
||||
JSGlobalProxy: 1,
|
||||
AsyncFromSyncIterator: 1,
|
||||
ModuleRecord: 13,
|
||||
FinalizationRegistry: 1,
|
||||
AsyncIterator: 1,
|
||||
InternalPromise: 22,
|
||||
Iterator: 1,
|
||||
CustomGetterSetter: 65,
|
||||
Promise: 19,
|
||||
WeakRef: 1,
|
||||
InternalPromisePrototype: 1,
|
||||
Function: 2381,
|
||||
AsyncFunction: 2,
|
||||
GlobalObject: 1,
|
||||
ArrayBuffer: 2,
|
||||
Boolean: 1,
|
||||
Math: 1,
|
||||
CallbackConstructor: 1,
|
||||
Error: 2,
|
||||
JSModuleEnvironment: 13,
|
||||
WebAssembly: 1,
|
||||
HashMapBucket: 300,
|
||||
Callee: 3,
|
||||
symbol: 37,
|
||||
string: 2484,
|
||||
Performance: 1,
|
||||
ModuleProgramCodeBlock: 12,
|
||||
JSSourceCode: 13,
|
||||
JSPropertyNameEnumerator: 3,
|
||||
NativeExecutable: 290,
|
||||
Number: 1,
|
||||
Structure: 1550,
|
||||
SymbolTable: 108,
|
||||
GeneratorFunction: 2,
|
||||
'Map Iterator': 1
|
||||
},
|
||||
protectedObjectTypeCounts: {
|
||||
CallbackConstructor: 1,
|
||||
BigInt: 1,
|
||||
RegExp: 2,
|
||||
GlobalObject: 1,
|
||||
UnlinkedModuleProgramCodeBlock: 13,
|
||||
HashMapBucket: 2,
|
||||
Structure: 41,
|
||||
JSPropertyNameEnumerator: 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
JavaScript is a garbage-collected language, not reference counted. It's normal and correct for objects to not be freed immediately in all cases, though it's not normal for objects to never be freed.
|
||||
|
||||
To force garbage collection to run manually:
|
||||
|
||||
```ts
|
||||
Bun.gc(true); // synchronous
|
||||
Bun.gc(false); // asynchronous
|
||||
```
|
||||
|
||||
Heap snapshots show which objects are not being freed. Use `Bun.generateHeapSnapshot()` to take a heap snapshot, then view it with Safari or WebKit GTK developer tools. To generate a heap snapshot:
|
||||
|
||||
```ts
|
||||
import { generateHeapSnapshot } from "bun";
|
||||
|
||||
const snapshot = generateHeapSnapshot();
|
||||
await Bun.write("heap.json", JSON.stringify(snapshot, null, 2));
|
||||
```
|
||||
|
||||
To view the snapshot, open the `heap.json` file in Safari's Developer Tools (or WebKit GTK):
|
||||
|
||||
1. Open the Developer Tools
|
||||
2. Click "Timeline"
|
||||
3. Click "JavaScript Allocations" in the menu on the left. It might not be visible until you click the pencil icon to show all the timelines
|
||||
4. Click "Import" and select your heap snapshot JSON
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
src="https://user-images.githubusercontent.com/709451/204428943-ba999e8f-8984-4f23-97cb-b4e3e280363e.png"
|
||||
alt="Importing a heap snapshot"
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
Once imported, you should see something like this:
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
alt="Viewing heap snapshot in Safari"
|
||||
src="https://user-images.githubusercontent.com/709451/204429337-b0d8935f-3509-4071-b991-217794d1fb27.png"
|
||||
caption="Viewing heap snapshot in Safari Dev Tools"
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
> The [web debugger](/runtime/debugger#inspect) timeline also tracks the memory usage of the running debug session.
|
||||
|
||||
### Native heap stats
|
||||
|
||||
Bun uses mimalloc for the other heap. To print a summary of non-JavaScript memory usage, call `Bun.unsafe.mimallocDump()`.
|
||||
|
||||
```ts
|
||||
Bun.unsafe.mimallocDump();
|
||||
```
|
||||
|
||||
```txt
|
||||
heap stats: peak total freed current unit count
|
||||
reserved: 64.0 MiB 64.0 MiB 0 64.0 MiB not all freed!
|
||||
committed: 64.0 MiB 64.0 MiB 0 64.0 MiB not all freed!
|
||||
reset: 0 0 0 0 ok
|
||||
touched: 128.5 KiB 128.5 KiB 5.4 MiB -5.3 MiB ok
|
||||
segments: 1 1 0 1 not all freed!
|
||||
-abandoned: 0 0 0 0 ok
|
||||
-cached: 0 0 0 0 ok
|
||||
pages: 0 0 53 -53 ok
|
||||
-abandoned: 0 0 0 0 ok
|
||||
-extended: 0
|
||||
-noretire: 0
|
||||
mmaps: 0
|
||||
commits: 0
|
||||
threads: 0 0 0 0 ok
|
||||
searches: 0.0 avg
|
||||
numa nodes: 1
|
||||
elapsed: 0.068 s
|
||||
process: user: 0.061 s, system: 0.014 s, faults: 0, rss: 57.4 MiB, commit: 64.0 MiB
|
||||
```
|
||||
|
||||
## CPU profiling
|
||||
|
||||
Profile JavaScript execution to identify performance bottlenecks with the `--cpu-prof` flag.
|
||||
|
||||
```sh terminal icon="terminal"
|
||||
bun --cpu-prof script.js
|
||||
```
|
||||
|
||||
`--cpu-prof` writes a `.cpuprofile` file you can open in Chrome DevTools (Performance tab → Load profile) or VS Code's CPU profiler.
|
||||
|
||||
### Markdown output
|
||||
|
||||
Use `--cpu-prof-md` to generate a markdown CPU profile, which is grep-friendly and designed for LLM analysis:
|
||||
|
||||
```sh terminal icon="terminal"
|
||||
bun --cpu-prof-md script.js
|
||||
```
|
||||
|
||||
Combine `--cpu-prof` and `--cpu-prof-md` to generate both formats at once:
|
||||
|
||||
```sh terminal icon="terminal"
|
||||
bun --cpu-prof --cpu-prof-md script.js
|
||||
```
|
||||
|
||||
You can also pass the flag through the `BUN_OPTIONS` environment variable:
|
||||
|
||||
```sh terminal icon="terminal"
|
||||
BUN_OPTIONS="--cpu-prof-md" bun script.js
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```sh terminal icon="terminal"
|
||||
bun --cpu-prof --cpu-prof-name my-profile.cpuprofile script.js
|
||||
bun --cpu-prof --cpu-prof-dir ./profiles script.js
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
| ---------------------------- | ----------------------------------------------------------- |
|
||||
| `--cpu-prof` | Generate a `.cpuprofile` JSON file (Chrome DevTools format) |
|
||||
| `--cpu-prof-md` | Generate a markdown CPU profile (grep/LLM-friendly) |
|
||||
| `--cpu-prof-name <filename>` | Set output filename |
|
||||
| `--cpu-prof-dir <dir>` | Set output directory |
|
||||
|
||||
## Heap profiling
|
||||
|
||||
Write a heap profile on exit to analyze memory usage and find memory leaks.
|
||||
|
||||
```sh terminal icon="terminal"
|
||||
bun --heap-prof script.js
|
||||
```
|
||||
|
||||
`--heap-prof` writes a full V8-format heap snapshot on exit, using Node.js's
|
||||
diagnostic filename format
|
||||
(`Heap.<yyyymmdd>.<hhmmss>.<pid>.<tid>.<seq>.heapprofile`). The extension
|
||||
follows Node's `--heap-prof` filename contract. The content is the same as
|
||||
`v8.writeHeapSnapshot()` /
|
||||
`Bun.generateHeapSnapshot("v8")`. Load it in Chrome DevTools via
|
||||
Memory tab → Load. Pick "All Files", or rename the file to `.heapsnapshot`.
|
||||
|
||||
### Markdown output
|
||||
|
||||
Use `--heap-prof-md` to generate a markdown heap profile for CLI analysis:
|
||||
|
||||
```sh terminal icon="terminal"
|
||||
bun --heap-prof-md script.js
|
||||
```
|
||||
|
||||
<Note>If you specify both `--heap-prof` and `--heap-prof-md`, Bun uses the markdown format.</Note>
|
||||
|
||||
### Options
|
||||
|
||||
```sh terminal icon="terminal"
|
||||
bun --heap-prof --heap-prof-name my-profile.heapprofile script.js
|
||||
bun --heap-prof --heap-prof-dir ./profiles script.js
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `--heap-prof` | Write a `.heapprofile` file on exit |
|
||||
| `--heap-prof-md` | Generate a markdown heap profile on exit |
|
||||
| `--heap-prof-name <filename>` | Set output filename |
|
||||
| `--heap-prof-dir <dir>` | Set output directory |
|
||||
| `--heap-prof-interval <bytes>` | Accepted for Node.js compatibility (the snapshot is taken once at exit; JavaScriptCore has no allocation sampling to apply an interval to) |
|
||||
@@ -0,0 +1,285 @@
|
||||
---
|
||||
title: Bindgen
|
||||
description: Bindgen for Bun
|
||||
---
|
||||
|
||||
<Note>This document is for maintainers and contributors to Bun, and describes internal implementation details.</Note>
|
||||
|
||||
The bindings generator scans for `*.bind.ts` files to find function and class
|
||||
definitions, and generates glue code to interop between JavaScript and native
|
||||
code.
|
||||
|
||||
There are other code generators and systems that achieve similar purposes;
|
||||
the following will all eventually be phased out in favor of this one:
|
||||
|
||||
- "Classes generator", converting `*.classes.ts` for custom classes.
|
||||
- "JS2Native", allowing ad-hoc calls from `src/js` to native code.
|
||||
|
||||
## Creating JS Functions in Rust
|
||||
|
||||
Given a file implementing a function, such as `add`:
|
||||
|
||||
```rust src/jsc/bindgen_test.rs
|
||||
use crate::{JSGlobalObject, JsResult};
|
||||
use crate::r#gen::bindgen_test as generated;
|
||||
|
||||
pub fn add(global: &JSGlobalObject, a: i32, b: i32) -> JsResult<i32> {
|
||||
match a.checked_add(b) {
|
||||
Some(v) => Ok(v),
|
||||
None => {
|
||||
// Binding functions can propagate out-of-memory and JS exceptions
|
||||
// directly; other failures (like this integer overflow) must be
|
||||
// converted into a thrown error. Remember to be descriptive.
|
||||
Err(global.throw(format_args!("Integer overflow while adding")))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then describe the API schema using a `.bind.ts` file. The binding file goes
|
||||
next to the Rust file.
|
||||
|
||||
```ts src/jsc/bindgen_test.bind.ts icon="/icons/typescript.svg"
|
||||
import { fn, t } from "bindgen";
|
||||
|
||||
export const add = fn({
|
||||
args: {
|
||||
global: t.globalObject,
|
||||
a: t.i32,
|
||||
b: t.i32.default(-1),
|
||||
},
|
||||
ret: t.i32,
|
||||
});
|
||||
```
|
||||
|
||||
This function declaration is equivalent to:
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Throws if zero arguments are provided.
|
||||
* Wraps out of range numbers using modulo.
|
||||
*/
|
||||
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; 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::<basename>` (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)`:
|
||||
|
||||
```rust
|
||||
use crate::r#gen::bindgen_test as generated;
|
||||
|
||||
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, through a hand-written
|
||||
`js2native_bindgen_<basename>_<fn>` 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
|
||||
callback constructor follows the same convention
|
||||
(`create_required_and_optional_arg_callback`).
|
||||
|
||||
## Strings
|
||||
|
||||
To receive a string, use [`t.DOMString`](https://webidl.spec.whatwg.org/#idl-DOMString), [`t.ByteString`](https://webidl.spec.whatwg.org/#idl-ByteString), or [`t.USVString`](https://webidl.spec.whatwg.org/#idl-USVString). These map directly to their WebIDL counterparts and have slightly different conversion logic. Bindgen passes `bun_core::String` to native code in all cases.
|
||||
|
||||
When in doubt, use DOMString.
|
||||
|
||||
`t.UTF8String` works in place of `t.DOMString`, but eagerly converts to UTF-8.
|
||||
The native callback receives a `&[u8]` slice (WTF-8 data) that is
|
||||
freed after the function returns.
|
||||
|
||||
TLDRs from the WebIDL spec:
|
||||
|
||||
- ByteString can only contain valid latin1 characters. It is not safe to assume `bun_core::String` is already in 8-bit format, but it is extremely likely.
|
||||
- USVString does not contain invalid surrogate pairs, so its text can be represented correctly in UTF-8.
|
||||
- DOMString is the loosest but also the most recommended strategy.
|
||||
|
||||
## Function Variants
|
||||
|
||||
The `variants` key declares multiple variants (also known as overloads) of a function.
|
||||
|
||||
```ts
|
||||
import { fn, t } from "bindgen";
|
||||
|
||||
export const action = fn({
|
||||
variants: [
|
||||
{
|
||||
args: {
|
||||
a: t.i32,
|
||||
},
|
||||
ret: t.i32,
|
||||
},
|
||||
{
|
||||
args: {
|
||||
a: t.DOMString,
|
||||
},
|
||||
ret: t.DOMString,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
Each variant gets a numbered Rust function:
|
||||
|
||||
```rust
|
||||
pub fn action1(a: i32) -> i32 {
|
||||
a
|
||||
}
|
||||
|
||||
pub fn action2(a: bun_core::String) -> bun_core::String {
|
||||
a
|
||||
}
|
||||
```
|
||||
|
||||
## `t.dictionary`
|
||||
|
||||
A `dictionary` describes a JavaScript object, typically a function input. For function outputs, prefer a class type so you can add methods and support destructuring.
|
||||
|
||||
## Enumerations
|
||||
|
||||
`t.stringEnum` creates a [WebIDL enumeration](https://webidl.spec.whatwg.org/#idl-enums) and generates a new enum type for it.
|
||||
|
||||
An example of `stringEnum` from `fmt_jsc.bind.ts` / `bun:internal-for-testing`:
|
||||
|
||||
```ts
|
||||
export const Formatter = t.stringEnum("highlight-javascript", "highlight-javascript-redacted", "escape-powershell");
|
||||
|
||||
export const fmtString = fn({
|
||||
args: {
|
||||
global: t.globalObject,
|
||||
code: t.UTF8String,
|
||||
formatter: Formatter,
|
||||
},
|
||||
ret: t.DOMString,
|
||||
});
|
||||
```
|
||||
|
||||
On the Rust side, the enum is mirrored as a `#[repr(u8)]` enum. Bindgen
|
||||
**sorts `t.stringEnum` values alphabetically** before emitting the C++
|
||||
`enum class`, so discriminants must match the generated header's order, not
|
||||
the `.bind.ts` declaration order:
|
||||
|
||||
```rust
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Formatter {
|
||||
EscapePowershell = 0,
|
||||
HighlightJavascript = 1,
|
||||
HighlightJavascriptRedacted = 2,
|
||||
}
|
||||
|
||||
pub fn fmt_string(
|
||||
global: &JSGlobalObject,
|
||||
code: &[u8],
|
||||
formatter_id: Formatter,
|
||||
) -> JsResult<bun_core::String> {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
WebIDL strongly encourages kebab-case for enumeration values, to be consistent with existing Web APIs.
|
||||
|
||||
## `t.oneOf`
|
||||
|
||||
A `oneOf` is a union of two or more types. It is represented as a Rust
|
||||
`enum` with one variant per member type.
|
||||
|
||||
## Attributes
|
||||
|
||||
You can chain attributes onto `t.*` types. On all types:
|
||||
|
||||
- `.required`, in dictionary parameters only
|
||||
- `.optional`, in function arguments only
|
||||
- `.default(T)`
|
||||
|
||||
When a value is `.optional`, it is lowered to a Rust `Option<T>`:
|
||||
|
||||
```ts
|
||||
export const requiredAndOptionalArg = fn({
|
||||
args: {
|
||||
a: t.boolean,
|
||||
b: t.usize.optional,
|
||||
c: t.i32.enforceRange(0, 100).default(42),
|
||||
d: t.u8.optional,
|
||||
},
|
||||
ret: t.i32,
|
||||
});
|
||||
```
|
||||
|
||||
```rust
|
||||
pub fn required_and_optional_arg(a: bool, b: Option<usize>, c: i32, d: Option<u8>) -> i32 {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Depending on the type, more attributes are available. See the type definitions
|
||||
in auto-complete for details. You can apply only one of these three attributes,
|
||||
and you must apply it last.
|
||||
|
||||
### Integer Attributes
|
||||
|
||||
Integer types take `clamp` or `enforceRange` to customize overflow behavior:
|
||||
|
||||
```ts
|
||||
import { fn, t } from "bindgen";
|
||||
|
||||
export const add = fn({
|
||||
args: {
|
||||
global: t.globalObject,
|
||||
// enforce in i32 range
|
||||
a: t.i32.enforceRange(),
|
||||
// clamp to u16 range
|
||||
b: t.u16,
|
||||
// enforce in arbitrary range, with a default if not provided
|
||||
c: t.i32.enforceRange(0, 1000).default(5),
|
||||
// clamp to arbitrary range, or None
|
||||
d: t.u16.clamp(0, 10).optional,
|
||||
},
|
||||
ret: t.i32,
|
||||
});
|
||||
```
|
||||
|
||||
Node.js validator functions such as `validateInteger` and `validateNumber`
|
||||
are also available. Use these when implementing Node.js APIs so the error
|
||||
messages match Node exactly.
|
||||
|
||||
Unlike `enforceRange`, which is taken from WebIDL, the `validate*` functions
|
||||
are much stricter about the input they accept. For example, Node's numerical
|
||||
validator checks `typeof value === 'number'`, while WebIDL uses `ToNumber` for
|
||||
lossy conversion.
|
||||
|
||||
```ts
|
||||
import { fn, t } from "bindgen";
|
||||
|
||||
export const add = fn({
|
||||
args: {
|
||||
global: t.globalObject,
|
||||
// throw if not given a number
|
||||
a: t.f64.validateNumber(),
|
||||
// valid in i32 range
|
||||
b: t.i32.validateInt32(),
|
||||
// f64 within safe integer range
|
||||
c: t.f64.validateInteger(),
|
||||
// f64 in given range
|
||||
d: t.f64.validateNumber(-10000, 10000),
|
||||
},
|
||||
ret: t.i32,
|
||||
});
|
||||
```
|
||||
|
||||
## Callbacks
|
||||
|
||||
TODO
|
||||
|
||||
## Classes
|
||||
|
||||
TODO
|
||||
@@ -0,0 +1,195 @@
|
||||
---
|
||||
title: Building Windows
|
||||
description: Building Bun on Windows
|
||||
---
|
||||
|
||||
Use [PowerShell 7 (`pwsh.exe`)](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4) instead of the default `powershell.exe`. If you run into problems, ask in the [#contributing channel on our Discord](http://bun.com/discord).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Enable Scripts
|
||||
|
||||
By default, running unverified scripts is blocked.
|
||||
|
||||
```ps1
|
||||
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted
|
||||
```
|
||||
|
||||
### System Dependencies
|
||||
|
||||
Bun v1.1 or later. The build uses Bun to run its own code generators.
|
||||
|
||||
```ps1
|
||||
irm bun.sh/install.ps1 | iex
|
||||
```
|
||||
|
||||
[Visual Studio](https://visualstudio.microsoft.com) with the "Desktop Development with C++" workload. While installing, also install Git if Git for Windows is not already installed.
|
||||
|
||||
Install Visual Studio with the graphical wizard or through WinGet:
|
||||
|
||||
```ps1
|
||||
winget install "Visual Studio Community 2022" --override "--add Microsoft.VisualStudio.Workload.NativeDesktop Microsoft.VisualStudio.Component.Git " -s msstore
|
||||
```
|
||||
|
||||
After Visual Studio, you need the following:
|
||||
|
||||
- LLVM 21.1.8
|
||||
- Go
|
||||
- Rust (via rustup)
|
||||
- NASM
|
||||
- Perl
|
||||
- Ruby
|
||||
- Node.js
|
||||
|
||||
<Note>rustup installs the Rust nightly toolchain pinned in `rust-toolchain.toml` on the first build.</Note>
|
||||
|
||||
Use [Scoop](https://scoop.sh) to install these remaining tools.
|
||||
|
||||
```ps1 Scoop (x64)
|
||||
irm https://get.scoop.sh | iex
|
||||
scoop install nodejs-lts go rustup nasm ruby perl ccache
|
||||
# scoop seems to be buggy if you install llvm and the rest at the same time
|
||||
scoop install [email protected]
|
||||
```
|
||||
|
||||
For Windows ARM64, download LLVM 21.1.8 directly from GitHub releases (first version with ARM64 Windows builds):
|
||||
|
||||
```ps1 ARM64
|
||||
# Download and install LLVM for ARM64
|
||||
Invoke-WebRequest -Uri "https://github.com/llvm/llvm-project/releases/download/llvmorg-21.1.8/LLVM-21.1.8-woa64.exe" -OutFile "$env:TEMP\LLVM-21.1.8-woa64.exe"
|
||||
Start-Process -FilePath "$env:TEMP\LLVM-21.1.8-woa64.exe" -ArgumentList "/S" -Wait
|
||||
```
|
||||
|
||||
<Note>
|
||||
Do not install these with WinGet or another package manager: you will likely get Strawberry Perl instead of a more
|
||||
minimal installation of Perl. Strawberry Perl adds many other utilities to `$Env:PATH` that conflict with MSVC and
|
||||
break the build.
|
||||
</Note>
|
||||
|
||||
To build WebKit locally (optional, x64 only), install these packages:
|
||||
|
||||
```ps1 Scoop
|
||||
scoop install make cygwin python
|
||||
```
|
||||
|
||||
<Note>ARM64 builds do not need Cygwin because WebKit is provided as a pre-built binary.</Note>
|
||||
|
||||
From here on out, **use a PowerShell terminal with `.\scripts\vs-shell.ps1` sourced**. Load the script by running it:
|
||||
|
||||
```ps1
|
||||
.\scripts\vs-shell.ps1
|
||||
```
|
||||
|
||||
To verify, check for an MSVC-only command such as `mt.exe`:
|
||||
|
||||
```ps1
|
||||
Get-Command mt
|
||||
```
|
||||
|
||||
<Note>
|
||||
Avoid installing `ninja` / `cmake` into your global path: you may end up building Bun without `.\scripts\vs-shell.ps1`
|
||||
sourced.
|
||||
</Note>
|
||||
|
||||
## Building
|
||||
|
||||
```ps1
|
||||
bun run build
|
||||
|
||||
# after the initial `bun run build` you can use the following to build
|
||||
ninja -Cbuild/debug
|
||||
```
|
||||
|
||||
A successful build writes `bun-debug.exe` to the `build/debug` folder.
|
||||
|
||||
```ps1
|
||||
.\build\debug\bun-debug.exe --revision
|
||||
```
|
||||
|
||||
Add this folder to `$Env:PATH`: open the Start menu, type "Path", and use the environment variables menu to add `C:\.....\bun\build\debug` to the user environment variable `PATH`. Then restart your editor (if it still does not pick up the change, log out and log back in).
|
||||
|
||||
## Extra paths
|
||||
|
||||
- The build extracts WebKit to `$Env:BUN_INSTALL\build-cache\webkit-<version>-debug` (`webkit-<version>-arm64-debug` on ARM64); `BUN_INSTALL` defaults to `~\.bun`
|
||||
|
||||
## Tests
|
||||
|
||||
Run the test suite with `bun-debug test <path>` or with the wrapper script `bun run test <path>`. The `bun run test` command runs every test file in a separate instance of `bun-debug.exe`, so a crash in the test runner does not stop the entire suite.
|
||||
|
||||
```ps1
|
||||
# Run the entire test suite with reporter
|
||||
# the package.json script "test" uses "build/debug/bun-debug.exe" by default
|
||||
bun run test
|
||||
|
||||
# Run an individual test file:
|
||||
bun-debug test node\fs
|
||||
bun-debug test "C:\bun\test\js\bun\resolve\import-meta.test.js"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### .rc file fails to build
|
||||
|
||||
`llvm-rc.exe` is odd; don't use it. Use `rc.exe` instead: make sure you are in a Visual Studio dev terminal, and check `rc /?` to confirm it is `Microsoft Resource Compiler`.
|
||||
|
||||
### failed to write output 'bun-debug.exe': permission denied
|
||||
|
||||
You cannot overwrite `bun-debug.exe` while it is open. You likely have a running instance, maybe in the VS Code debugger.
|
||||
|
||||
## Cross-compiling from Linux
|
||||
|
||||
You can also build Windows binaries (both x64 and arm64) on a Linux host. The build uses the host LLVM's `clang-cl`, `lld-link`, `llvm-lib` and `llvm-rc` (part of every LLVM distribution). For headers and import libraries, the build also uses an "xwin splat" of the MSVC CRT/STL and Windows SDK.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. The same LLVM version a native build uses (see `scripts/bootstrap.sh` `llvm_version_exact`), installed so that `clang-cl`, `lld-link`, `llvm-lib` and `llvm-rc` are available. On Debian/Ubuntu, `apt.llvm.org` packages provide all of them.
|
||||
2. `nasm` (only needed for Windows x64; BoringSSL's x64 assembly is NASM syntax).
|
||||
3. Rust std for the Windows targets (`rust-toolchain.toml` lists them; `rustup target add x86_64-pc-windows-msvc aarch64-pc-windows-msvc` if missing).
|
||||
4. A Windows sysroot: an [xwin](https://github.com/Jake-Shadle/xwin) splat of the MSVC CRT, Windows SDK, and ATL laid out like a Visual Studio install. Downloading these components means accepting Microsoft's license terms for them.
|
||||
|
||||
```bash
|
||||
cargo install xwin # or download a release binary
|
||||
xwin --accept-license --arch x86_64,aarch64 --sdk-version 10.0.26100 --crt-version 14.44.17.14 --include-atl splat \
|
||||
--use-winsysroot-style --preserve-ms-arch-notation --include-debug-libs \
|
||||
--output /opt/winsysroot
|
||||
# clang-cl/lld-link look up SDK paths as "Include"/"Lib"; the splat writes
|
||||
# them lowercase, so alias both spellings (needs the same privileges as the
|
||||
# splat — configure creates these itself when the directory is writable).
|
||||
ln -s include "/opt/winsysroot/Windows Kits/10/Include"
|
||||
ln -s lib "/opt/winsysroot/Windows Kits/10/Lib"
|
||||
```
|
||||
|
||||
The build looks for the sysroot at `/opt/winsysroot` (or `/opt/xwin`) automatically. If the sysroot is elsewhere, set `WINDOWS_SYSROOT=<path>` or pass `--winsysroot=<path>`. A user-writable path also lets configure manage the aliases for you. Configure validates the splat at the start of every cross build. CI agents bake the same splat into their images (`.buildkite/Dockerfile`, `scripts/bootstrap.sh`); when an agent doesn't have one, the build fetches it into its cache dir at configure time.
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# Debug builds
|
||||
bun run build --profile=windows-x64
|
||||
bun run build --profile=windows-arm64
|
||||
|
||||
# Release builds
|
||||
bun run build --profile=windows-x64-release
|
||||
bun run build --profile=windows-arm64-release
|
||||
```
|
||||
|
||||
Output lands in `build/debug-windows-x64/bun-debug.exe`, `build/release-windows-aarch64/bun-profile.exe` + `bun.exe`, and so on. Equivalent raw flags: `bun run build --os=windows --arch=aarch64`.
|
||||
|
||||
The build does not run cross-compiled executables on the host (it skips the `--revision` smoke test), so test them on a Windows machine or under Wine.
|
||||
|
||||
### LTO
|
||||
|
||||
x64 release cross builds support ThinLTO with cross-language (Rust↔C++) LTO. It's opt-in:
|
||||
|
||||
```bash
|
||||
bun run build --profile=windows-x64-release --lto=on
|
||||
```
|
||||
|
||||
`--lto=on` does the following:
|
||||
|
||||
- compiles Bun's C/C++ with `-flto=thin`
|
||||
- makes rustc emit LLVM bitcode (`-Clinker-plugin-lto`)
|
||||
- pulls the `bun-webkit-windows-amd64-lto` ThinLTO prebuilt
|
||||
- links everything with rustc's bundled `lld-link` (its LLVM is new enough to read both compilers' bitcode)
|
||||
|
||||
There is no LTO for arm64, because there is no `-lto` WebKit prebuilt: LLVM's CodeView emitter can't handle ARM64 NEON tuple registers during LTO codegen. There is also no LTO for `--baseline`.
|
||||
@@ -0,0 +1,399 @@
|
||||
---
|
||||
title: Contributing
|
||||
description: Contributing to Bun
|
||||
---
|
||||
|
||||
Configuring a development environment for Bun can take 10-30 minutes depending on your internet connection and computer speed. You will need ~10GB of free disk space for the repository and build artifacts.
|
||||
|
||||
If you are using Windows, see [Building Windows](/project/building-windows).
|
||||
|
||||
## Using Nix (Alternative)
|
||||
|
||||
The repository includes a Nix flake as an alternative to installing dependencies manually:
|
||||
|
||||
```bash
|
||||
nix develop
|
||||
bun bd
|
||||
```
|
||||
|
||||
`nix develop` provides all dependencies in an isolated, reproducible environment without requiring sudo.
|
||||
|
||||
## Install Dependencies (Manual)
|
||||
|
||||
Using your system's package manager, install Bun's dependencies:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash macOS (Homebrew)
|
||||
brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rustup-init ruby
|
||||
```
|
||||
|
||||
```bash Ubuntu/Debian
|
||||
sudo apt install curl wget lsb-release software-properties-common cmake git golang libtool ninja-build pkg-config ruby-full xz-utils
|
||||
```
|
||||
|
||||
```bash Arch
|
||||
sudo pacman -S base-devel cmake git go libiconv libtool make ninja pkg-config python rustup sed unzip ruby
|
||||
```
|
||||
|
||||
```bash Fedora
|
||||
sudo dnf install clang21 llvm21 lld21 cmake git golang libtool ninja-build pkg-config ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
|
||||
```
|
||||
|
||||
```bash openSUSE Tumbleweed
|
||||
sudo zypper install go cmake ninja automake git icu rustup
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Bun is written in Rust and requires a specific nightly toolchain (pinned in `rust-toolchain.toml`). Install Rust with [rustup](https://rustup.rs) rather than your distro's `rust`/`cargo` packages — the build scripts use rustup to automatically install and update the pinned nightly:
|
||||
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
```
|
||||
|
||||
Before starting, install a release build of Bun: the build uses Bun's bundler to transpile and minify code, and to run the code generation scripts.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Native
|
||||
curl -fsSL https://bun.com/install | bash
|
||||
```
|
||||
|
||||
```bash npm
|
||||
npm install -g bun
|
||||
```
|
||||
|
||||
```bash Homebrew
|
||||
brew tap oven-sh/bun
|
||||
brew install bun
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
### Optional: Install `ccache`
|
||||
|
||||
`ccache` caches compilation artifacts, which speeds up rebuilds:
|
||||
|
||||
```bash
|
||||
# For macOS
|
||||
brew install ccache
|
||||
|
||||
# For Ubuntu/Debian
|
||||
sudo apt install ccache
|
||||
|
||||
# For Arch
|
||||
sudo pacman -S ccache
|
||||
|
||||
# For Fedora
|
||||
sudo dnf install ccache
|
||||
|
||||
# For openSUSE
|
||||
sudo zypper install ccache
|
||||
```
|
||||
|
||||
The build scripts detect and use `ccache` automatically if it's available. Check cache statistics with `ccache --show-stats`.
|
||||
|
||||
## Install LLVM
|
||||
|
||||
Bun requires LLVM 21.1.8 (`clang` is part of LLVM). The build system enforces this version: a mismatched version causes memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash macOS (Homebrew)
|
||||
brew install llvm@21
|
||||
```
|
||||
|
||||
```bash Ubuntu/Debian
|
||||
# LLVM has an automatic installation script that is compatible with all versions of Ubuntu
|
||||
wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 21 all
|
||||
```
|
||||
|
||||
```bash Arch
|
||||
sudo pacman -S llvm clang lld
|
||||
```
|
||||
|
||||
```bash Fedora
|
||||
sudo dnf install llvm clang lld-devel
|
||||
```
|
||||
|
||||
```bash openSUSE Tumbleweed
|
||||
sudo zypper install clang21 lld21 llvm21
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
If none of these work, install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-21.1.8).
|
||||
|
||||
Make sure Clang/LLVM 21 is in your path:
|
||||
|
||||
```bash
|
||||
which clang-21
|
||||
```
|
||||
|
||||
If not, add it manually:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash macOS (Homebrew)
|
||||
# use fish_add_path if you're using fish
|
||||
# use path+="$(brew --prefix llvm@21)/bin" if you are using zsh
|
||||
export PATH="$(brew --prefix llvm@21)/bin:$PATH"
|
||||
```
|
||||
|
||||
```bash Arch
|
||||
# use fish_add_path if you're using fish
|
||||
export PATH="$PATH:/usr/lib/llvm21/bin"
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<Warning>
|
||||
⚠️ On Ubuntu \<= 20.04, you may need to install the C++ standard library separately. See the [troubleshooting section](#span-file-not-found-on-ubuntu).
|
||||
</Warning>
|
||||
|
||||
## Building Bun
|
||||
|
||||
After cloning the repository, run the following command to build. This can take a while: it downloads and builds dependencies.
|
||||
|
||||
```bash
|
||||
bun run build
|
||||
```
|
||||
|
||||
The binary is at `./build/debug/bun-debug`. It is recommended to add this to your `$PATH`. To verify the build worked, print its version:
|
||||
|
||||
```bash
|
||||
build/debug/bun-debug --version
|
||||
x.y.z_debug
|
||||
```
|
||||
|
||||
## VSCode
|
||||
|
||||
VSCode is the recommended IDE for working on Bun; the repository includes configuration for it. After opening the repository, run `Extensions: Show Recommended Extensions` to install the recommended extensions for Rust and C++. rust-analyzer picks up the workspace `Cargo.toml` automatically and uses the pinned toolchain in `rust-toolchain.toml` for analysis, so diagnostics match the build.
|
||||
|
||||
If you use a different editor, point rust-analyzer (or your editor's Rust plugin) at the repo root — the Cargo workspace and `rust-toolchain.toml` are discovered automatically.
|
||||
|
||||
We recommend adding `./build/debug` to your `$PATH` so that you can run `bun-debug` in your terminal:
|
||||
|
||||
```sh
|
||||
bun-debug
|
||||
```
|
||||
|
||||
## Running debug builds
|
||||
|
||||
The `bd` package.json script compiles and runs a debug build of Bun, only printing the output of the build process if it fails.
|
||||
|
||||
```sh
|
||||
bun bd <args>
|
||||
bun bd test foo.test.ts
|
||||
bun bd ./foo.ts
|
||||
```
|
||||
|
||||
A full debug build can take a few minutes when Rust or C++ has changed; cargo's incremental compilation makes subsequent Rust-only rebuilds much faster. If your development workflow is "change one line, save, rebuild", you will still spend too much time waiting for the link step. Instead:
|
||||
|
||||
- Batch up your changes
|
||||
- Use `cargo check -p <crate>` (or `bun run rust:check` for the whole workspace) to type-check Rust changes without linking. `bun run watch` runs `cargo check` on every save.
|
||||
- Ensure rust-analyzer is running for inline diagnostics (the recommended VSCode extensions set this up)
|
||||
- Prefer using the debugger ("CodeLLDB" in VSCode) to step through the code.
|
||||
- Use debug logs. `BUN_DEBUG_<scope>=1` enables debug logging for the corresponding `declare_scope!(<scope>, ...)` / `scoped_log!(<scope>, ...)` logs. Set `BUN_DEBUG_QUIET_LOGS=1` to disable all debug logging that isn't explicitly enabled. To dump debug logs into a file, set `BUN_DEBUG=<path-to-file>.log`. Debug logs are removed in release builds.
|
||||
- src/js/\*\*.ts changes rebuild almost instantly. Single-crate Rust changes and C++ changes are incremental; only the final link is unavoidable.
|
||||
|
||||
## Code generation scripts
|
||||
|
||||
Bun's build process runs several code generation scripts automatically when certain files change:
|
||||
|
||||
- `./src/codegen/generate-jssink.ts` -- Generates `build/debug/codegen/JSSink.cpp`, `build/debug/codegen/JSSink.h` which implement various classes for interfacing with `ReadableStream`. This is internally how `FileSink`, `ArrayBufferSink`, `"type": "direct"` streams and other code related to streams work.
|
||||
- `./src/codegen/generate-classes.ts` -- Generates Rust & C++ bindings for JavaScriptCore classes implemented in Rust. `**/*.classes.ts` files define the interfaces for classes, methods, prototypes, and getters/setters; the code generator reads them to generate the boilerplate that implements the JavaScript objects in C++ and wires them up to Rust.
|
||||
- `./src/codegen/cppbind.ts` -- Scans the C++ bindings for functions marked with an export attribute and generates automatic Rust FFI wrappers (`cpp.rs`) for them.
|
||||
- `./src/codegen/bundle-modules.ts` -- Bundles built-in modules like `node:fs`, `bun:ffi` into files included in the final binary. In development, these can be reloaded without rebuilding native code (you still need to run `bun run build`, but it re-reads the transpiled files from disk afterwards). In release builds, these are embedded into the binary.
|
||||
- `./src/codegen/bundle-functions.ts` -- Bundles globally-accessible functions implemented in JavaScript/TypeScript like `ReadableStream` and `WritableStream`. These are used similarly to the builtin modules, but the output more closely aligns with what WebKit/Safari does for Safari's built-in functions, so implementations can be copy-pasted from WebKit as a starting point.
|
||||
|
||||
## Modifying ESM modules
|
||||
|
||||
Certain modules like `node:fs`, `node:stream`, `bun:sqlite`, and `ws` are implemented in JavaScript. These live in `src/js/{node,bun,thirdparty}` files and are pre-bundled using Bun.
|
||||
|
||||
## Release build
|
||||
|
||||
To compile a release build of Bun, run:
|
||||
|
||||
```bash
|
||||
bun run build:release
|
||||
```
|
||||
|
||||
The binaries are at `./build/release/bun` and `./build/release/bun-profile`.
|
||||
|
||||
### Download release build from pull requests
|
||||
|
||||
You can run the release build from a pull request without building it locally, which is useful for manually testing changes before they are merged.
|
||||
|
||||
Use the `bun-pr` npm package:
|
||||
|
||||
```sh
|
||||
bunx bun-pr <pr-number>
|
||||
bunx bun-pr <branch-name>
|
||||
bunx bun-pr "https://github.com/oven-sh/bun/pull/1234566"
|
||||
bunx bun-pr --asan <pr-number> # Linux x64 only
|
||||
```
|
||||
|
||||
`bun-pr` downloads the release build from the pull request's GitHub Actions artifacts and adds it to `$PATH` as `bun-${pr-number}`, so you can run it directly:
|
||||
|
||||
```sh
|
||||
bun-1234566 --version
|
||||
```
|
||||
|
||||
You may need the `gh` CLI installed to authenticate with GitHub.
|
||||
|
||||
### Viewing CI failures from the terminal
|
||||
|
||||
Bun's CI runs on BuildKite. Install the [BuildKite CLI](https://github.com/buildkite/cli) (`brew install buildkite/buildkite/bk`) and set `BUILDKITE_API_TOKEN` to a read-scoped [API token](https://buildkite.com/user/api-access-tokens). The repo includes a `.bk.yaml` so `bk` commands default to the `bun` pipeline.
|
||||
|
||||
```sh
|
||||
bun run ci:status # progress summary for the current branch's latest build
|
||||
bun run ci:errors # rendered test-failure output, tagged [new] vs [also on main]
|
||||
bun run ci:logs # save full logs for each failed job to ./tmp/ci-<build>/
|
||||
bun run ci:watch # watch until the build finishes
|
||||
bun run ci:find # print the build number (compose with raw `bk`)
|
||||
```
|
||||
|
||||
All of these accept a target: `#1234` (PR number), a PR URL, a branch name, or a build number. Without one they use the current git branch.
|
||||
|
||||
## AddressSanitizer
|
||||
|
||||
[AddressSanitizer](https://en.wikipedia.org/wiki/AddressSanitizer) helps find memory issues, and is enabled by default in debug builds of Bun on Linux and macOS. This covers the Rust code, the C++ bindings, and all dependencies. It makes the build take about 2x longer; if that's stopping you from being productive you can disable it with `bun run build:debug:noasan` (or pass `--asan=off` to `scripts/build.ts`), but generally we recommend batching your changes up between builds.
|
||||
|
||||
To build a release build with AddressSanitizer, run:
|
||||
|
||||
```bash
|
||||
bun run build:asan
|
||||
```
|
||||
|
||||
CI runs the test suite with at least one target built with AddressSanitizer.
|
||||
|
||||
## Building WebKit locally + Debug mode of JSC
|
||||
|
||||
WebKit is not cloned by default (to save time and disk space). To clone and build WebKit locally, run:
|
||||
|
||||
```bash
|
||||
# Clone WebKit into ./vendor/WebKit
|
||||
git clone https://github.com/oven-sh/WebKit vendor/WebKit
|
||||
|
||||
# Check out the version pinned in WEBKIT_VERSION in scripts/build/deps/webkit.ts
|
||||
# (a commit sha or an autobuild-* release tag; this handles both)
|
||||
bun sync-webkit-source
|
||||
|
||||
# Build bun with the local JSC build — this automatically configures and builds JSC
|
||||
bun run build:local
|
||||
```
|
||||
|
||||
`bun run build:local` handles everything: configuring JSC, building JSC, and building Bun. On subsequent runs, JSC rebuilds incrementally if any WebKit sources changed. `ninja -Cbuild/debug-local` also works after the first build, and builds both Bun and JSC.
|
||||
|
||||
The build output goes to `./build/debug-local` (instead of `./build/debug`), so you'll need to update a couple of places:
|
||||
|
||||
- The first line in `src/js/builtins.d.ts`
|
||||
- The `CompilationDatabase` line in `.clangd` config should be `CompilationDatabase: build/debug-local`
|
||||
- In `.vscode/launch.json`, many configurations use `./build/debug/`, change them as you see fit
|
||||
|
||||
The WebKit folder, including build artifacts, is 8GB+ in size.
|
||||
|
||||
If you are using a JSC debug build with VSCode, run the `C/C++: Select a Configuration` command so IntelliSense finds the debug headers.
|
||||
|
||||
If you make changes to Bun's [WebKit fork](https://github.com/oven-sh/WebKit), you also have to change `WEBKIT_VERSION` in `scripts/build/deps/webkit.ts` to point to your commit hash or release tag.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### 'span' file not found on Ubuntu
|
||||
|
||||
<Warning>
|
||||
⚠️ These instructions are specific to Ubuntu. The same issues are unlikely on other Linux distributions.
|
||||
</Warning>
|
||||
|
||||
Clang uses `libstdc++`, the C++ standard library implementation provided by the GNU Compiler Collection (GCC), by default. Clang can link against `libc++` instead, but that requires explicitly passing the `-stdlib` flag.
|
||||
|
||||
Bun relies on C++20 features like `std::span`, which are not available in GCC versions lower than 11. As a result, running `bun run build` may fail with the following error:
|
||||
|
||||
```txt
|
||||
fatal error: 'span' file not found
|
||||
#include <span>
|
||||
^~~~~~
|
||||
```
|
||||
|
||||
The issue may also surface when first running `bun run build`, with Clang unable to compile a simple program:
|
||||
|
||||
```txt
|
||||
The C++ compiler
|
||||
|
||||
"/usr/bin/clang++-21"
|
||||
|
||||
is not able to compile a simple test program.
|
||||
```
|
||||
|
||||
To fix the error, update GCC to version 11. It may be available in your distribution's official repositories; otherwise, add a third-party repository that provides GCC 11 packages:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install gcc-11 g++-11
|
||||
# If the above command fails with `Unable to locate package gcc-11` we need
|
||||
# to add the APT repository
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
# Now run `apt install` again
|
||||
sudo apt install gcc-11 g++-11
|
||||
```
|
||||
|
||||
Then set GCC 11 as the default compiler:
|
||||
|
||||
```bash
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 100
|
||||
```
|
||||
|
||||
### libarchive
|
||||
|
||||
If you see an error on macOS when compiling `libarchive`, run:
|
||||
|
||||
```bash
|
||||
brew install pkg-config
|
||||
```
|
||||
|
||||
### macOS `library not found for -lSystem`
|
||||
|
||||
If you see this error when compiling, run:
|
||||
|
||||
```bash
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
### Cannot find `libatomic.a`
|
||||
|
||||
Bun defaults to linking `libatomic` statically, as not all systems have it. If you are building on a distro that does not have a static libatomic available, enable dynamic linking with:
|
||||
|
||||
```bash
|
||||
bun run build --static-libatomic=off
|
||||
```
|
||||
|
||||
The built version of Bun may not work on other systems if compiled this way.
|
||||
|
||||
## Using bun-debug
|
||||
|
||||
- Disable logging: `BUN_DEBUG_QUIET_LOGS=1 bun-debug ...` (to disable all debug logging)
|
||||
- Enable logging for a specific scope: `BUN_DEBUG_EventLoop=1 bun-debug ...` (to enable `scoped_log!(EventLoop, ...)` output)
|
||||
- Bun transpiles every file it runs. To see the actual executed source in a debug build, find it in `/tmp/bun-debug-src/...path/to/file`. For example, the transpiled version of `/home/bun/index.ts` is in `/tmp/bun-debug-src/home/bun/index.ts`
|
||||
|
||||
## Contributing to the docs
|
||||
|
||||
The docs are the MDX files in `docs/` in the Bun repository. [bun.com/docs](https://bun.com/docs) is built from them.
|
||||
|
||||
### Voice
|
||||
|
||||
A docs page describes what Bun does and what you can do with it. Write it so that a developer who is new to Bun can read the page once and act on it. These guidelines are adapted from the [Next.js docs contribution guide](https://nextjs.org/docs/community/contribution-guide#voice):
|
||||
|
||||
- Write short sentences that each make one point. If a sentence needs several commas or a parenthetical, split it up or turn it into a list.
|
||||
- Use plain words: "use" rather than "utilize", "to" rather than "in order to". Cut filler such as "Note that" and "Please".
|
||||
- Use the active voice and name the actor: "Bun reads `bunfig.toml`", rather than "`bunfig.toml` is read". A sentence built around "is" and "by" is usually passive.
|
||||
- Describe current behavior in the present tense: "Bun installs the package", rather than "Bun will install the package".
|
||||
- Name the subject when "this" or "it" could refer to more than one thing: "`--isolate` is how Jest behaves by default", rather than "This is how Jest behaves by default".
|
||||
- Address the reader as "you", and make Bun (or the specific tool) the other actor: "Bun caches the tarball", rather than "we cache the tarball" or "let's cache the tarball".
|
||||
- Leave out "easy", "simple", "just", and "quick". They add nothing when a task is easy and discourage readers when it is not. State the concrete property instead: "one command", "no configuration".
|
||||
- Say what to do rather than what to avoid: "use `port: 0` so the operating system picks a free port", rather than "don't hardcode ports". State limitations plainly; a limitation is a fact, not a warning to the reader.
|
||||
- Use gender-neutral language: "developers", "users", "they".
|
||||
- Make link text name its destination: "see [`bun install`](/pm/cli/install)", rather than "see here".
|
||||
- Run every code example before you publish it, and check option names and defaults against the implementation on `main`.
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
title: License
|
||||
description: License for Bun
|
||||
---
|
||||
|
||||
Bun itself is MIT-licensed.
|
||||
|
||||
## JavaScriptCore
|
||||
|
||||
Bun statically links JavaScriptCore (and WebKit), which is LGPL-2 licensed. WebCore files from WebKit are also licensed under LGPL-2. Per LGPL-2:
|
||||
|
||||
> (1) If you statically link against an LGPL'd library, you must also provide your application in an object (not necessarily source) format, so that a user has the opportunity to modify the library and relink the application.
|
||||
|
||||
Bun's patched version of WebKit lives at https://github.com/oven-sh/webkit. To relink Bun with changes:
|
||||
|
||||
- `git clone https://github.com/oven-sh/WebKit vendor/WebKit`
|
||||
- `bun sync-webkit-source` (checks out the version pinned in `WEBKIT_VERSION` in `scripts/build/deps/webkit.ts`)
|
||||
- `bun run build:local`
|
||||
|
||||
`bun run build:local` compiles JavaScriptCore, compiles Bun's `.cpp` bindings for JavaScriptCore (the object files that use JavaScriptCore), and outputs a new `bun` binary with your changes.
|
||||
|
||||
## Linked libraries
|
||||
|
||||
Bun statically links these libraries:
|
||||
|
||||
| Library | License |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
|
||||
| [`boringssl`](https://boringssl.googlesource.com/boringssl/) | [several licenses](https://boringssl.googlesource.com/boringssl/+/refs/heads/master/LICENSE) |
|
||||
| [`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 (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 |
|
||||
| [`picohttp`](https://github.com/h2o/picohttpparser) | dual-licensed under the Perl License or the MIT License |
|
||||
| [`zstd`](https://github.com/facebook/zstd) | dual-licensed under the BSD License or GPLv2 license |
|
||||
| [`simdutf`](https://github.com/simdutf/simdutf) | Apache 2.0 |
|
||||
| [`tinycc`](https://github.com/tinycc/tinycc) | LGPL v2.1 |
|
||||
| [`uSockets`](https://github.com/uNetworking/uSockets) | Apache 2.0 |
|
||||
| [`zlib-ng`](https://github.com/zlib-ng/zlib-ng) | zlib |
|
||||
| [`c-ares`](https://github.com/c-ares/c-ares) | MIT licensed |
|
||||
| [`libicu`](https://github.com/unicode-org/icu) 78 | [ICU license](https://github.com/unicode-org/icu/blob/main/icu4c/LICENSE) |
|
||||
| [`libbase64`](https://github.com/aklomp/base64/blob/master/LICENSE) | BSD 2-Clause |
|
||||
| [`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 (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 |
|
||||
| [`sqlite`](https://sqlite.org) (on Linux and Windows) | [public domain](https://sqlite.org/copyright.html) |
|
||||
| A fork of [`uWebsockets`](https://github.com/jarred-sumner/uwebsockets) | Apache 2.0 licensed |
|
||||
| Parts of [Tigerbeetle's IO code](https://github.com/tigerbeetle/tigerbeetle/blob/532c8b70b9142c17e07737ab6d3da68d7500cbca/src/io/windows.zig#L1) | Apache 2.0 licensed |
|
||||
|
||||
## Polyfills
|
||||
|
||||
For compatibility, Bun embeds the following packages into its binary and injects them if imported.
|
||||
|
||||
| Package | License |
|
||||
| ------------------------------------------------------------------------ | ------- |
|
||||
| [`acorn`](https://github.com/acornjs/acorn) | MIT |
|
||||
| [`acorn-walk`](https://github.com/acornjs/acorn) | MIT |
|
||||
| [`assert`](https://npmjs.com/package/assert) | MIT |
|
||||
| [`browserify-zlib`](https://npmjs.com/package/browserify-zlib) | MIT |
|
||||
| [`buffer`](https://npmjs.com/package/buffer) | MIT |
|
||||
| [`constants-browserify`](https://npmjs.com/package/constants-browserify) | MIT |
|
||||
| [`crypto-browserify`](https://npmjs.com/package/crypto-browserify) | MIT |
|
||||
| [`domain-browser`](https://npmjs.com/package/domain-browser) | MIT |
|
||||
| [`events`](https://npmjs.com/package/events) | MIT |
|
||||
| [`https-browserify`](https://npmjs.com/package/https-browserify) | MIT |
|
||||
| [`os-browserify`](https://npmjs.com/package/os-browserify) | MIT |
|
||||
| [`path-browserify`](https://npmjs.com/package/path-browserify) | MIT |
|
||||
| [`process`](https://npmjs.com/package/process) | MIT |
|
||||
| [`punycode`](https://npmjs.com/package/punycode) | MIT |
|
||||
| [`querystring-es3`](https://npmjs.com/package/querystring-es3) | MIT |
|
||||
| [`stream-browserify`](https://npmjs.com/package/stream-browserify) | MIT |
|
||||
| [`stream-http`](https://npmjs.com/package/stream-http) | MIT |
|
||||
| [`string_decoder`](https://npmjs.com/package/string_decoder) | MIT |
|
||||
| [`timers-browserify`](https://npmjs.com/package/timers-browserify) | MIT |
|
||||
| [`tty-browserify`](https://npmjs.com/package/tty-browserify) | MIT |
|
||||
| [`url`](https://npmjs.com/package/url) | MIT |
|
||||
| [`util`](https://npmjs.com/package/util) | MIT |
|
||||
| [`vm-browserify`](https://npmjs.com/package/vm-browserify) | MIT |
|
||||
|
||||
## Additional credits
|
||||
|
||||
- Bun's JS transpiler and Node.js module resolver source code is a port of [@evanw](https://github.com/evanw)’s [esbuild](https://github.com/evanw/esbuild) project.
|
||||
- Bun's CSS parser source code is derived from the [Lightning CSS](https://github.com/parcel-bundler/lightningcss) and [Servo](https://github.com/servo/servo) projects.
|
||||
- Credit to [@kipply](https://github.com/kipply) for the name "Bun".
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Roadmap
|
||||
description: Bun's roadmap and long-term plans
|
||||
---
|
||||
|
||||
Bun is a project with a large scope and is still in its early days. Long-term, Bun aims to provide an all-in-one toolkit to replace the complex, fragmented toolchains common today: Node.js, Jest, Webpack, esbuild, Babel, yarn, PostCSS, and others.
|
||||
|
||||
See [Bun's Roadmap](https://github.com/oven-sh/bun/issues/159) on GitHub for the project's long-term plans and priorities.
|
||||
Reference in New Issue
Block a user