mirror of
https://github.com/oven-sh/bun
synced 2026-02-05 16:38:55 +00:00
Compare commits
107 Commits
repl
...
save-in-up
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17b5f79567 | ||
|
|
64033f11cc | ||
|
|
1c570b41bc | ||
|
|
500bd15fb5 | ||
|
|
687e31dc3a | ||
|
|
c3455c0cee | ||
|
|
9101774593 | ||
|
|
9a0ea00705 | ||
|
|
ec6b75ff54 | ||
|
|
a18e3ff451 | ||
|
|
eeb790a2f1 | ||
|
|
878b473085 | ||
|
|
6161c201e1 | ||
|
|
32664df254 | ||
|
|
15f7bacb8b | ||
|
|
473513db7e | ||
|
|
75b5c71540 | ||
|
|
c9c62f37e5 | ||
|
|
18b521d9b8 | ||
|
|
534fd30dbd | ||
|
|
3b2c0941e4 | ||
|
|
8d3829114e | ||
|
|
5f9c30b717 | ||
|
|
c55574b4d3 | ||
|
|
2f27e24778 | ||
|
|
b910db74be | ||
|
|
b37cb98a6e | ||
|
|
263382103f | ||
|
|
8777c3f72c | ||
|
|
996491f719 | ||
|
|
12c2da0ebf | ||
|
|
a3166457d3 | ||
|
|
b1bd93bffc | ||
|
|
4c113d1866 | ||
|
|
f9d2e687f5 | ||
|
|
31aec4ebe3 | ||
|
|
b432006e43 | ||
|
|
015f0a6e9a | ||
|
|
07a6443a80 | ||
|
|
6e4f746ace | ||
|
|
b5a3bed7f2 | ||
|
|
8615b8ad6b | ||
|
|
4992839232 | ||
|
|
03b8e9d5cf | ||
|
|
f267c1d097 | ||
|
|
c4507a5db3 | ||
|
|
c9a0ea96cd | ||
|
|
ca461f9e83 | ||
|
|
9c4765f616 | ||
|
|
e091290748 | ||
|
|
350403663e | ||
|
|
895f3824b5 | ||
|
|
58e69ef9f4 | ||
|
|
decad91d24 | ||
|
|
ea56182c5a | ||
|
|
9d6a8ee79d | ||
|
|
b55b511f68 | ||
|
|
49b9306dce | ||
|
|
2956ed4289 | ||
|
|
51d3d43822 | ||
|
|
edea4f095a | ||
|
|
07c88435e0 | ||
|
|
7121c1d6ab | ||
|
|
60dc76676c | ||
|
|
f64b504bae | ||
|
|
97153c5a5f | ||
|
|
d48ff53e4e | ||
|
|
afcbed218c | ||
|
|
682406c42c | ||
|
|
6fe40f383a | ||
|
|
e2d327881c | ||
|
|
4280f74429 | ||
|
|
8139a20c9f | ||
|
|
620f6c51ce | ||
|
|
ffe4f561a3 | ||
|
|
c896792c37 | ||
|
|
088491cb59 | ||
|
|
f27ef667c7 | ||
|
|
7d9820d478 | ||
|
|
b5da5168bf | ||
|
|
61569fab80 | ||
|
|
0887825f54 | ||
|
|
6d02b18680 | ||
|
|
1b8c6f266f | ||
|
|
989dd92ea8 | ||
|
|
9e3cabc540 | ||
|
|
3170cf08ba | ||
|
|
182d3f1567 | ||
|
|
189f0f7c36 | ||
|
|
a05a1780c1 | ||
|
|
822a00c4d5 | ||
|
|
f6a621f36a | ||
|
|
5b9d8b87c4 | ||
|
|
a7c3bc8a5a | ||
|
|
5424ea3403 | ||
|
|
4b63ced72d | ||
|
|
c8883a39a5 | ||
|
|
36e5a072a9 | ||
|
|
57a06745a4 | ||
|
|
4360ec83b4 | ||
|
|
3b9829f171 | ||
|
|
849a2cdfae | ||
|
|
77f1f2480d | ||
|
|
5e074209c6 | ||
|
|
0c2675c8d3 | ||
|
|
a79440f0c3 | ||
|
|
daaac7792c |
35
.github/ISSUE_TEMPLATE/1-install-problem.yml
vendored
35
.github/ISSUE_TEMPLATE/1-install-problem.yml
vendored
@@ -1,35 +0,0 @@
|
||||
name: 📥 Install Problem
|
||||
description: Report an issue during install or upgrade
|
||||
labels: [bug, install]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for submitting a bug report. It helps make Bun better.
|
||||
|
||||
If you need help or support using Bun, and are not reporting an issue, please
|
||||
join our [Discord](https://discord.gg/CXdq2DP29u) server, where you can ask questions in the [`#help`](https://discord.gg/32EtH6p7HN) forum.
|
||||
|
||||
Please try to include as much information as possible.
|
||||
- type: input
|
||||
attributes:
|
||||
label: What platform is your computer?
|
||||
description: |
|
||||
For MacOS and Linux: copy the output of `uname -mprs`
|
||||
For Windows: copy the output of `"$([Environment]::OSVersion | ForEach-Object VersionString) $(if ([Environment]::Is64BitOperatingSystem) { "x64" } else { "x86" })"` in the PowerShell console
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: How did you attempt to install or upgrade?
|
||||
description: Please provide the commands you ran to install or upgrade.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: What do you see instead?
|
||||
description: If possible, please provide text instead of a screenshot.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Is there anything else you think we should know?
|
||||
@@ -20,7 +20,7 @@ ARG ZIG_FILENAME=${ZIG_FOLDERNAME}.tar.xz
|
||||
ARG WEBKIT_URL="https://github.com/oven-sh/WebKit/releases/download/$WEBKIT_TAG/${WEBKIT_BASENAME}.tar.gz"
|
||||
ARG ZIG_URL="https://ziglang.org/builds/${ZIG_FILENAME}"
|
||||
ARG GIT_SHA=""
|
||||
ARG BUN_BASE_VERSION=0.8
|
||||
ARG BUN_BASE_VERSION=1.0
|
||||
|
||||
FROM bitnami/minideb:bullseye as bun-base
|
||||
|
||||
|
||||
4
Makefile
4
Makefile
@@ -38,7 +38,7 @@ NATIVE_OR_OLD_MARCH = -march=nehalem
|
||||
endif
|
||||
|
||||
MIN_MACOS_VERSION ?= $(DEFAULT_MIN_MACOS_VERSION)
|
||||
BUN_BASE_VERSION = 0.8
|
||||
BUN_BASE_VERSION = 1.0
|
||||
|
||||
CI ?= false
|
||||
|
||||
@@ -1880,7 +1880,7 @@ PACKAGE_MAP = --pkg-begin async_io $(BUN_DIR)/src/io/io_darwin.zig --pkg-begin b
|
||||
|
||||
.PHONY: base64
|
||||
base64:
|
||||
cd $(BUN_DEPS_DIR)/base64 && make clean && cmake $(CMAKE_FLAGS) . && make
|
||||
cd $(BUN_DEPS_DIR)/base64 && make clean && rm -rf CMakeCache.txt CMakeFiles && cmake $(CMAKE_FLAGS) . && make
|
||||
cp $(BUN_DEPS_DIR)/base64/libbase64.a $(BUN_DEPS_OUT_DIR)/libbase64.a
|
||||
|
||||
.PHONY: cold-jsc-start
|
||||
|
||||
12
SECURITY.md
Normal file
12
SECURITY.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 1.x.x | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Report any discovered vulnerabilities to the Bun team by emailing `security@bun.sh`. Your report will acknowledged within 5 days, and a team member will be assigned as the primary handler. To the greatest extent possible, the security team will endeavor to keep you informed of the progress being made towards a fix and full announcement, and may ask for additional information or guidance surrounding the reported issue.
|
||||
|
||||
@@ -10,7 +10,7 @@ To run in Bun:
|
||||
|
||||
```bash
|
||||
# so it doesn't run the vitest one
|
||||
bun wiptest expect-to-equal.test.js
|
||||
bun test expect-to-equal.test.js
|
||||
```
|
||||
|
||||
To run in Jest:
|
||||
|
||||
@@ -1,11 +1,33 @@
|
||||
# `install` benchmark
|
||||
|
||||
Requires [`hyperfine`](https://github.com/sharkdp/hyperfine)
|
||||
Requires [`hyperfine`](https://github.com/sharkdp/hyperfine). The goal of this benchmark is to compare installation performance of Bun with other package managers _when caches are hot_.
|
||||
|
||||
```
|
||||
### With lockfile, online mode
|
||||
|
||||
To run the benchmark with the standard "install" command for each package manager:
|
||||
|
||||
```sh
|
||||
$ hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'
|
||||
```
|
||||
|
||||
### With lockfile, offline mode
|
||||
|
||||
Even though all packages are cached, some tools may hit the npm API during the version resolution step. (This is not the same as re-downloading a package.) To entirely avoid network calls, the other package managers require `--prefer-offline/--offline` flag. To run the benchmark using "offline" mode:
|
||||
|
||||
```sh
|
||||
$ hyperfine --prepare 'rm -rf node_modules' --runs 1 'bun install' 'pnpm install --prefer-offline' 'yarn --offline' 'npm install --prefer-offline'
|
||||
```
|
||||
|
||||
### Without lockfile, offline mode
|
||||
|
||||
To run the benchmark with offline mode but without lockfiles:
|
||||
|
||||
```sh
|
||||
$ hyperfine --prepare 'rm -rf node_modules' --warmup 1 'rm bun.lockb && bun install' 'rm pnpm-lock.yaml && pnpm install --prefer-offline' 'rm yarn.lock && yarn --offline' 'rm package-lock.json && npm install --prefer-offline'
|
||||
```
|
||||
|
||||
##
|
||||
|
||||
To check that the app is working as expected:
|
||||
|
||||
```
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[test]
|
||||
# Large monorepos (like Bun) may want to specify the test directory more specifically
|
||||
# By default, `bun test` scans every single folder recurisvely which, if you
|
||||
# have a gigantic submodule (like WebKit), it has to do lots of directory
|
||||
# By default, `bun test` scans every single folder recursively which, if you
|
||||
# have a gigantic submodule (like WebKit), requires lots of directory
|
||||
# traversals
|
||||
#
|
||||
# Instead, we can just make it scan only the test directory for Bun's runtime tests
|
||||
# Instead, we can only scan the test directory for Bun's runtime tests
|
||||
root = "test"
|
||||
|
||||
@@ -74,7 +74,7 @@ dv.getUint8(0); // => 3
|
||||
// [0x11, 0x0, 0x0, 0x0]
|
||||
```
|
||||
|
||||
Now lets write a `Uint16` at byte offset `1`. This requires two bytes. We're using the value `513`, which is `2 * 256 + 1`; in bytes, that's `00000010 00000001`.
|
||||
Now let's write a `Uint16` at byte offset `1`. This requires two bytes. We're using the value `513`, which is `2 * 256 + 1`; in bytes, that's `00000010 00000001`.
|
||||
|
||||
```ts
|
||||
dv.setUint16(1, 513);
|
||||
@@ -90,7 +90,7 @@ console.log(dv.getUint8(1)); // => 2
|
||||
console.log(dv.getUint8(2)); // => 1
|
||||
```
|
||||
|
||||
Attempting to write a value that requires more space than is available in the underlying `ArrayBuffer` will cuase an error. Below we attempt to write a `Float64` (which requires 8 bytes) at byte offset `0`, but there are only four total bytes in the buffer.
|
||||
Attempting to write a value that requires more space than is available in the underlying `ArrayBuffer` will cause an error. Below we attempt to write a `Float64` (which requires 8 bytes) at byte offset `0`, but there are only four total bytes in the buffer.
|
||||
|
||||
```ts
|
||||
dv.setFloat64(0, 3.1415);
|
||||
@@ -412,7 +412,7 @@ For complete documentation, refer to the [Node.js documentation](https://nodejs.
|
||||
|
||||
`Blob` is a Web API commonly used for representing files. `Blob` was initially implemented in browsers (unlike `ArrayBuffer` which is part of JavaScript itself), but it is now supported in Node and Bun.
|
||||
|
||||
It isn't common to directly create `Blob` instances. More often, you'll recieve instances of `Blob` from an external source (like an `<input type="file">` element in the browser) or library. That said, it is possible to create a `Blob` from one or more string or binary "blob parts".
|
||||
It isn't common to directly create `Blob` instances. More often, you'll receive instances of `Blob` from an external source (like an `<input type="file">` element in the browser) or library. That said, it is possible to create a `Blob` from one or more string or binary "blob parts".
|
||||
|
||||
```ts
|
||||
const blob = new Blob(["<html>Hello</html>"], {
|
||||
@@ -507,7 +507,7 @@ for await (const chunk of stream) {
|
||||
}
|
||||
```
|
||||
|
||||
For a more complete discusson of streams in Bun, see [API > Streams](/docs/api/streams).
|
||||
For a more complete discussion of streams in Bun, see [API > Streams](/docs/api/streams).
|
||||
|
||||
## Conversion
|
||||
|
||||
|
||||
@@ -229,7 +229,11 @@ const lib = linkSymbols({
|
||||
},
|
||||
});
|
||||
|
||||
const [major, minor, patch] = [lib.symbols.getMajor(), lib.symbols.getMinor(), lib.symbols.getPatch()];
|
||||
const [major, minor, patch] = [
|
||||
lib.symbols.getMajor(),
|
||||
lib.symbols.getMinor(),
|
||||
lib.symbols.getPatch(),
|
||||
];
|
||||
```
|
||||
|
||||
## Callbacks
|
||||
@@ -249,10 +253,13 @@ const {
|
||||
},
|
||||
});
|
||||
|
||||
const searchIterator = new JSCallback((ptr, length) => /hello/.test(new CString(ptr, length)), {
|
||||
returns: "bool",
|
||||
args: ["ptr", "usize"],
|
||||
});
|
||||
const searchIterator = new JSCallback(
|
||||
(ptr, length) => /hello/.test(new CString(ptr, length)),
|
||||
{
|
||||
returns: "bool",
|
||||
args: ["ptr", "usize"],
|
||||
},
|
||||
);
|
||||
|
||||
const str = Buffer.from("wwutwutwutwutwutwutwutwutwutwutut\0", "utf8");
|
||||
if (search(ptr(str), searchIterator)) {
|
||||
@@ -376,10 +383,6 @@ If you want to track when a `TypedArray` is no longer in use from JavaScript, yo
|
||||
|
||||
#### From C, Rust, Zig, etc
|
||||
|
||||
{% callout %}
|
||||
**Note** — Available in Bun v0.1.8 and later.
|
||||
{% /callout %}
|
||||
|
||||
If you want to track when a `TypedArray` is no longer in use from C or FFI, you can pass a callback and an optional context pointer to `toArrayBuffer` or `toBuffer`. This function is called at some point later, once the garbage collector frees the underlying `ArrayBuffer` JavaScript object.
|
||||
|
||||
The expected signature is the same as in [JavaScriptCore's C API](https://developer.apple.com/documentation/javascriptcore/jstypedarraybytesdeallocator?language=objc):
|
||||
|
||||
@@ -195,7 +195,7 @@ const input = Bun.file("input.txt");
|
||||
await Bun.write(Bun.stdout, input);
|
||||
```
|
||||
|
||||
To write an HTTP response to disk:
|
||||
To write the body of an HTTP response to disk:
|
||||
|
||||
```ts
|
||||
const response = await fetch("https://bun.sh");
|
||||
|
||||
@@ -6,10 +6,6 @@ Bun implements the `createHash` and `createHmac` functions from [`node:crypto`](
|
||||
|
||||
## `Bun.password`
|
||||
|
||||
{% callout %}
|
||||
**Note** — Added in Bun 0.6.8.
|
||||
{% /callout %}
|
||||
|
||||
`Bun.password` is a collection of utility functions for hashing and verifying passwords with various cryptographically secure algorithms.
|
||||
|
||||
```ts
|
||||
@@ -136,7 +132,7 @@ hasher.digest();
|
||||
Once initialized, data can be incrementally fed to to the hasher using `.update()`. This method accepts `string`, `TypedArray`, and `ArrayBuffer`.
|
||||
|
||||
```ts
|
||||
const hasher = new Bun.CryptoHasher();
|
||||
const hasher = new Bun.CryptoHasher("sha256");
|
||||
|
||||
hasher.update("hello world");
|
||||
hasher.update(new Uint8Array([1, 2, 3]));
|
||||
@@ -174,7 +170,7 @@ hasher.update("hello world", "latin1");
|
||||
After the data has been feed into the hasher, a final hash can be computed using `.digest()`. By default, this method returns a `Uint8Array` containing the hash.
|
||||
|
||||
```ts
|
||||
const hasher = new Bun.CryptoHasher();
|
||||
const hasher = new Bun.CryptoHasher("sha256");
|
||||
hasher.update("hello world");
|
||||
|
||||
hasher.digest();
|
||||
|
||||
@@ -13,7 +13,7 @@ Start an HTTP server in Bun with `Bun.serve`.
|
||||
```ts
|
||||
Bun.serve({
|
||||
fetch(req) {
|
||||
return new Response(`Bun!`);
|
||||
return new Response("Bun!");
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -24,9 +24,9 @@ The `fetch` handler handles incoming requests. It receives a [`Request`](https:/
|
||||
Bun.serve({
|
||||
fetch(req) {
|
||||
const url = new URL(req.url);
|
||||
if (url.pathname === "/") return new Response(`Home page!`);
|
||||
if (url.pathname === "/") return new Response("Home page!");
|
||||
if (url.pathname === "/blog") return new Response("Blog!");
|
||||
return new Response(`404!`);
|
||||
return new Response("404!");
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -38,7 +38,7 @@ Bun.serve({
|
||||
port: 8080, // defaults to $BUN_PORT, $PORT, $NODE_PORT otherwise 3000
|
||||
hostname: "mydomain.com", // defaults to "0.0.0.0"
|
||||
fetch(req) {
|
||||
return new Response(`404!`);
|
||||
return new Response("404!");
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -140,12 +140,6 @@ Bun.serve({
|
||||
});
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
|
||||
**Note** — Earlier versions of Bun supported passing a file path as `keyFile` and `certFile`; this has been deprecated as of `v0.6.3`.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
If your private key is encrypted with a passphrase, provide a value for `passphrase` to decrypt it.
|
||||
|
||||
```ts-diff
|
||||
@@ -198,7 +192,7 @@ import {type Serve} from "bun";
|
||||
|
||||
export default {
|
||||
fetch(req) {
|
||||
return new Response(`Bun!`);
|
||||
return new Response("Bun!");
|
||||
},
|
||||
} satisfies Serve;
|
||||
```
|
||||
@@ -231,7 +225,7 @@ serve({
|
||||
⚡️ **Speed** — Bun automatically uses the [`sendfile(2)`](https://man7.org/linux/man-pages/man2/sendfile.2.html) system call when possible, enabling zero-copy file transfers in the kernel—the fastest way to send files.
|
||||
{% /callout %}
|
||||
|
||||
**[v0.3.0+]** You can send part of a file using the [`slice(start, end)`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice) method on the `Bun.file` object. This automatically sets the `Content-Range` and `Content-Length` headers on the `Response` object.
|
||||
You can send part of a file using the [`slice(start, end)`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice) method on the `Bun.file` object. This automatically sets the `Content-Range` and `Content-Length` headers on the `Response` object.
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
@@ -260,7 +254,7 @@ Below are Bun and Node.js implementations of a simple HTTP server that responds
|
||||
```ts#Bun
|
||||
Bun.serve({
|
||||
fetch(req: Request) {
|
||||
return new Response(`Bun!`);
|
||||
return new Response("Bun!");
|
||||
},
|
||||
port: 3000,
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ import.meta.resolveSync("zod")
|
||||
---
|
||||
|
||||
- `import.meta.resolve{Sync}`
|
||||
- Resolve a module specifier (e.g. `"zod"` or `"./file.tsx`) to an absolute path. While file would be imported if the specifier were imported from this file?
|
||||
- Resolve a module specifier (e.g. `"zod"` or `"./file.tsx"`) to an absolute path. While file would be imported if the specifier were imported from this file?
|
||||
|
||||
```ts
|
||||
import.meta.resolveSync("zod");
|
||||
|
||||
@@ -28,7 +28,9 @@ By default, the input stream of the subprocess is undefined; it can be configure
|
||||
|
||||
```ts
|
||||
const proc = Bun.spawn(["cat"], {
|
||||
stdin: await fetch("https://raw.githubusercontent.com/oven-sh/bun/main/examples/hashing.js"),
|
||||
stdin: await fetch(
|
||||
"https://raw.githubusercontent.com/oven-sh/bun/main/examples/hashing.js",
|
||||
),
|
||||
});
|
||||
|
||||
const text = await new Response(proc.stdout).text();
|
||||
@@ -209,7 +211,7 @@ Bun's `spawnSync` spawns processes 60% faster than the Node.js `child_process` m
|
||||
```bash
|
||||
$ bun spawn.mjs
|
||||
cpu: Apple M1 Max
|
||||
runtime: bun 0.2.0 (arm64-darwin)
|
||||
runtime: bun 1.x (arm64-darwin)
|
||||
|
||||
benchmark time (avg) (min … max) p75 p99 p995
|
||||
--------------------------------------------------------- -----------------------------
|
||||
@@ -230,10 +232,15 @@ A simple reference of the Spawn API and types are shown below. The real types ha
|
||||
```ts
|
||||
interface Bun {
|
||||
spawn(command: string[], options?: SpawnOptions.OptionsObject): Subprocess;
|
||||
spawnSync(command: string[], options?: SpawnOptions.OptionsObject): SyncSubprocess;
|
||||
spawnSync(
|
||||
command: string[],
|
||||
options?: SpawnOptions.OptionsObject,
|
||||
): SyncSubprocess;
|
||||
|
||||
spawn(options: { cmd: string[] } & SpawnOptions.OptionsObject): Subprocess;
|
||||
spawnSync(options: { cmd: string[] } & SpawnOptions.OptionsObject): SyncSubprocess;
|
||||
spawnSync(
|
||||
options: { cmd: string[] } & SpawnOptions.OptionsObject,
|
||||
): SyncSubprocess;
|
||||
}
|
||||
|
||||
namespace SpawnOptions {
|
||||
@@ -243,7 +250,12 @@ namespace SpawnOptions {
|
||||
stdin?: SpawnOptions.Readable;
|
||||
stdout?: SpawnOptions.Writable;
|
||||
stderr?: SpawnOptions.Writable;
|
||||
onExit?: (proc: Subprocess, exitCode: number | null, signalCode: string | null, error: Error | null) => void;
|
||||
onExit?: (
|
||||
proc: Subprocess,
|
||||
exitCode: number | null,
|
||||
signalCode: string | null,
|
||||
error: Error | null,
|
||||
) => void;
|
||||
}
|
||||
|
||||
type Readable =
|
||||
|
||||
@@ -76,12 +76,6 @@ Bun.listen({
|
||||
});
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
|
||||
**Note** — Earlier versions of Bun supported passing a file path as `keyFile` and `certFile`; this has been deprecated as of `v0.6.3`.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
The `key` and `cert` fields expect the _contents_ of your TLS key and certificate. This can be a string, `BunFile`, `TypedArray`, or `Buffer`.
|
||||
|
||||
```ts
|
||||
@@ -95,7 +89,7 @@ Bun.listen({
|
||||
// string
|
||||
key: fs.readFileSync("./key.pem", "utf8"),
|
||||
// array of above
|
||||
key: [Bun.file('./key1.pem'), Bun.file('./key2.pem')]
|
||||
key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@@ -76,7 +76,7 @@ await transpiler.transform("<div>hi!</div>", "tsx");
|
||||
```
|
||||
|
||||
{% details summary="Nitty gritty" %}
|
||||
The `.tranform()` method runs the transpiler in Bun's worker threadpool, so if you run it 100 times, it will run it across `Math.floor($cpu_count * 0.8)` threads, without blocking the main JavaScript thread.
|
||||
The `.transform()` method runs the transpiler in Bun's worker threadpool, so if you run it 100 times, it will run it across `Math.floor($cpu_count * 0.8)` threads, without blocking the main JavaScript thread.
|
||||
|
||||
If your code uses a macro, it will potentially spawn a new copy of Bun's JavaScript runtime environment in that new thread.
|
||||
{% /details %}
|
||||
@@ -160,7 +160,6 @@ export const name = "hello";
|
||||
`;
|
||||
|
||||
const result = transpiler.scanImports(code);
|
||||
`);
|
||||
```
|
||||
|
||||
```json#Results
|
||||
|
||||
@@ -43,7 +43,7 @@ This is analogous to the [`require.main = module` trick](https://stackoverflow.c
|
||||
|
||||
## `Bun.sleep()`
|
||||
|
||||
`Bun.sleep(ms: number)` (added in Bun v0.5.6)
|
||||
`Bun.sleep(ms: number)`
|
||||
|
||||
Returns a `Promise` that resolves after the given number of milliseconds.
|
||||
|
||||
@@ -65,7 +65,7 @@ console.log("hello one second later!");
|
||||
|
||||
## `Bun.sleepSync()`
|
||||
|
||||
`Bun.sleepSync(ms: number)` (added in Bun v0.5.6)
|
||||
`Bun.sleepSync(ms: number)`
|
||||
|
||||
A blocking synchronous version of `Bun.sleep`.
|
||||
|
||||
@@ -108,7 +108,7 @@ console.log(ls); // null
|
||||
|
||||
## `Bun.peek()`
|
||||
|
||||
`Bun.peek(prom: Promise)` (added in Bun v0.2.2)
|
||||
`Bun.peek(prom: Promise)`
|
||||
|
||||
Reads a promise's result without `await` or `.then`, but only if the promise has already fulfilled or rejected.
|
||||
|
||||
@@ -204,7 +204,7 @@ Bun.ArrayBufferSink;
|
||||
|
||||
## `Bun.deepEquals()`
|
||||
|
||||
Nestedly checks if two objects are equivalent. This is used internally by `expect().toEqual()` in `bun:test`.
|
||||
Recursively checks if two objects are equivalent. This is used internally by `expect().toEqual()` in `bun:test`.
|
||||
|
||||
```ts
|
||||
const foo = { a: 1, b: 2, c: { d: 3 } };
|
||||
|
||||
@@ -87,7 +87,7 @@ ws.send(new Uint8Array([1, 2, 3])); // TypedArray | DataView
|
||||
|
||||
### Headers
|
||||
|
||||
Once the upgrade succeeds, Bun will send a `101 Switching Protocols` response per the [spec](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism). Additional `headers` can be attched to this `Response` in the call to `server.upgrade()`.
|
||||
Once the upgrade succeeds, Bun will send a `101 Switching Protocols` response per the [spec](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism). Additional `headers` can be attached to this `Response` in the call to `server.upgrade()`.
|
||||
|
||||
```ts
|
||||
Bun.serve({
|
||||
@@ -236,7 +236,11 @@ This gives you better control over backpressure in your server.
|
||||
|
||||
## Connect to a `Websocket` server
|
||||
|
||||
To connect to an external socket server, either from a browser or from Bun, create an instance of `WebSocket` with the constructor.
|
||||
{% callout %}
|
||||
**🚧** — The `WebSocket` client still does not pass the full [Autobahn test suite](https://github.com/crossbario/autobahn-testsuite) and should not be considered ready for production.
|
||||
{% /callout %}
|
||||
|
||||
Bun implements the `WebSocket` class. To create a WebSocket client that connects to a `ws://` or `wss://` server, create an instance of `WebSocket`, as you would in the browser.
|
||||
|
||||
```ts
|
||||
const socket = new WebSocket("ws://localhost:3000");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% callout %}
|
||||
`Worker` support was added in Bun v0.7.0.
|
||||
**🚧** — The `Worker` API is still experimental and should not be considered ready for production.
|
||||
{% /callout %}
|
||||
|
||||
[`Worker`](https://developer.mozilla.org/en-US/docs/Web/API/Worker) lets you start and communicate with a new JavaScript instance running on a separate thread while sharing I/O resources with the main thread.
|
||||
@@ -123,7 +123,7 @@ By default, an active `Worker` will keep the main (spawning) process alive, so a
|
||||
|
||||
### `worker.unref()`
|
||||
|
||||
To stop a running worker from keeping the process alive, call `worker.unref()`. This decouples the lifetime of the worker to the lifetime of the main process, and is equivlent to what Node.js' `worker_threads` does.
|
||||
To stop a running worker from keeping the process alive, call `worker.unref()`. This decouples the lifetime of the worker to the lifetime of the main process, and is equivalent to what Node.js' `worker_threads` does.
|
||||
|
||||
```ts
|
||||
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
|
||||
|
||||
@@ -52,7 +52,6 @@ Run this with `bun cat.js /path/to/big/file`.
|
||||
## Reading from standard input
|
||||
|
||||
```ts
|
||||
// As of Bun v0.3.0, console is an AsyncIterable
|
||||
for await (const line of console) {
|
||||
// line of text from stdin
|
||||
console.log(line);
|
||||
|
||||
@@ -28,7 +28,7 @@ All imported files and packages are bundled into the executable, along with a co
|
||||
- `--outdir` — use `outfile` instead.
|
||||
- `--external`
|
||||
- `--splitting`
|
||||
- `--publicPath`
|
||||
- `--public-path`
|
||||
|
||||
{% /callout %}
|
||||
|
||||
|
||||
@@ -960,7 +960,7 @@ By specifying `.` as `root`, the generated file structure will look like this:
|
||||
|
||||
A prefix to be appended to any import paths in bundled code.
|
||||
|
||||
<!-- $ bun build ./index.tsx --outdir ./out --publicPath https://cdn.example.com -->
|
||||
<!-- $ bun build ./index.tsx --outdir ./out --public-path https://cdn.example.com -->
|
||||
|
||||
In many cases, generated bundles will contain no `import` statements. After all, the goal of bundling is to combine all of the code into a single file. However there are a number of cases with the generated bundles will contain `import` statements.
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ When a user visits this website, the files are loaded in the following order:
|
||||
|
||||
This approach works, it requires three round-trip HTTP requests before the browser is ready to render the page. On slow internet connections, this may add up to a non-trivial delay.
|
||||
|
||||
This example is extremely simplistic. A modern app may be loading dozens of modules from `node_modules`, each consisting of hundrends of files. Loading each of these files with a separate HTTP request becomes untenable very quickly. While most of these requests will be running in parallel, the number of round-trip requests can still be very high; plus, there are limits on how many simultaneous requests a browser can make.
|
||||
This example is extremely simplistic. A modern app may be loading dozens of modules from `node_modules`, each consisting of hundred of files. Loading each of these files with a separate HTTP request becomes untenable very quickly. While most of these requests will be running in parallel, the number of round-trip requests can still be very high; plus, there are limits on how many simultaneous requests a browser can make.
|
||||
|
||||
{% callout %}
|
||||
Some recent advances like modulepreload and HTTP/3 are intended to solve some of these problems, but at the moment bundling is still the most performant approach.
|
||||
|
||||
@@ -16,7 +16,7 @@ Parses the code and applies a set of default transforms, like dead-code eliminat
|
||||
|
||||
**JavaScript + JSX.**. Default for `.js` and `.jsx`.
|
||||
|
||||
Same as the `js` loader, but JSX syntax is supported. By default, JSX is downconverted to plain JavaScript; the details of how this is done depends on the `jsx*` compiler options in your `tsconfig.json`. Refer to the TypeScript documentation [on JSX](https://www.typescriptlang.org/docs/handbook/jsx.html) for more information.
|
||||
Same as the `js` loader, but JSX syntax is supported. By default, JSX is down-converted to plain JavaScript; the details of how this is done depends on the `jsx*` compiler options in your `tsconfig.json`. Refer to the TypeScript documentation [on JSX](https://www.typescriptlang.org/docs/handbook/jsx.html) for more information.
|
||||
|
||||
### `ts`
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ if (returnFalse()) {
|
||||
}
|
||||
```
|
||||
|
||||
## Serializablility
|
||||
## Serializability
|
||||
|
||||
Bun's transpiler needs to be able to serialize the result of the macro so it can be inlined into the AST. All JSON-compatible data structures are supported:
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
{% callout %}
|
||||
**Note** — Introduced in Bun v0.1.11.
|
||||
{% /callout %}
|
||||
|
||||
Bun provides a universal plugin API that can be used to extend both the _runtime_ and _bundler_.
|
||||
|
||||
Plugins intercept imports and perform custom loading logic: reading files, transpiling code, etc. They can be used to add support for additional file types, like `.scss` or `.yaml`. In the context of Bun's bundler, plugins can be used to implement framework-level features like CSS extraction, macros, and client-server code co-location.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
{% callout %}
|
||||
**Note** — Available in Bun v0.6.0 and later.
|
||||
{% /callout %}
|
||||
|
||||
Bun's bundler API is inspired heavily by [esbuild](https://esbuild.github.io/). Migrating to Bun's bundler from esbuild should be relatively painless. This guide will briefly explain why you might consider migrating to Bun's bundler and provide a side-by-side API comparison reference for those who are already familiar with esbuild's API.
|
||||
|
||||
There are a few behavioral differences to note.
|
||||
@@ -129,7 +125,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
|
||||
|
||||
- `--target`
|
||||
- n/a
|
||||
- No supported. Bun's bundler performs no syntactic downleveling at this time.
|
||||
- No supported. Bun's bundler performs no syntactic down-leveling at this time.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -13,8 +13,6 @@ If you pass `-y` or `--yes`, it will assume you want to continue without asking
|
||||
|
||||
At the end, it runs `bun install` to install `bun-types`.
|
||||
|
||||
Added in Bun v0.1.7.
|
||||
|
||||
#### How is `bun init` different than `bun create`?
|
||||
|
||||
`bun init` is for blank projects. `bun create` applies templates.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Bundling is currently an important mechanism for building complex web apps.
|
||||
|
||||
Modern apps typically consist of a large number of files and package dependencies. Despite the fact that modern browsers support [ES Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) imports, it's still too slow to fetch each file via inidividual HTTP requests. _Bundling_ is the process of concatenating several source files into a single large file that can be loaded in a single request.
|
||||
Modern apps typically consist of a large number of files and package dependencies. Despite the fact that modern browsers support [ES Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) imports, it's still too slow to fetch each file via individual HTTP requests. _Bundling_ is the process of concatenating several source files into a single large file that can be loaded in a single request.
|
||||
|
||||
{% callout %}
|
||||
**On bundling** — Despite recent advances like [`modulepreload`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload) and [HTTP/3](https://en.wikipedia.org/wiki/HTTP/3), bundling is still the most performant approach.
|
||||
|
||||
@@ -50,7 +50,7 @@ Running `bun create` performs the following steps:
|
||||
- Initialize a fresh Git repo. Opt out with the `--no-git` flag.
|
||||
- Run the template's configured `start` script, if defined.
|
||||
|
||||
## Official templates
|
||||
<!-- ## Official templates
|
||||
|
||||
The following official templates are available.
|
||||
|
||||
@@ -73,7 +73,7 @@ Welcome to bun! Create a new project by pasting any of the following:
|
||||
|
||||
{% callout %}
|
||||
⚡️ **Speed** — At the time of writing, `bun create react app` runs ~11x faster on a M1 Macbook Pro than `yarn create react-app app`.
|
||||
{% /callout %}
|
||||
{% /callout %} -->
|
||||
|
||||
## GitHub repos
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ $ bun install --silent # no logging
|
||||
```
|
||||
|
||||
{% details summary="Configuring behavior" %}
|
||||
The default behavior of `bun install` can be configured in `bun.toml`:
|
||||
The default behavior of `bun install` can be configured in `bunfig.toml`:
|
||||
|
||||
```toml
|
||||
[install]
|
||||
@@ -197,7 +197,7 @@ $ cat package.json
|
||||
"version": "1.0.0"
|
||||
}
|
||||
$ bun link
|
||||
bun link v0.5.7 (7416672e)
|
||||
bun link v1.x (7416672e)
|
||||
Success! Registered "cool-pkg"
|
||||
|
||||
To use cool-pkg in a project, run:
|
||||
@@ -289,7 +289,7 @@ Bun supports a variety of protocols, including [`github`](https://docs.npmjs.com
|
||||
|
||||
## Tarball dependencies
|
||||
|
||||
A package name can correspond to a publically hosted `.tgz` file. During `bun install`, Bun will download and install the package from the specified tarball URL, rather than from the package registry.
|
||||
A package name can correspond to a publicly hosted `.tgz` file. During `bun install`, Bun will download and install the package from the specified tarball URL, rather than from the package registry.
|
||||
|
||||
```json#package.json
|
||||
{
|
||||
|
||||
@@ -42,10 +42,6 @@ $ bun --watch run index.tsx
|
||||
|
||||
### `--smol`
|
||||
|
||||
{% callout %}
|
||||
Added in Bun v0.7.0.
|
||||
{% /callout %}
|
||||
|
||||
In memory-constrained environments, use the `--smol` flag to reduce memory usage at a cost to performance.
|
||||
|
||||
```bash
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
[Buchta](https://buchtajs.com) is a fullstack framework designed to take full advantage of Bun's strengths. It currently supports Preact and Svelte.
|
||||
|
||||
To get started:
|
||||
|
||||
```bash
|
||||
$ bunx buchta init myapp
|
||||
Project templates:
|
||||
- svelte
|
||||
- default
|
||||
- preact
|
||||
Name of template: preact
|
||||
Do you want TSX? y
|
||||
Do you want SSR? y
|
||||
Enable livereload? y
|
||||
Buchta Preact project was setup successfully!
|
||||
$ cd myapp
|
||||
$ bun install
|
||||
$ bunx buchta serve
|
||||
```
|
||||
|
||||
To implement a simple HTTP server with Buchta:
|
||||
|
||||
```ts#server.ts
|
||||
import { Buchta, type BuchtaRequest, type BuchtaResponse } from "buchta";
|
||||
|
||||
const app = new Buchta();
|
||||
|
||||
app.get("/api/hello/", (req: BuchtaRequest, res: BuchtaResponse) => {
|
||||
res.send("Hello, World!");
|
||||
});
|
||||
|
||||
app.run();
|
||||
```
|
||||
|
||||
|
||||
For more information, refer to Buchta's [documentation](https://buchtajs.com/docs/).
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Convert a Blob to a ReadableStream
|
||||
---
|
||||
|
||||
The [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) class provides a number of methods for consuming its contents in different formats, inluding `.stream()`. This returns `Promise<ReadableStream>`.
|
||||
The [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) class provides a number of methods for consuming its contents in different formats, including `.stream()`. This returns `Promise<ReadableStream>`.
|
||||
|
||||
```ts
|
||||
const blob = new Blob(["hello world"]);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Convert a Blob to a string
|
||||
---
|
||||
|
||||
The [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) class provides a number of methods for consuming its contents in different formats, inluding `.text()`.
|
||||
The [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) class provides a number of methods for consuming its contents in different formats, including `.text()`.
|
||||
|
||||
```ts
|
||||
const blob = new Blob(["hello world"]);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Create a Discord bot
|
||||
---
|
||||
|
||||
Discord.js works [out of the box](https://bun.sh/blog/bun-v0.6.7) with Bun. Let's write a simple bot. First create a directory and initialize it with `bun init`.
|
||||
Discord.js works out of the box with Bun. Let's write a simple bot. First create a directory and initialize it with `bun init`.
|
||||
|
||||
```bash
|
||||
mkdir my-bot
|
||||
@@ -74,4 +74,4 @@ Ready! Logged in as my-bot#1234
|
||||
|
||||
---
|
||||
|
||||
You're up and running with a bare-bones Discord.js bot! This is a basic guide to setting up your bot with Bun; we recommend the [official Discord docs](https://discordjs.guide/) for complete information on the `discord.js` API.
|
||||
You're up and running with a bare-bones Discord.js bot! This is a basic guide to setting up your bot with Bun; we recommend the [official discord.js docs](https://discordjs.guide/) for complete information on the `discord.js` API.
|
||||
|
||||
@@ -33,11 +33,18 @@ const animalSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {type: String, required: true},
|
||||
sound: {type: String, required: true},
|
||||
},
|
||||
{
|
||||
methods: {
|
||||
speak() {
|
||||
console.log(`${this.sound}!`);
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export type Animal = mongoose.InferSchemaType<typeof animalSchema>;
|
||||
export const Animal = mongoose.model('Kitten', animalSchema);
|
||||
export const Animal = mongoose.model('Animal', animalSchema);
|
||||
```
|
||||
|
||||
---
|
||||
@@ -62,13 +69,13 @@ await cow.save(); // saves to the database
|
||||
const animals = await Animal.find();
|
||||
animals[0].speak(); // logs "Moo!"
|
||||
|
||||
// disconect
|
||||
// disconnect
|
||||
await mongoose.disconnect();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Lets run this with `bun run`.
|
||||
Let's run this with `bun run`.
|
||||
|
||||
```bash
|
||||
$ bun run index.ts
|
||||
|
||||
@@ -9,7 +9,7 @@ $ bunx nuxi init my-nuxt-app
|
||||
✔ Which package manager would you like to use?
|
||||
bun
|
||||
◐ Installing dependencies...
|
||||
bun install v0.8.1 (16b4bf34)
|
||||
bun install v1.x (16b4bf34)
|
||||
+ @nuxt/devtools@0.8.2
|
||||
+ nuxt@3.7.0
|
||||
785 packages installed [2.67s]
|
||||
@@ -45,9 +45,9 @@ Nuxt 3.6.5 with Nitro 2.5.2
|
||||
|
||||
---
|
||||
|
||||
Once the dev server spins up, open [http://localhost:3000](http://localhost:3000) to see the app. The app will render Nuxt's built-in `WelcomePage` template component.
|
||||
Once the dev server spins up, open [http://localhost:3000](http://localhost:3000) to see the app. The app will render Nuxt's built-in `NuxtWelcome` template component.
|
||||
|
||||
To start developing your app, replace `<WelcomePage />` in `app.vue` with your own UI.
|
||||
To start developing your app, replace `<NuxtWelcome />` in `app.vue` with your own UI.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/2c683ecc-3298-4bb0-b8c0-cf4cfaea1daa" caption="Demo Nuxt app running on localhost" /%}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ cloned solidjs/solid-start#main to /path/to/my-app/.solid-start
|
||||
|
||||
---
|
||||
|
||||
As instructed by the `create-solid` CLI, lets install our dependencies.
|
||||
As instructed by the `create-solid` CLI, let's install our dependencies.
|
||||
|
||||
```sh
|
||||
$ cd my-app
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Build an app with SvelteKit and Bun
|
||||
---
|
||||
|
||||
Use `bunx` to scaffold your app with the `create-svelte` CLI. Answer the prompts to slect a template and set up your development environment.
|
||||
Use `bunx` to scaffold your app with the `create-svelte` CLI. Answer the prompts to select a template and set up your development environment.
|
||||
|
||||
```sh
|
||||
$ bunx create-svelte my-app
|
||||
@@ -63,3 +63,58 @@ Visit [http://localhost:5173](http://localhost:5173/) in a browser to see the te
|
||||
---
|
||||
|
||||
If you edit and save `src/routes/+page.svelte`, you should see your changes hot-reloaded in the browser.
|
||||
|
||||
---
|
||||
|
||||
To build for production, you'll need to add the right SvelteKit adapter. Currently we recommend the
|
||||
|
||||
`bun add -D svelte-adapter-bun`.
|
||||
|
||||
Now, make the following changes to your `svelte.config.js`.
|
||||
|
||||
```ts-diff
|
||||
- import adapter from "@sveltejs/adapter-auto";
|
||||
+ import adapter from "svelte-adapter-bun";
|
||||
import { vitePreprocess } from "@sveltejs/kit/vite";
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
},
|
||||
preprocess: vitePreprocess(),
|
||||
};
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To build a production bundle:
|
||||
|
||||
```sh
|
||||
$ bun run build
|
||||
$ vite build
|
||||
|
||||
vite v4.4.9 building SSR bundle for production...
|
||||
transforming (60) node_modules/@sveltejs/kit/src/utils/escape.js
|
||||
|
||||
✓ 98 modules transformed.
|
||||
Generated an empty chunk: "entries/endpoints/waitlist/_server.ts".
|
||||
|
||||
vite v4.4.9 building for production...
|
||||
✓ 92 modules transformed.
|
||||
Generated an empty chunk: "7".
|
||||
.svelte-kit/output/client/_app/version.json 0.03 kB │ gzip: 0.05 kB
|
||||
|
||||
...
|
||||
|
||||
.svelte-kit/output/server/index.js 86.47 kB
|
||||
|
||||
Run npm run preview to preview your production build locally.
|
||||
|
||||
> Using svelte-adapter-bun
|
||||
✔ Start server with: bun ./build/index.js
|
||||
✔ done
|
||||
✓ built in 7.81s
|
||||
```
|
||||
|
||||
@@ -8,7 +8,7 @@ While Vite currently works with Bun, it has not been heavily optimized, nor has
|
||||
|
||||
---
|
||||
|
||||
Vite works out of the box with Bun (v0.7 and later). Get started with one of Vite's templates.
|
||||
Vite works out of the box with Bun. Get started with one of Vite's templates.
|
||||
|
||||
```bash
|
||||
$ bunx create-vite my-app
|
||||
|
||||
@@ -59,7 +59,7 @@ Listening on http://localhost:4000
|
||||
|
||||
Our form will send a `POST` request to the `/action` endpoint with the form data. Let's handle that request in our server.
|
||||
|
||||
First we use the [`.formData()`](https://developer.mozilla.org/en-US/docs/Web/API/Request/formData) method on the incoming `Request` to asynchonously parse its contents to a `FormData` instance. Then we can use the [`.get()`](https://developer.mozilla.org/en-US/docs/Web/API/FormData/get) method to extract the value of the `name` and `profilePicture` fields. Here `name` corresponds to a `string` and `profilePicture` is a `Blob`.
|
||||
First we use the [`.formData()`](https://developer.mozilla.org/en-US/docs/Web/API/Request/formData) method on the incoming `Request` to asynchronously parse its contents to a `FormData` instance. Then we can use the [`.get()`](https://developer.mozilla.org/en-US/docs/Web/API/FormData/get) method to extract the value of the `name` and `profilePicture` fields. Here `name` corresponds to a `string` and `profilePicture` is a `Blob`.
|
||||
|
||||
Finally, we write the `Blob` to disk using [`Bun.write()`](/docs/api/file-io#writing-files-bun-write).
|
||||
|
||||
@@ -81,7 +81,7 @@ const server = Bun.serve({
|
||||
+ if (url.pathname === '/action') {
|
||||
+ const formdata = await req.formData();
|
||||
+ const name = formdata.get('name');
|
||||
+ const profilePicture = formdata.get('profilePicture');+
|
||||
+ const profilePicture = formdata.get('profilePicture');
|
||||
+ if (!profilePicture) throw new Error('Must upload a profile picture.');
|
||||
+ // write profilePicture to disk
|
||||
+ await Bun.write('profilePicture.png', profilePicture);
|
||||
|
||||
29
docs/guides/install/trusted.md
Normal file
29
docs/guides/install/trusted.md
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Add a trusted dependency
|
||||
---
|
||||
|
||||
Unlike other npm clients, Bun does not execute arbitrary lifecycle scripts for installed dependencies, such as `postinstall` and `node-gyp` builds. These scripts represent a potential security risk, as they can execute arbitrary code on your machine.
|
||||
|
||||
---
|
||||
|
||||
To tell Bun to allow lifecycle scripts for a particular package, add the package to `trustedDependencies` in your package.json.
|
||||
|
||||
```json-diff
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "1.0.0",
|
||||
+ "trustedDependencies": ["my-trusted-package"]
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Bun maintains an allow-list of popular packages containing `postinstall` scripts that are known to be safe. To run lifecycle scripts for packages that aren't on this list, add the package to `trustedDependencies` in your package.json. -->
|
||||
|
||||
---
|
||||
|
||||
Note that this only allows lifecycle scripts for the specific package listed in `trustedDependencies`, _not_ the dependencies of that dependency!
|
||||
|
||||
Soon, Bun will include a built-in allow-list that automatically allows lifecycle scripts to be run by popular packages that are known to be safe. This is still under development.
|
||||
|
||||
---
|
||||
|
||||
See [Docs > Package manager > Trusted dependencies](/docs/cli/install#trusted-dependencies) for complete documentation of trusted dependencies.
|
||||
@@ -35,7 +35,7 @@ It's common to place all packages in a `packages` directory. The `"workspaces"`
|
||||
|
||||
---
|
||||
|
||||
To add one workspace as a dependency of another, modify its `package.json`. Here were adding `stuff-a` as a dependency of `stuff-b`.
|
||||
To add one workspace as a dependency of another, modify its `package.json`. Here we're adding `stuff-a` as a dependency of `stuff-b`.
|
||||
|
||||
```json#packages/stuff-b/package.json
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ The `Bun.file()` function accepts a path and returns a `BunFile` instance. Use t
|
||||
const path = "/path/to/package.json";
|
||||
const file = Bun.file(path);
|
||||
|
||||
file.exists(); // boolean;
|
||||
await file.exists(); // boolean;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
41
docs/guides/runtime/vscode-debugger.md
Normal file
41
docs/guides/runtime/vscode-debugger.md
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
name: Debugging Bun with the VS Code extension
|
||||
---
|
||||
|
||||
Bun speaks the [WebKit Inspector Protocol](https://github.com/oven-sh/bun/blob/main/packages/bun-vscode/types/jsc.d.ts) so you can debug your code with an interactive debugger.
|
||||
|
||||
---
|
||||
|
||||
To install the extension, visit the [Bun for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=oven.bun-vscode) page on the VS Code marketplace website, then click Install.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/7c8c80e6-d49e-457a-a45e-45ebed946d56" /%}
|
||||
|
||||
---
|
||||
|
||||
Alternatively, search `bun-vscode` in the Extensions tab of VS Code.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/664b4c40-944c-4076-a4c2-f812aebd3dc9" /%}
|
||||
|
||||
---
|
||||
|
||||
Make sure you are installing the extension published by the verified Oven organization.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/73e6b09f-9ff1-4d85-b725-c5eb7215b6ae" /%}
|
||||
|
||||
---
|
||||
|
||||
Once installed, two new Bun-specific commands will appear in the Command Palette. To open the palette, click View > Command Palette, or type `Ctrl+Shift+P` (Windows, Linux) or `Cmd+Shift+P` on (Mac).
|
||||
|
||||
---
|
||||
|
||||
The `Bun: Run File` command will execute your code and print the output to the Debug Console in VS Code. Breakpoints will be ignored; this is similar to executing the file with `bun <file>` from the command line.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/1b2c7fd9-fbb9-486a-84d0-eb7ec135ded3" /%}
|
||||
|
||||
---
|
||||
|
||||
The `Bun: Debug File` command will execute your code and print the output to the Debug Console in VS Code. You can set breakpoints in your code by clicking to the left of a line number; a red dot should appear.
|
||||
|
||||
When you run the file with `Bun: Debug File`, execution will pause at the breakpoint. You can inspect the variables in scope and step through the code line-by-line using the VS Code controls.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/c579a36c-eb21-4a58-bc9c-74612aad82af" /%}
|
||||
@@ -49,7 +49,7 @@ test("set button text", () => {
|
||||
|
||||
---
|
||||
|
||||
With Happy DOM propertly configured, this test runs as expected.
|
||||
With Happy DOM properly configured, this test runs as expected.
|
||||
|
||||
```sh
|
||||
$ bun test
|
||||
|
||||
112
docs/guides/test/migrate-from-jest.md
Normal file
112
docs/guides/test/migrate-from-jest.md
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: Migrate from Jest to Bun's test runner
|
||||
---
|
||||
|
||||
In many cases, Bun's test runner can run Jest test suites with no code changes. Just run `bun test` instead of `npx jest`, `yarn test`, etc.
|
||||
|
||||
```sh-diff
|
||||
- $ npx jest
|
||||
- $ yarn test
|
||||
+ $ bun test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
There's often no need for code changes.
|
||||
|
||||
- Bun internally re-writes imports from `@jest/globals` to use the `bun:test` equivalents.
|
||||
- If you're relying on Jest to inject `test`, `expect`, etc. as globals, Bun does that too.
|
||||
|
||||
But if you'd rather switch to the `bun:test` imports, you can do that too.
|
||||
|
||||
```ts-diff
|
||||
- import {test, expect} from "@jest/globals";
|
||||
+ import {test, expect} from "bun:test";
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Bun implements the vast majority of Jest's matchers, but compatibility isn't 100% yet. Refer to the full compatibility table at [Docs > Test runner > Writing tests](/docs/test/writing#matchers).
|
||||
|
||||
Some notable missing features:
|
||||
|
||||
- `expect.extend()`
|
||||
- `expect().toMatchInlineSnapshot()`
|
||||
- `expect().toHaveBeenCalledWith()`
|
||||
- `expect().toHaveReturned()`
|
||||
|
||||
---
|
||||
|
||||
If you're using `testEnvironment: "jsdom"` to run your tests in a browser-like environment, you should follow the [DOM testing with Bun and happy-dom](/guides/test/happy-dom) guide to inject browser APIs into the global scope. This guide relies on [`happy-dom`](https://github.com/capricorn86/happy-dom), which is a leaner and faster alternative to [`jsdom`](https://github.com/jsdom/jsdom).
|
||||
|
||||
At the moment jsdom does not work in Bun due to its internal use of V8 APIs. Track support for it [here](https://github.com/oven-sh/bun/issues/3554).
|
||||
|
||||
```toml#bunfig.toml
|
||||
[test]
|
||||
preload = ["./happy-dom.ts"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Replace `bail` in your Jest config with the `--bail` CLI flag.
|
||||
|
||||
<!-- ```ts-diff
|
||||
- import type {Config} from 'jest';
|
||||
-
|
||||
- const config: Config = {
|
||||
- bail: 3
|
||||
- };
|
||||
``` -->
|
||||
|
||||
```sh-diff
|
||||
$ bun test --bail 3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Replace `collectCoverage` with the `--coverage` CLI flag.
|
||||
|
||||
<!-- ```ts-diff
|
||||
- import type {Config} from 'jest';
|
||||
-
|
||||
- const config: Config = {
|
||||
- collectCoverageFrom: [
|
||||
- '**/*.{js,jsx}',
|
||||
- '!**/node_modules/**',
|
||||
- '!**/vendor/**',
|
||||
- ],
|
||||
- };
|
||||
``` -->
|
||||
|
||||
```sh
|
||||
$ bun test --coverage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Replace `testTimeout` with the `--test-timeout` CLI flag.
|
||||
|
||||
```sh
|
||||
$ bun test --timeout 10000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Many other flags become irrelevant or obsolete when using `bun test`.
|
||||
|
||||
- `transform` — Buns supports TypeScript & JSX. Other file types can be configured with [Plugins](/docs/runtime/plugins).
|
||||
- `extensionsToTreatAsEsm`
|
||||
- `haste` — Bun uses it's own internal source maps
|
||||
- `watchman`, `watchPlugins`, `watchPathIgnorePatterns` — use `--watch` to run tests in watch mode
|
||||
- `verbose` — set `logLevel: "debug"` in [`bunfig.toml`](/docs/runtime/configuration.md#runtime)
|
||||
|
||||
---
|
||||
|
||||
Settings that aren't mentioned here are not supported or have no equivalent. Please [file a feature request](https://github.com/oven-sh/bun) if something important is missing.
|
||||
|
||||
---
|
||||
|
||||
See also:
|
||||
|
||||
- [Mark a test as a todo](/guides/test/todo-tests)
|
||||
- [Docs > Test runner > Writing tests](/docs/test/writing)
|
||||
@@ -21,7 +21,7 @@ Here's what the output of a typical test run looks like. In this case, there are
|
||||
|
||||
```sh
|
||||
$ bun test
|
||||
bun test v0.8.0 (9c68abdb)
|
||||
bun test v1.x (9c68abdb)
|
||||
|
||||
test.test.js:
|
||||
✓ add [0.87ms]
|
||||
@@ -47,7 +47,7 @@ To only run certain test files, pass a positional argument to `bun test`. The ru
|
||||
|
||||
```sh
|
||||
$ bun test test3
|
||||
bun test v0.8.0 (9c68abdb)
|
||||
bun test v1.x (9c68abdb)
|
||||
|
||||
test3.test.js:
|
||||
✓ add [1.40ms]
|
||||
@@ -85,7 +85,7 @@ Adding `-t add` will only run tests with "add" in the name. This works with test
|
||||
|
||||
```sh
|
||||
$ bun test -t add
|
||||
bun test v0.8.0 (9c68abdb)
|
||||
bun test v1.x (9c68abdb)
|
||||
|
||||
test.test.js:
|
||||
✓ add [1.79ms]
|
||||
|
||||
@@ -22,7 +22,7 @@ The first time this test is executed, Bun will evaluate the value passed into `e
|
||||
|
||||
```sh
|
||||
$ bun test test/snap
|
||||
bun test v0.8.0 (9c68abdb)
|
||||
bun test v1.x (9c68abdb)
|
||||
|
||||
test/snap.test.ts:
|
||||
✓ snapshot [1.48ms]
|
||||
@@ -65,7 +65,7 @@ Later, when this test file is executed again, Bun will read the snapshot file an
|
||||
|
||||
```sh
|
||||
$ bun test
|
||||
bun test v0.8.0 (9c68abdb)
|
||||
bun test v1.x (9c68abdb)
|
||||
|
||||
test/snap.test.ts:
|
||||
✓ snapshot [1.05ms]
|
||||
@@ -82,7 +82,7 @@ To update snapshots, use the `--update-snapshots` flag.
|
||||
|
||||
```sh
|
||||
$ bun test --update-snapshots
|
||||
bun test v0.8.0 (9c68abdb)
|
||||
bun test v1.x (9c68abdb)
|
||||
|
||||
test/snap.test.ts:
|
||||
✓ snapshot [0.86ms]
|
||||
|
||||
@@ -36,7 +36,7 @@ Once the spy is created, it can be used to write `expect` assertions relating to
|
||||
+ test("turtles", ()=>{
|
||||
+ expect(spy).toHaveBeenCalledTimes(0);
|
||||
+ leo.sayHi("pizza");
|
||||
+ expect(spy).toHaveBeenCalledTimes(0);
|
||||
+ expect(spy).toHaveBeenCalledTimes(1);
|
||||
+ expect(spy.mock.calls).toEqual([[ "pizza" ]]);
|
||||
+ })
|
||||
```
|
||||
|
||||
@@ -44,7 +44,7 @@ test.todo("unimplemented feature", () => {
|
||||
|
||||
---
|
||||
|
||||
If an implementation is provides, it will be executed and _expected to fail_ by test runner! If a todo test passes, the `bun test` run will return a non-zero exit code to signal the failure.
|
||||
If an implementation is provided, it will be executed and _expected to fail_ by test runner! If a todo test passes, the `bun test` run will return a non-zero exit code to signal the failure.
|
||||
|
||||
```sh
|
||||
$ bun test
|
||||
|
||||
@@ -33,7 +33,7 @@ To regenerate snapshots, use the `--update-snapshots` flag.
|
||||
|
||||
```sh
|
||||
$ bun test --update-snapshots
|
||||
bun test v0.8.0 (9c68abdb)
|
||||
bun test v1.x (9c68abdb)
|
||||
|
||||
test/snap.test.ts:
|
||||
✓ snapshot [0.86ms]
|
||||
|
||||
@@ -6,7 +6,7 @@ Use `Bun.gzipSync()` to compress a `Uint8Array` with gzip.
|
||||
|
||||
```ts
|
||||
const data = Buffer.from("Hello, world!");
|
||||
const compressed = Bun.gzipSync("Hello, world!");
|
||||
const compressed = Bun.gzipSync(data);
|
||||
// => Uint8Array
|
||||
|
||||
const decompressed = Bun.gunzipSync(compressed);
|
||||
|
||||
@@ -24,7 +24,7 @@ Bun.serve({
|
||||
websocket: {
|
||||
async message(ws, message) {
|
||||
// send a compressed message
|
||||
ws.send("Hello world!", true);
|
||||
ws.send(message, true);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -29,5 +29,5 @@ const server = Bun.serve<{ authToken: string }>({
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Listening on localhost:\${server.port}`);
|
||||
console.log(`Listening on localhost:${server.port}`);
|
||||
```
|
||||
|
||||
@@ -66,7 +66,7 @@ Bun is designed from the ground-up with today's JavaScript ecosystem in mind.
|
||||
- **TypeScript & JSX support**. You can directly execute `.jsx`, `.ts`, and `.tsx` files; Bun's transpiler converts these to vanilla JavaScript before execution.
|
||||
- **ESM & CommonJS compatibility**. The world is moving towards ES modules (ESM), but millions of packages on npm still require CommonJS. Bun recommends ES modules, but supports CommonJS.
|
||||
- **Web-standard APIs**. Bun implements standard Web APIs like `fetch`, `WebSocket`, and `ReadableStream`. Bun is powered by the JavaScriptCore engine, which is developed by Apple for Safari, so some APIs like [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) and [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) directly use [Safari's implementation](https://github.com/oven-sh/bun/blob/HEAD/src/bun.js/bindings/webcore/JSFetchHeaders.cpp).
|
||||
- **Node.js compatibility**. In addition to supporting Node-style module resolution, Bun aims for full compatibility with built-in Node.js globals (`process`, `Buffer`) and modules (`path`, `fs`, `http`, etc.) _This is an ongoing effort that is not complete._ Refer to the compatibility page for the current status.
|
||||
- **Node.js compatibility**. In addition to supporting Node-style module resolution, Bun aims for full compatibility with built-in Node.js globals (`process`, `Buffer`) and modules (`path`, `fs`, `http`, etc.) _This is an ongoing effort that is not complete._ Refer to the [compatibility page](https://bun.sh/docs/runtime/nodejs-apis) for the current status.
|
||||
|
||||
Bun is more than a runtime. The long-term goal is to be a cohesive, infrastructural toolkit for building apps with JavaScript/TypeScript, including a package manager, transpiler, bundler, script runner, test runner, and more.
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ This behavior is configurable with the `--backend` flag, which is respected by a
|
||||
- **`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`**: Currently used only `file:` (and eventually `link:`) dependencies. To prevent infinite loops, it skips symlinking the `node_modules` folder.
|
||||
- **`symlink`**: Currently used only `file:` (and eventually `link:`) dependencies. To prevent infinite loops, it skips symlinking the `node_modules` folder.
|
||||
|
||||
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`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks).
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ $ bun install --silent # no logging
|
||||
```
|
||||
|
||||
{% details summary="Configuring behavior" %}
|
||||
The default behavior of `bun install` can be configured in `bun.toml`:
|
||||
The default behavior of `bun install` can be configured in `bunfig.toml`:
|
||||
|
||||
```toml
|
||||
[install]
|
||||
@@ -188,7 +188,7 @@ Bun supports a variety of protocols, including [`github`](https://docs.npmjs.com
|
||||
|
||||
## Tarball dependencies
|
||||
|
||||
A package name can correspond to a publically hosted `.tgz` file. During `bun install`, Bun will download and install the package from the specified tarball URL, rather than from the package registry.
|
||||
A package name can correspond to a publicly hosted `.tgz` file. During `bun install`, Bun will download and install the package from the specified tarball URL, rather than from the package registry.
|
||||
|
||||
```json#package.json
|
||||
{
|
||||
|
||||
@@ -10,32 +10,26 @@ Run `bun install -y` to generate a Yarn-compatible `yarn.lock` (v1) that can be
|
||||
|
||||
#### How do I `git diff` Bun's lockfile?
|
||||
|
||||
To add to the global gitattributes file:
|
||||
|
||||
- First try `$XDG_CONFIG_HOME/git/attributes`
|
||||
- If `$XDG_CONFIG_HOME` is not set, try `~/.config/git/attributes`
|
||||
|
||||
For example, on macOS, add the following to `~/.config/git/attributes`:
|
||||
Add the following to your local or global `.gitattributes` file:
|
||||
|
||||
```
|
||||
*.lockb diff=lockb
|
||||
*.lockb binary diff=lockb
|
||||
```
|
||||
|
||||
Then add the following to `~/.gitconfig`:
|
||||
|
||||
```
|
||||
[diff "lockb"]
|
||||
textconv = bun
|
||||
binary = true
|
||||
```
|
||||
|
||||
To only add to the local gitattributes file:
|
||||
Then add the following to you local git config with:
|
||||
|
||||
```sh
|
||||
$ git config diff.lockb.textconv bun
|
||||
$ git config diff.lockb.binary true
|
||||
```
|
||||
|
||||
Or to your global git config (system-wide) with the `--global` option:
|
||||
|
||||
```sh
|
||||
$ git config --global diff.lockb.textconv bun
|
||||
$ git config --global diff.lockb.binary true
|
||||
```
|
||||
|
||||
**Why this works:**
|
||||
|
||||
- `textconv` tells git to run `bun` on the file before diffing
|
||||
|
||||
@@ -11,7 +11,7 @@ To try it, specify a list of sub-packages in the `workspaces` field of your `pac
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Glob support** — Bun v0.5.8 added support for simple `<directory>/*` globs in `"workspaces"`. Full glob syntax (e.g. `**` and `?`) is not yet supported (soon!).
|
||||
**Glob support** — Bun supports simple `<directory>/*` globs in `"workspaces"`. Full glob syntax (e.g. `**` and `?`) is not yet supported.
|
||||
{% /callout %}
|
||||
|
||||
This has a couple major benefits.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
Bun ships as a single executable that can be installed a few different ways.
|
||||
|
||||
{% callout %}
|
||||
**Windows users** — Bun does not currently provide a native Windows build. We're working on this; progress can be tracked at [this issue](https://github.com/oven-sh/bun/issues/43). In the meantime, use one of the installation methods below for Windows Subsystem for Linux.
|
||||
## macOS and Linux
|
||||
|
||||
{% callout %}
|
||||
**Linux users** — The `unzip` package is required to install Bun. Kernel version 5.6 or higher is strongly recommended, but the minimum is 5.1.
|
||||
{% /callout %}
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```bash#Native
|
||||
```bash#macOS/Linux_(curl)
|
||||
$ curl -fsSL https://bun.sh/install | bash # for macOS, Linux, and WSL
|
||||
```
|
||||
|
||||
@@ -32,6 +32,20 @@ $ proto install bun
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
## Windows
|
||||
|
||||
Bun provides a _limited, experimental_ native build for Windows. At the moment, only the Bun runtime is supported.
|
||||
|
||||
- `bun <file>`
|
||||
- `bun run <file>`
|
||||
|
||||
The test runner, package manager, and bundler are still under development. The following commands have been disabled.
|
||||
|
||||
- `bun test`
|
||||
- `bun install/add/remove`
|
||||
- `bun link/unlink`
|
||||
- `bun build`
|
||||
|
||||
## Upgrading
|
||||
|
||||
Once installed, the binary can upgrade itself.
|
||||
@@ -135,3 +149,27 @@ To write the completions to a custom location:
|
||||
$ bun completions > path-to-file # write to file
|
||||
$ bun completions /path/to/directory # write into directory
|
||||
```
|
||||
|
||||
## Uninstall
|
||||
|
||||
If you need to remove Bun from your system, use the following commands.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```bash#macOS/Linux_(curl)
|
||||
$ rm -rf ~/.bun # for macOS, Linux, and WSL
|
||||
```
|
||||
|
||||
```bash#NPM
|
||||
$ npm uninstall -g bun
|
||||
```
|
||||
|
||||
```bash#Homebrew
|
||||
$ brew uninstall bun
|
||||
```
|
||||
|
||||
```bash#Proto
|
||||
$ proto uninstall bun
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
@@ -166,7 +166,7 @@ export default {
|
||||
|
||||
divider("Bundler"),
|
||||
page("bundler", "`Bun.build`", {
|
||||
description: "Bundle code for comsumption in the browser with Bun's native bundler.",
|
||||
description: "Bundle code for consumption in the browser with Bun's native bundler.",
|
||||
}),
|
||||
// page("bundler/intro", "How bundlers work", {
|
||||
// description: "A visual introduction to bundling",
|
||||
|
||||
@@ -46,7 +46,8 @@ $ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 15 all
|
||||
```
|
||||
|
||||
```bash#Arch
|
||||
$ sudo pacman -S llvm clang lld
|
||||
$ sudo pacman -S llvm15 clang15 lld
|
||||
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
@@ -70,6 +71,14 @@ $ export LDFLAGS="$LDFLAGS -L$(brew --prefix llvm@15)/lib"
|
||||
$ export CPPFLAGS="$CPPFLAGS -I$(brew --prefix llvm@15)/include"
|
||||
```
|
||||
|
||||
```bash#Arch
|
||||
|
||||
$ export PATH="$PATH:/usr/lib/llvm15/bin"
|
||||
$ export LDFLAGS="$LDFLAGS -L/usr/lib/llvm15/lib"
|
||||
$ export CPPFLAGS="$CPPFLAGS -I/usr/lib/llvm15/include"
|
||||
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
## Install Dependencies
|
||||
@@ -127,11 +136,11 @@ After cloning the repository, run the following command to run the first build.
|
||||
$ make setup
|
||||
```
|
||||
|
||||
The binary will be located at `packages/debug-bun-{platform}-{arch}/bun-debug`. It is recommended to add this to your `$PATH`. To verify the build worked, lets print the version number on the development build of Bun.
|
||||
The binary will be located at `packages/debug-bun-{platform}-{arch}/bun-debug`. It is recommended to add this to your `$PATH`. To verify the build worked, let's print the version number on the development build of Bun.
|
||||
|
||||
```bash
|
||||
$ packages/debug-bun-*/bun-debug --version
|
||||
bun 0.x.y__dev
|
||||
bun 1.x.y__dev
|
||||
```
|
||||
|
||||
Note: `make setup` is just an alias for the following:
|
||||
@@ -192,7 +201,7 @@ Bun uses a series of make commands to rebuild parts of the codebase. The general
|
||||
---
|
||||
|
||||
- Code using `cppFn`/`JSC.markBinding`
|
||||
- `make headers` (TODO: explain explain what this is used for and why it's useful)
|
||||
- `make headers` (TODO: explain what this is used for and why it's useful)
|
||||
|
||||
{% /table %}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ Bun statically links these libraries:
|
||||
|
||||
---
|
||||
|
||||
- Parts of Tigerbeetle's IO code https://github.com/tigerbeetle/tigerbeetle/blob/532c8b70b9142c17e07737ab6d3da68d7500cbca/src/io/windows.zig#L1
|
||||
- Parts of [Tigerbeetle's IO code](https://github.com/tigerbeetle/tigerbeetle/blob/532c8b70b9142c17e07737ab6d3da68d7500cbca/src/io/windows.zig#L1)
|
||||
- Apache 2.0 licensed
|
||||
|
||||
{% /table %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Bun is a project with an incredibly large scope and is still in its early days. Long-term, Bun aims to provide an all-in-one tookit to replace the complex, fragmented toolchains common today: Node.js, Jest, Webpack, esbuild, Babel, yarn, PostCSS, etc.
|
||||
Bun is a project with an incredibly 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, etc.
|
||||
|
||||
Refer to [Bun's Roadmap](https://github.com/oven-sh/bun/issues/159) on GitHub to learn more about the project's long-term plans and priorities.
|
||||
|
||||
|
||||
@@ -35,18 +35,18 @@ Open `index.ts` and paste the following code snippet, which implements a simple
|
||||
const server = Bun.serve({
|
||||
port: 3000,
|
||||
fetch(req) {
|
||||
return new Response(`Bun!`);
|
||||
return new Response("Bun!");
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Listening on http://localhost:${server.port}...`);
|
||||
console.log(`Listening on http://localhost:${server.port} ...`);
|
||||
```
|
||||
|
||||
Run the file from your shell.
|
||||
|
||||
```bash
|
||||
$ bun index.ts
|
||||
Listening at http://localhost:3000...
|
||||
Listening on http://localhost:3000 ...
|
||||
```
|
||||
|
||||
Visit [http://localhost:3000](http://localhost:3000) to test the server. You should see a simple page that says "Bun!".
|
||||
@@ -97,9 +97,9 @@ Update `index.ts` to use `figlet` in the `fetch` handler.
|
||||
|
||||
const server = Bun.serve({
|
||||
fetch() {
|
||||
+ const body = figlet.textSync('Bun!');
|
||||
+ const body = figlet.textSync("Bun!");
|
||||
+ return new Response(body);
|
||||
- return new Response(`Bun!`);
|
||||
- return new Response("Bun!");
|
||||
},
|
||||
port: 3000,
|
||||
});
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
{% callout %}
|
||||
**Note** — Added in Bun v0.3.0
|
||||
{% /callout %}
|
||||
|
||||
If no `node_modules` directory is found in the working directory or higher, Bun will abandon Node.js-style module resolution in favor of the **Bun module resolution algorithm**.
|
||||
|
||||
Under Bun-style module resolution, all imported packages are auto-installed on the fly into a [global module cache](/docs/install/cache) during execution (the same cache used by [`bun install`](/docs/cli/install)).
|
||||
|
||||
@@ -10,9 +10,11 @@ You can also create a global configuration file at the following paths:
|
||||
- `$HOME/.bunfig.toml`
|
||||
- `$XDG_CONFIG_HOME/.bunfig.toml`
|
||||
|
||||
If both a global and local `bunfig` are detected, the results are shallow-merged, with local overridding global. CLI flags will override `bunfig` setting where applicable.
|
||||
If both a global and local `bunfig` are detected, the results are shallow-merged, with local overriding global. CLI flags will override `bunfig` setting where applicable.
|
||||
|
||||
## Runtime
|
||||
## `bunfig.toml`
|
||||
|
||||
### Runtime
|
||||
|
||||
```toml
|
||||
# scripts to run before `bun run`ning a file or script
|
||||
@@ -42,7 +44,7 @@ logLevel = "debug" # "debug", "warn", "error"
|
||||
".bagel" = "js"
|
||||
```
|
||||
|
||||
## Test runner
|
||||
### Test runner
|
||||
|
||||
```toml
|
||||
[test]
|
||||
@@ -53,7 +55,7 @@ preload = ["./setup.ts"]
|
||||
smol = true
|
||||
```
|
||||
|
||||
## Package manager
|
||||
### Package manager
|
||||
|
||||
Package management is a complex issue; to support a range of use cases, the behavior of `bun install` can be configured in [`bunfig.toml`](/docs/runtime/configuration).
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Debugger
|
||||
---
|
||||
|
||||
Bun speaks the [WebKit Inspector Protocol](https://github.com/oven-sh/bun/blob/main/packages/bun-vscode/types/jsc.d.ts). For demonstration purposes, consider the following simple web server.
|
||||
Bun speaks the [WebKit Inspector Protocol](https://github.com/oven-sh/bun/blob/main/packages/bun-vscode/types/jsc.d.ts), so you can debug your code with an interactive debugger. For demonstration purposes, consider the following simple web server.
|
||||
|
||||
```ts#server.ts
|
||||
Bun.serve({
|
||||
@@ -48,7 +48,7 @@ $ bun --inspect=localhost:4000/prefix server.ts
|
||||
|
||||
## Debuggers
|
||||
|
||||
Various debugging tools can connect to this server to provide an interactive debugging experience. Bun hosts a web-based debugger at [debug.bun.sh](https://debug.bun.sh). It is a modified version of WebKit's [Web Inspector Interface](https://webkit.org/web-inspector/web-inspector-interface/), which will look familiar to Safari users.
|
||||
Various debugging tools can connect to this server to provide an interactive debugging experience.
|
||||
|
||||
### `debug.bun.sh`
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Bun supports two kinds of automatic reloading via CLI flags:
|
||||
|
||||
- `--watch` mode, which hard restarts Bun's process when imported files change (introduced in Bun v0.5.9)
|
||||
- `--hot` mode, which soft reloads the code (without restarting the process) when imported files change (introduced in Bun v0.2.0)
|
||||
- `--watch` mode, which hard restarts Bun's process when imported files change/
|
||||
- `--hot` mode, which soft reloads the code (without restarting the process) when imported files change.
|
||||
|
||||
## `--watch` mode
|
||||
|
||||
@@ -117,7 +117,7 @@ serve({
|
||||
|
||||
The file above is simply exporting an object with a `fetch` handler defined. When this file is executed, Bun interprets this as an HTTP server and passes the exported object into `Bun.serve`.
|
||||
|
||||
When you save the file, your HTTP server be reloaded with the updated code without the process being restarted. This results in seriously fast refresh speeds.
|
||||
When you save the file, your HTTP server will be reloaded with the updated code without the process being restarted. This results in seriously fast refresh speeds.
|
||||
|
||||
{% image src="https://user-images.githubusercontent.com/709451/195477632-5fd8a73e-014d-4589-9ba2-e075ad9eb040.gif" alt="Bun vs Nodemon refresh speeds" caption="Bun on the left, Nodemon on the right." /%}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ Bun is a new JavaScript & TypeScript runtime designed to be a faster, leaner, an
|
||||
|
||||
## Speed
|
||||
|
||||
Bun is designed to start fast and run fast. It's transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js.
|
||||
Bun is designed to start fast and run fast. Its transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js.
|
||||
|
||||
{% image src="/images/bun-run-speed.jpeg" caption="Bun vs Node.js vs Deno running Hello World" /%}
|
||||
|
||||
@@ -27,7 +27,7 @@ Some aspects of Bun's runtime behavior are affected by the contents of your `tsc
|
||||
|
||||
<!--
|
||||
|
||||
every file before execution. It's transpiler can directly run TypeScript and JSX `{.js|.jsx|.ts|.tsx}` files directly. During execution, Bun internally transpiles all files (including `.js` files) to vanilla JavaScript with it's fast native transpiler. -->
|
||||
every file before execution. Its transpiler can directly run TypeScript and JSX `{.js|.jsx|.ts|.tsx}` files directly. During execution, Bun internally transpiles all files (including `.js` files) to vanilla JavaScript with its fast native transpiler. -->
|
||||
|
||||
<!-- A loader determines how to map imports & file extensions to transforms and output. -->
|
||||
|
||||
@@ -103,7 +103,11 @@ import bunfig from "./bunfig.toml";
|
||||
|
||||
## WASM
|
||||
|
||||
As of v0.5.2, experimental support exists for WASI, the [WebAssembly System Interface](https://github.com/WebAssembly/WASI). To run a `.wasm` binary with Bun:
|
||||
{% callout %}
|
||||
🚧 **Experimental**
|
||||
{% /callout %}
|
||||
|
||||
Bun has experimental support for WASI, the [WebAssembly System Interface](https://github.com/WebAssembly/WASI). To run a `.wasm` binary with Bun:
|
||||
|
||||
```bash
|
||||
$ bun ./my-wasm-app.wasm
|
||||
@@ -113,7 +117,7 @@ $ bun run ./my-wasm-app.whatever
|
||||
|
||||
{% callout %}
|
||||
|
||||
**Note** — WASI support is based on [wasi-js](https://github.com/sagemathinc/cowasm/tree/main/packages/wasi-js). Currently, it only supports WASI binaries that use the `wasi_snapshot_preview1` or `wasi_unstable` APIs. Bun's implementation is not fully optimized for performance; this will become more of a priority as WASM grows in popularity.
|
||||
**Note** — WASI support is based on [wasi-js](https://github.com/sagemathinc/cowasm/tree/main/core/wasi-js). Currently, it only supports WASI binaries that use the `wasi_snapshot_preview1` or `wasi_unstable` APIs. Bun's implementation is not fully optimized for performance; this will become more of a priority as WASM grows in popularity.
|
||||
{% /callout %}
|
||||
|
||||
## Node.js compatibility
|
||||
|
||||
@@ -175,7 +175,7 @@ The function name used to represent [JSX fragments](https://react.dev/reference/
|
||||
|
||||
// output
|
||||
import { myjsx, MyFragment } from "react";
|
||||
createElement("Box", { width: 5 }, "Hello");
|
||||
myjsx(MyFragment, null, "Hello");
|
||||
```
|
||||
|
||||
{% /table %}
|
||||
|
||||
@@ -36,10 +36,6 @@ $ bun run react.tsx
|
||||
|
||||
## Text files
|
||||
|
||||
{% callout %}
|
||||
Supported in Bun v0.6.0 canary.
|
||||
{% /callout %}
|
||||
|
||||
Text files can be imported as strings.
|
||||
|
||||
{% codetabs %}
|
||||
@@ -67,7 +63,11 @@ import data from "./data.toml";
|
||||
|
||||
## WASM
|
||||
|
||||
As of v0.5.2, experimental support exists for WASI, the [WebAssembly System Interface](https://github.com/WebAssembly/WASI). To run a `.wasm` binary with Bun:
|
||||
{% callout %}
|
||||
🚧 **Experimental**
|
||||
{% /callout %}
|
||||
|
||||
Bun has experimental support for WASI, the [WebAssembly System Interface](https://github.com/WebAssembly/WASI). To run a `.wasm` binary with Bun:
|
||||
|
||||
```bash
|
||||
$ bun ./my-wasm-app.wasm
|
||||
@@ -77,7 +77,7 @@ $ bun run ./my-wasm-app.whatever
|
||||
|
||||
{% callout %}
|
||||
|
||||
**Note** — WASI support is based on [wasi-js](https://github.com/sagemathinc/cowasm/tree/main/packages/wasi-js). Currently, it only supports WASI binaries that use the `wasi_snapshot_preview1` or `wasi_unstable` APIs. Bun's implementation is not fully optimized for performance; this will become more of a priority as WASM grows in popularity.
|
||||
**Note** — WASI support is based on [wasi-js](https://github.com/sagemathinc/cowasm/tree/main/core/wasi-js). Currently, it only supports WASI binaries that use the `wasi_snapshot_preview1` or `wasi_unstable` APIs. Bun's implementation is not fully optimized for performance; this will become more of a priority as WASM grows in popularity.
|
||||
{% /callout %}
|
||||
|
||||
## Custom loaders
|
||||
|
||||
@@ -31,7 +31,7 @@ $ bun index.ts
|
||||
Hello world!
|
||||
```
|
||||
|
||||
In this case, we are importing from `./hello`, a relative path with no extension. To resolve this import, Bun will check for the following files in order:
|
||||
In this case, we are importing from `./hello`, a relative path with no extension. **Extensioned imports are optional but supported.** To resolve this import, Bun will check for the following files in order:
|
||||
|
||||
- `./hello.ts`
|
||||
- `./hello.tsx`
|
||||
@@ -43,7 +43,7 @@ In this case, we are importing from `./hello`, a relative path with no extension
|
||||
- `./hello/index.json`
|
||||
- `./hello/index.mjs`
|
||||
|
||||
Import paths are case-insensitive.
|
||||
Import paths are case-insensitive, meaning these are all valid imports:
|
||||
|
||||
```ts#index.ts
|
||||
import { hello } from "./hello";
|
||||
@@ -58,7 +58,7 @@ import { hello } from "./hello";
|
||||
import { hello } from "./hello.ts"; // this works
|
||||
```
|
||||
|
||||
There is one exception: if you import `from "*.js{x}"`, Bun will additionally check for a matching `*.ts{x}` file, to be compatible with TypeScript's [ES module support](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#new-file-extensions).
|
||||
If you import `from "*.js{x}"`, Bun will additionally check for a matching `*.ts{x}` file, to be compatible with TypeScript's [ES module support](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#new-file-extensions).
|
||||
|
||||
```ts#index.ts
|
||||
import { hello } from "./hello";
|
||||
@@ -88,7 +88,75 @@ exports.hello = hello;
|
||||
|
||||
That said, using CommonJS is discouraged in new projects.
|
||||
|
||||
## Resolution
|
||||
## Module systems
|
||||
|
||||
Bun has native support for CommonJS and ES modules. ES Modules are the recommended module format for new projects, but CommonJS modules are still widely used in the Node.js ecosystem.
|
||||
|
||||
In Bun's JavaScript runtime, `require` can be used by both ES Modules and CommonJS modules. If the target module is an ES Module, `require` returns the module namespace object (equivalent to `import * as`). If the target module is a CommonJS module, `require` returns the `module.exports` object (as in Node.js).
|
||||
|
||||
| Module Type | `require()` | `import * as` |
|
||||
| ----------- | ---------------- | ----------------------------------------------------------------------- |
|
||||
| ES Module | Module Namespace | Module Namespace |
|
||||
| CommonJS | module.exports | `default` is `module.exports`, keys of module.exports are named exports |
|
||||
|
||||
### Using `require()`
|
||||
|
||||
You can `require()` any file or package, even `.ts` or `.mjs` files.
|
||||
|
||||
```ts
|
||||
const { foo } = require("./foo"); // extensions are optional
|
||||
const { bar } = require("./bar.mjs");
|
||||
const { baz } = require("./baz.tsx");
|
||||
```
|
||||
|
||||
{% details summary="What is a CommonJS module?" %}
|
||||
|
||||
In 2016, ECMAScript added support for [ES Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). ES Modules are the standard for JavaScript modules. However, millions of npm packages still use CommonJS modules.
|
||||
|
||||
CommonJS modules are modules that use `module.exports` to export values. Typically, `require` is used to import CommonJS modules.
|
||||
|
||||
```ts
|
||||
// my-commonjs.cjs
|
||||
const stuff = require("./stuff");
|
||||
module.exports = { stuff };
|
||||
```
|
||||
|
||||
The biggest difference between CommonJS and ES Modules is that CommonJS modules are synchronous, while ES Modules are asynchronous. There are other differences too.
|
||||
|
||||
- ES Modules support top-level `await` and CommonJS modules don't.
|
||||
- ES Modules are always in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), while CommonJS modules are not.
|
||||
- Browsers do not have native support for CommonJS modules, but they do have native support for ES Modules via `<script type="module">`.
|
||||
- CommonJS modules are not statically analyzable, while ES Modules only allow static imports and exports.
|
||||
|
||||
{% /details %}
|
||||
|
||||
### Using `import`
|
||||
|
||||
You can `import` any file or package, even `.cjs` files.
|
||||
|
||||
```ts
|
||||
const { foo } = require("./foo"); // extensions are optional
|
||||
const { bar } = require("./bar.mjs");
|
||||
const { baz } = require("./my-typescript.tsx");
|
||||
```
|
||||
|
||||
### Using `import` and `require()` together
|
||||
|
||||
In Bun, you can use `import` or `require` in the same file—they both work, all the time.
|
||||
|
||||
```ts
|
||||
import { stuff } from "./my-commonjs.cjs";
|
||||
import Stuff from "./my-commonjs.cjs";
|
||||
const myStuff = require("./my-commonjs.cjs");
|
||||
```
|
||||
|
||||
### Top level await
|
||||
|
||||
The only exception to this rule is top-level await. You can't `require()` a file that uses top-level await, since the `require()` function is inherently synchronous.
|
||||
|
||||
Fortunately, very few libraries use top-level await, so this is rarely a problem. But if you're using top-level await in your application code, make sure that file isn't being `require()` from elsewhere in your application. Instead, you should use `import` or [dynamic `import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import).
|
||||
|
||||
## Importing packages
|
||||
|
||||
Bun implements the Node.js module resolution algorithm, so you can import packages from `node_modules` with a bare specifier.
|
||||
|
||||
@@ -107,8 +175,8 @@ Once it finds the `foo` package, Bun reads the `package.json` to determine how t
|
||||
"bun": "./index.js",
|
||||
"worker": "./index.js",
|
||||
"node": "./index.js",
|
||||
"require": "./index.js", # if importer is CommonJS
|
||||
"import": "./index.mjs", # if importer is ES module
|
||||
"require": "./index.js", // if importer is CommonJS
|
||||
"import": "./index.mjs", // if importer is ES module
|
||||
"default": "./index.js",
|
||||
}
|
||||
}
|
||||
@@ -159,80 +227,9 @@ In the spirit of treating TypeScript as a first-class citizen, the Bun runtime w
|
||||
|
||||
If you aren't a TypeScript user, you can create a [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) in your project root to achieve the same behavior.
|
||||
|
||||
## CommonJS
|
||||
{% details summary="Low-level details of CommonJS interop in Bun" %}
|
||||
|
||||
Bun has native support for CommonJS modules (added in Bun v0.6.5). ES Modules are the recommended module format, but CommonJS modules are still widely used in the Node.js ecosystem. Bun supports both module formats, so that existing CommonJS packages can be used.
|
||||
|
||||
In Bun's JavaScript runtime, `require` can be used by both ES Modules and CommonJS modules.
|
||||
|
||||
In Bun, you can `require()` ESM modules from CommonJS modules.
|
||||
|
||||
| Module Type | `require()` | `import * as` |
|
||||
| ----------- | ---------------- | ----------------------------------------------------------------------- |
|
||||
| ES Module | Module Namespace | Module Namespace |
|
||||
| CommonJS | module.exports | `default` is `module.exports`, keys of module.exports are named exports |
|
||||
|
||||
If the target module is an ES Module, `require` returns the module namespace object (equivalent to `import * as`).
|
||||
If the target module is a CommonJS module, `require` returns the `module.exports` object.
|
||||
|
||||
### What is a CommonJS module?
|
||||
|
||||
In 2016, ECMAScript added support for [ES Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). ES Modules are the standard for JavaScript modules. However, millions of npm packages still use CommonJS modules.
|
||||
|
||||
CommonJS modules are modules that use `module.exports` to export values. Typically, `require` is used to import CommonJS modules.
|
||||
|
||||
```ts
|
||||
// my-commonjs.cjs
|
||||
const stuff = require("./stuff");
|
||||
module.exports = { stuff };
|
||||
```
|
||||
|
||||
The biggest difference between CommonJS and ES Modules is that CommonJS modules are synchronous, while ES Modules are asynchronous. There are other differences too, like ES Modules support top-level `await` and CommonJS modules don't. ES Modules are always in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), while CommonJS modules are not. Browsers do not have native support for CommonJS modules, but they do have native support for ES Modules (`<script type="module">`). CommonJS modules are not statically analyzable, while ES Modules only allow static imports and exports.
|
||||
|
||||
### Importing CommonJS from ESM
|
||||
|
||||
You can `import` or `require` CommonJS modules from ESM modules.
|
||||
|
||||
```ts
|
||||
import { stuff } from "./my-commonjs.cjs";
|
||||
import Stuff from "./my-commonjs.cjs";
|
||||
const myStuff = require("./my-commonjs.cjs");
|
||||
```
|
||||
|
||||
### Importing ESM from CommonJS
|
||||
|
||||
```ts
|
||||
// this works in Bun v0.6.5+
|
||||
// It does not work in Node.js
|
||||
const { stuff } = require("./my-esm.mjs");
|
||||
```
|
||||
|
||||
### Importing CommonJS from CommonJS
|
||||
|
||||
You can `require()` CommonJS modules from CommonJS modules.
|
||||
|
||||
```ts
|
||||
const { stuff } = require("./my-commonjs.cjs");
|
||||
```
|
||||
|
||||
#### Top-level await
|
||||
|
||||
If you are using top-level await, you must use `import()` to import ESM modules from CommonJS modules.
|
||||
|
||||
```ts
|
||||
import("./my-esm.js").then(({ stuff }) => {
|
||||
// ...
|
||||
});
|
||||
|
||||
// this will throw an error if "my-esm.js" uses top-level await
|
||||
const { stuff } = require("./my-esm.js");
|
||||
```
|
||||
|
||||
#### Low-level details of CommonJS interop in Bun
|
||||
|
||||
Bun's JavaScript runtime has native support for CommonJS as of Bun v0.6.5.
|
||||
|
||||
When Bun's JavaScript transpiler detects usages of `module.exports`, it treats the file as CommonJS. The module loader will then wrap the transpiled module in a function shaped like this:
|
||||
Bun's JavaScript runtime has native support for CommonJS. When Bun's JavaScript transpiler detects usages of `module.exports`, it treats the file as CommonJS. The module loader will then wrap the transpiled module in a function shaped like this:
|
||||
|
||||
```js
|
||||
(function (module, exports, require) {
|
||||
@@ -245,3 +242,5 @@ When Bun's JavaScript transpiler detects usages of `module.exports`, it treats t
|
||||
Once the CommonJS module is successfully evaluated, a Synthetic Module Record is created with the `default` ES Module [export set to `module.exports`](https://github.com/oven-sh/bun/blob/9b6913e1a674ceb7f670f917fc355bb8758c6c72/src/bun.js/bindings/CommonJSModuleRecord.cpp#L212-L213) and keys of the `module.exports` object are re-exported as named exports (if the `module.exports` object is an object).
|
||||
|
||||
When using Bun's bundler, this works differently. The bundler will wrap the CommonJS module in a `require_${moduleName}` function which returns the `module.exports` object.
|
||||
|
||||
{% /details %}
|
||||
|
||||
@@ -18,7 +18,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:child_process`](https://nodejs.org/api/child_process.html)
|
||||
|
||||
🟡 Missing IPC, `Stream` stdio, `proc.gid`, `proc.uid`, advanced serialization.
|
||||
🟡 Missing `Stream` stdio, `proc.gid`, `proc.uid`. IPC has partial support and only current only works with other `bun` processes.
|
||||
|
||||
### [`node:cluster`](https://nodejs.org/api/cluster.html)
|
||||
|
||||
@@ -26,7 +26,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:console`](https://nodejs.org/api/console.html)
|
||||
|
||||
🟢 Recommended to use `console` global instead
|
||||
🟡 Missing `Console` constructor.
|
||||
|
||||
### [`node:crypto`](https://nodejs.org/api/crypto.html)
|
||||
|
||||
@@ -50,11 +50,11 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:events`](https://nodejs.org/api/events.html)
|
||||
|
||||
🟡 Missing `on`
|
||||
🟡 Missing `on`.
|
||||
|
||||
### [`node:fs`](https://nodejs.org/api/fs.html)
|
||||
|
||||
🟡 Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}` `fs.{watchFile|unwatchFile}` `fs.{cp|cpSync}`. `fs.promises.open` incorrectly returns a file descriptor instead of a `FileHandle`.
|
||||
🟡 Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}`. `fs.promises.open` incorrectly returns a file descriptor instead of a `FileHandle`.
|
||||
|
||||
### [`node:http`](https://nodejs.org/api/http.html)
|
||||
|
||||
@@ -94,7 +94,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:process`](https://nodejs.org/api/process.html)
|
||||
|
||||
🟡 See `Globals > process`.
|
||||
🟡 See [`process`](#process) Global.
|
||||
|
||||
### [`node:punycode`](https://nodejs.org/api/punycode.html)
|
||||
|
||||
@@ -122,7 +122,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:sys`](https://nodejs.org/api/util.html)
|
||||
|
||||
🟡 See `node:util`.
|
||||
🟡 See [`node:util`](#node-util).
|
||||
|
||||
### [`node:timers`](https://nodejs.org/api/timers.html)
|
||||
|
||||
@@ -130,7 +130,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:tls`](https://nodejs.org/api/tls.html)
|
||||
|
||||
🟡 Missing `tls.createSecurePair`
|
||||
🟡 Missing `tls.createSecurePair`.
|
||||
|
||||
### [`node:trace_events`](https://nodejs.org/api/tracing.html)
|
||||
|
||||
@@ -146,7 +146,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:util`](https://nodejs.org/api/util.html)
|
||||
|
||||
🟡 Missing `util.MIMEParams` `util.MIMEType` `util.formatWithOptions()` `util.getSystemErrorMap()` `util.getSystemErrorName()` `util.parseArgs()` `util.stripVTControlCharacters()` `util.transferableAbortController()` `util.transferableAbortSignal()`.
|
||||
🟡 Missing `util.MIMEParams` `util.MIMEType` `util.getSystemErrorMap()` `util.getSystemErrorName()` `util.parseArgs()` `util.stripVTControlCharacters()` `util.transferableAbortController()` `util.transferableAbortSignal()`.
|
||||
|
||||
### [`node:v8`](https://nodejs.org/api/v8.html)
|
||||
|
||||
@@ -166,7 +166,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:zlib`](https://nodejs.org/api/zlib.html)
|
||||
|
||||
🟡 Missing `zlib.brotli*`. Some methods are not optimized.
|
||||
🟡 Missing `zlib.brotli*`. Has not been optimized.
|
||||
|
||||
<!-- {% block className="ScrollFrame" %}
|
||||
{% table %}
|
||||
@@ -250,7 +250,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
- {% anchor id="node_fs" %} [`node:fs`](https://nodejs.org/api/fs.html) {% /anchor %}
|
||||
- 🟡
|
||||
- Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}` `fs.{watchFile|unwatchFile}` `fs.{cp|cpSync}`. `fs.promises.open` incorrectly returns a file descriptor instead of a `FileHandle`.
|
||||
- Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}`. `fs.promises.open` incorrectly returns a file descriptor instead of a `FileHandle`.
|
||||
|
||||
---
|
||||
|
||||
@@ -364,7 +364,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
- {% anchor id="node_tls" %} [`node:tls`](https://nodejs.org/api/tls.html) {% /anchor %}
|
||||
- 🟡
|
||||
- Missing `tls.createSecurePair`
|
||||
- Missing `tls.createSecurePair`.
|
||||
|
||||
---
|
||||
|
||||
@@ -418,7 +418,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
- {% anchor id="node_zlib" %} [`node:zlib`](https://nodejs.org/api/zlib.html) {% /anchor %}
|
||||
- 🟡
|
||||
- Missing `zlib.brotli*`
|
||||
- Missing `zlib.brotli*`.
|
||||
|
||||
{% /table %}
|
||||
{% /block %} -->
|
||||
@@ -529,7 +529,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
|
||||
|
||||
### [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
|
||||
|
||||
🟢 Fully implemented. Added in Bun 0.5.7.
|
||||
🟢 Fully implemented.
|
||||
|
||||
### [`global`](https://nodejs.org/api/globals.html#global)
|
||||
|
||||
@@ -589,7 +589,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
|
||||
|
||||
### [`process`](https://nodejs.org/api/process.html)
|
||||
|
||||
🟡 Missing `process.allowedNodeEnvironmentFlags` `process.channel()` `process.connected` `process.constrainedMemory()` `process.disconnect()` `process.getActiveResourcesInfo/setActiveResourcesInfo()` `process.setuid/setgid/setegid/seteuid/setgroups()` `process.hasUncaughtExceptionCaptureCallback` `process.initGroups()` `process.report` `process.resourceUsage()` `process.send()`.
|
||||
🟡 Missing `process.allowedNodeEnvironmentFlags` `process.channel` `process.constrainedMemory()` `process.getActiveResourcesInfo/setActiveResourcesInfo()` `process.setuid/setgid/setegid/seteuid/setgroups()` `process.hasUncaughtExceptionCaptureCallback` `process.initGroups()` `process.report` `process.resourceUsage()`.
|
||||
|
||||
### [`queueMicrotask()`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
|
||||
|
||||
@@ -621,7 +621,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
|
||||
|
||||
### [`require()`](https://nodejs.org/api/globals.html#require)
|
||||
|
||||
🟢 Fully implemented, as well as [`require.main`](https://nodejs.org/api/modules.html#requiremain), [`require.cache`](https://nodejs.org/api/modules.html#requirecache), and [`require.resolve`](https://nodejs.org/api/modules.html#requireresolverequest-options)
|
||||
🟢 Fully implemented, as well as [`require.main`](https://nodejs.org/api/modules.html#requiremain), [`require.cache`](https://nodejs.org/api/modules.html#requirecache), and [`require.resolve`](https://nodejs.org/api/modules.html#requireresolverequest-options).
|
||||
|
||||
### [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
|
||||
|
||||
@@ -859,7 +859,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
|
||||
|
||||
- {% anchor id="node_formdata" %} [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) {% /anchor %}
|
||||
- 🟢
|
||||
- Fully implemented. Added in Bun 0.5.7.
|
||||
- Fully implemented.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
{% callout %}
|
||||
**Note** — Introduced in Bun v0.1.11.
|
||||
{% /callout %}
|
||||
|
||||
Bun provides a universal plugin API that can be used to extend both the _runtime_ and [_bundler_](/docs/bundler).
|
||||
|
||||
Plugins intercept imports and perform custom loading logic: reading files, transpiling code, etc. They can be used to add support for additional file types, like `.scss` or `.yaml`. In the context of Bun's bundler, plugins can be used to implement framework-level features like CSS extraction, macros, and client-server code co-location.
|
||||
@@ -131,7 +127,7 @@ In this case we're using `"object"`—a built-in loader (intended for use by plu
|
||||
---
|
||||
|
||||
- `ts`
|
||||
- `.ts` `.mts` `cts`
|
||||
- `.ts` `.mts` `.cts`
|
||||
- Transform TypeScript then transpile
|
||||
|
||||
---
|
||||
@@ -177,7 +173,7 @@ Loading a YAML file is useful, but plugins support more than just data loading.
|
||||
```ts#sveltePlugin.ts
|
||||
import { plugin } from "bun";
|
||||
|
||||
await plugin({
|
||||
plugin({
|
||||
name: "svelte loader",
|
||||
async setup(build) {
|
||||
const { compile } = await import("svelte/compiler");
|
||||
|
||||
@@ -32,7 +32,7 @@ The following Web APIs are partially or completely supported.
|
||||
---
|
||||
|
||||
- WebSockets
|
||||
- [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
|
||||
- [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) (_not production ready_)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -24,33 +24,56 @@ Press `enter` to accept the default answer for each prompt, or pass the `-y` fla
|
||||
|
||||
## `bun create`
|
||||
|
||||
Template a new Bun project with `bun create`.
|
||||
|
||||
```bash
|
||||
$ bun create <template> <destination>
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Note** — You don’t need `bun create` to use Bun. You don’t need any configuration at all. This command exists to make getting started a bit quicker and easier.
|
||||
{% /callout %}
|
||||
|
||||
A template can take a number of forms:
|
||||
Template a new Bun project with `bun create`. This is a flexible command that can be used to create a new project with a `create-<template>` npm package, a GitHub repo, or a local template.
|
||||
|
||||
```bash
|
||||
$ bun create <template> # an official template (remote)
|
||||
$ bun create <username>/<repo> # a GitHub repo (remote)
|
||||
$ bun create <local-template> # a custom template (local)
|
||||
### From `npm`
|
||||
|
||||
```sh
|
||||
$ bun create <template> [<destination>]
|
||||
```
|
||||
|
||||
Running `bun create` performs the following steps:
|
||||
Assuming you don't have a [local template](#local-templates) with the same name, this command will download and execute the `create-<template>` package from npm. The following two commands will behave identically:
|
||||
|
||||
- Download the template (remote templates only)
|
||||
- Copy all template files into the destination folder. By default Bun will _not overwrite_ any existing files. Use the `--force` flag to overwrite existing files.
|
||||
```sh
|
||||
$ bun create remix
|
||||
$ bunx create-remix
|
||||
```
|
||||
|
||||
Refer to the documentation of the associated `create-<template>` package for complete documentation and usage instructions.
|
||||
|
||||
### From GitHub
|
||||
|
||||
This will download the contents of the GitHub repo to disk.
|
||||
|
||||
```bash
|
||||
$ bun create <user>/<repo>
|
||||
$ bun create github.com/<user>/<repo>
|
||||
```
|
||||
|
||||
Optionally specify a name for the destination folder. If no destination is specified, the repo name will be used.
|
||||
|
||||
```bash
|
||||
$ bun create <user>/<repo> mydir
|
||||
$ bun create github.com/<user>/<repo> mydir
|
||||
```
|
||||
|
||||
Bun will perform the following steps:
|
||||
|
||||
- Download the template
|
||||
- Copy all template files into the destination folder
|
||||
- Install dependencies with `bun install`.
|
||||
- Initialize a fresh Git repo. Opt out with the `--no-git` flag.
|
||||
- Run the template's configured `start` script, if defined.
|
||||
|
||||
### Official templates
|
||||
{% callout %}
|
||||
By default Bun will _not overwrite_ any existing files. Use the `--force` flag to overwrite existing files.
|
||||
{% /callout %}
|
||||
|
||||
<!-- ### Official templates
|
||||
|
||||
The following official templates are available.
|
||||
|
||||
@@ -73,9 +96,9 @@ Welcome to bun! Create a new project by pasting any of the following:
|
||||
|
||||
{% callout %}
|
||||
⚡️ **Speed** — At the time of writing, `bun create react app` runs ~11x faster on a M1 Macbook Pro than `yarn create react-app app`.
|
||||
{% /callout %}
|
||||
{% /callout %} -->
|
||||
|
||||
### GitHub repos
|
||||
<!-- ### GitHub repos
|
||||
|
||||
A template of the form `<username>/<repo>` will be downloaded from GitHub.
|
||||
|
||||
@@ -90,9 +113,9 @@ $ bun create github.com/ahfarmer/calculator ./myapp
|
||||
$ bun create https://github.com/ahfarmer/calculator ./myapp
|
||||
```
|
||||
|
||||
Bun installs the files as they currently exist current default branch (usually `main` or `master`). Unlike `git clone` it doesn't download the commit history or configure a remote.
|
||||
Bun installs the files as they currently exist current default branch (usually `main` or `master`). Unlike `git clone` it doesn't download the commit history or configure a remote. -->
|
||||
|
||||
### Local templates
|
||||
### From a local template
|
||||
|
||||
{% callout %}
|
||||
**⚠️ Warning** — Unlike remote templates, running `bun create` with a local template will delete the entire destination folder if it already exists! Be careful.
|
||||
@@ -124,26 +147,9 @@ Then, create a `package.json` file in that directory with the following contents
|
||||
|
||||
You can run `bun create foo` elsewhere on your file system to verify that Bun is correctly finding your local template.
|
||||
|
||||
{% table %}
|
||||
#### Setup logic
|
||||
|
||||
---
|
||||
|
||||
- `postinstall`
|
||||
- runs after installing dependencies
|
||||
|
||||
---
|
||||
|
||||
- `preinstall`
|
||||
- runs before installing dependencies
|
||||
|
||||
<!-- ---
|
||||
|
||||
- `start`
|
||||
- a command to auto-start the application -->
|
||||
|
||||
{% /table %}
|
||||
|
||||
Each of these can correspond to a string or array of strings. An array of commands will be executed in order. Here is an example:
|
||||
You can specify pre- and post-install setup scripts in the `"bun-create"` section of your local template's `package.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -162,11 +168,27 @@ Each of these can correspond to a string or array of strings. An array of comman
|
||||
}
|
||||
```
|
||||
|
||||
When cloning a template, `bun create` will automatically remove the `"bun-create"` section from `package.json` before writing it to the destination folder.
|
||||
The following fields are supported. Each of these can correspond to a string or array of strings. An array of commands will be executed in order.
|
||||
|
||||
### Reference
|
||||
{% table %}
|
||||
|
||||
#### CLI flags
|
||||
---
|
||||
|
||||
- `postinstall`
|
||||
- runs after installing dependencies
|
||||
|
||||
---
|
||||
|
||||
- `preinstall`
|
||||
- runs before installing dependencies
|
||||
|
||||
{% /table %}
|
||||
|
||||
After cloning a template, `bun create` will automatically remove the `"bun-create"` section from `package.json` before writing it to the destination folder.
|
||||
|
||||
## Reference
|
||||
|
||||
### CLI flags
|
||||
|
||||
{% table %}
|
||||
|
||||
@@ -195,7 +217,7 @@ When cloning a template, `bun create` will automatically remove the `"bun-create
|
||||
|
||||
{% /table %}
|
||||
|
||||
#### Environment variables
|
||||
### Environment variables
|
||||
|
||||
{% table %}
|
||||
|
||||
|
||||
@@ -43,10 +43,6 @@ coverageSkipTestFiles = true # default false
|
||||
|
||||
### Coverage thresholds
|
||||
|
||||
{% callout %}
|
||||
**Note** — Support for coverage reporting was added in Bun v0.7.3.
|
||||
{% /callout %}
|
||||
|
||||
It is possible to specify a coverage threshold in `bunfig.toml`. If your test suite does not meet or exceed this threshold, `bun test` will exit with a non-zero exit code to indicate the failure.
|
||||
|
||||
```toml
|
||||
|
||||
@@ -55,7 +55,7 @@ Let's run this test with `bun test`:
|
||||
|
||||
```bash
|
||||
$ bun test
|
||||
bun test v0.x.y
|
||||
bun test v1.x
|
||||
|
||||
dom.test.ts:
|
||||
✓ dom test [0.82ms]
|
||||
|
||||
@@ -44,11 +44,11 @@ To scope the hooks to a test file:
|
||||
```ts
|
||||
import { describe, beforeAll } from "bun:test";
|
||||
|
||||
describe("test group", () => {
|
||||
beforeAll(() => {
|
||||
// setup
|
||||
});
|
||||
beforeAll(() => {
|
||||
// setup
|
||||
});
|
||||
|
||||
describe("test group", () => {
|
||||
// tests...
|
||||
});
|
||||
```
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
`bun:test` lets you change what time it is in your tests. This was introduced in Bun v0.6.13.
|
||||
`bun:test` lets you change what time it is in your tests.
|
||||
|
||||
This works with any of the following:
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ $ bun test --todo
|
||||
|
||||
## `test.only`
|
||||
|
||||
To run a particular test or suite of tests use `test.only()` or `describe.only()`. Once declared, running `bun test --skip` will only execute tests/suites that have been marked with `.only()`.
|
||||
To run a particular test or suite of tests use `test.only()` or `describe.only()`. Once declared, running `bun test --only` will only execute tests/suites that have been marked with `.only()`.
|
||||
|
||||
```ts
|
||||
import { test, describe } from "bun:test";
|
||||
@@ -300,12 +300,12 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
|
||||
---
|
||||
|
||||
- 🟢
|
||||
- [`.resolves()`](https://jestjs.io/docs/expect#resolves) (since Bun v0.6.12+)
|
||||
- [`.resolves()`](https://jestjs.io/docs/expect#resolves)
|
||||
|
||||
---
|
||||
|
||||
- 🟢
|
||||
- [`.rejects()`](https://jestjs.io/docs/expect#rejects) (since Bun v0.6.12+)
|
||||
- [`.rejects()`](https://jestjs.io/docs/expect#rejects)
|
||||
|
||||
---
|
||||
|
||||
@@ -385,7 +385,7 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
|
||||
---
|
||||
|
||||
- 🟢
|
||||
- [`.toBeInstanceOf()`](https://jestjs.io/docs/expect#tobeinstanceofclass) (Bun v0.5.8+)
|
||||
- [`.toBeInstanceOf()`](https://jestjs.io/docs/expect#tobeinstanceofclass)
|
||||
|
||||
---
|
||||
|
||||
@@ -405,7 +405,7 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
|
||||
---
|
||||
|
||||
- 🟢
|
||||
- [`.toMatchSnapshot()`](https://jestjs.io/docs/expect#tomatchsnapshotpropertymatchers-hint) (Bun v0.5.8+)
|
||||
- [`.toMatchSnapshot()`](https://jestjs.io/docs/expect#tomatchsnapshotpropertymatchers-hint)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"build-fallback": "esbuild --target=esnext --bundle src/fallback.ts --format=iife --platform=browser --minify > src/fallback.out.js",
|
||||
"postinstall": "bash .scripts/postinstall.sh",
|
||||
"typecheck": "tsc --noEmit && cd test && bun run typecheck",
|
||||
"fmt": "prettier --write --cache './{src,test,bench,packages/{bun-inspector-*,bun-vscode,bun-debug-adapter-protocol}}/**/*.{mjs,ts,tsx,js,jsx}'",
|
||||
"fmt": "prettier --write --cache './{src,test,bench,packages/{bun-types,bun-inspector-*,bun-vscode,bun-debug-adapter-protocol}}/**/*.{mjs,ts,tsx,js,jsx}'",
|
||||
"lint": "eslint './**/*.d.ts' --cache",
|
||||
"lint:fix": "eslint './**/*.d.ts' --cache --fix"
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@ async function loadPackage(pkg: Package, cwd?: string): Promise<void> {
|
||||
}
|
||||
await spawn({
|
||||
cwd: dir,
|
||||
cmd: ["bun", "wiptest", path],
|
||||
cmd: ["bun", "test", path],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,76 @@ A custom runtime layer that runs Bun on AWS Lambda.
|
||||
|
||||
## Setup
|
||||
|
||||
First, you will need to deploy the layer to your AWS account. Clone this repository and run the `publish-layer` script to get started.
|
||||
First, you will need to deploy the layer to your AWS account. Clone this repository and run the `publish-layer` script to get started. Note: the `publish-layer` script also builds the layer.
|
||||
|
||||
```sh
|
||||
git clone git@github.com:oven-sh/bun.git
|
||||
cd packages/bun-lambda
|
||||
cd bun/packages/bun-lambda
|
||||
bun install
|
||||
bun run publish-layer
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Once you publish the layer to your AWS account, you can create a Lambda function that uses the layer.
|
||||
|
||||
### Step 1: Create a Bun Lambda handler function
|
||||
|
||||
In addition to providing the Bun runtime itself, the Bun Lambda Layer also provides an event transformation so you can write your Bun function in a classic Bun server format. This allows you to also run your Lambda function as a local Bun server with `bun run <handler-name>.ts`. Here are some examples of how to write a Bun Lambda function:
|
||||
|
||||
#### HTTP Event Example
|
||||
|
||||
When an event is triggered from [API Gateway](https://docs.aws.amazon.com/lambda/latest/dg/services-apigateway.html), the layer transforms the event payload into a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request). This means you can test your Lambda function locally using `bun run`, without any code changes.
|
||||
|
||||
```ts
|
||||
export default {
|
||||
async fetch(request: Request): Promise<Response> {
|
||||
console.log(request.headers.get("x-amzn-function-arn"));
|
||||
// ...
|
||||
return new Response("Hello from Lambda!", {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "text/plain",
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
#### Non-HTTP Event Example
|
||||
|
||||
For non-HTTP events — S3, SQS, EventBridge, etc. — the event payload is the body of the [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request).
|
||||
|
||||
```ts
|
||||
export default {
|
||||
async fetch(request: Request): Promise<Response> {
|
||||
const event = await request.json();
|
||||
// ...
|
||||
return new Response();
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Step 2: Build the Bun handler
|
||||
|
||||
The final step is to upload your Bun handler. You can technically write the handler directly in the console if you wish, but if you want a full development environment, use the Bun toolkit. There are several ways you can choose to build and manage your artifacts, but follow these steps for a simple approach:
|
||||
|
||||
1. Run `bun build <handler-entry>.[ts|js] --outfile /dist/handler.js`
|
||||
2. Zip the `/dist` folder
|
||||
|
||||
### Step 3: Create the Lambda function on AWS
|
||||
|
||||
Once you've written your Lambda function, you need to configure a new Lambda function to use Bun. The following steps apply to configuring in the console, CloudFormation, CDK, Terraform, or any other configuration management option for AWS:
|
||||
|
||||
1. Create the Lambda function
|
||||
2. Set the Runtime to custom with Amazon Linux 2
|
||||
3. Set the handler to <handler-file-name>.fetch (e.g. if your bundled Bun handler is at `handler.js`, set the handler as `handler.fetch`)
|
||||
4. Set the architecture to whichever architecture you configured when you built/deployed the Lambda Layer
|
||||
5. Attach the Lambda Layer to your new function
|
||||
6. Upload the zip file from step 2. You can do this in the console directly, upload to S3 and set that as the location for the handler file in Lambda, or use something like CDK to manage this for you.
|
||||
|
||||
## API
|
||||
|
||||
### `bun run build-layer`
|
||||
|
||||
Builds a Lambda layer for Bun and saves it to a `.zip` file.
|
||||
@@ -51,42 +112,3 @@ bun run publish-layer -- \
|
||||
--output /path/to/layer.zip \
|
||||
--region us-east-1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Once you publish the layer to your AWS account, you can create a Lambda function that uses the layer.
|
||||
|
||||
Here's an example function that can run on Lambda using the layer for Bun:
|
||||
|
||||
### HTTP events
|
||||
|
||||
When an event is triggered from [API Gateway](https://docs.aws.amazon.com/lambda/latest/dg/services-apigateway.html), the layer transforms the event payload into a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request). This means you can test your Lambda function locally using `bun run`, without any code changes.
|
||||
|
||||
```ts
|
||||
export default {
|
||||
async fetch(request: Request): Promise<Response> {
|
||||
console.log(request.headers.get("x-amzn-function-arn"));
|
||||
// ...
|
||||
return new Response("Hello from Lambda!", {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "text/plain",
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Non-HTTP events
|
||||
|
||||
For non-HTTP events — S3, SQS, EventBridge, etc. — the event payload is the body of the [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request).
|
||||
|
||||
```ts
|
||||
export default {
|
||||
async fetch(request: Request): Promise<Response> {
|
||||
const event = await request.json();
|
||||
// ...
|
||||
return new Response();
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Binary file not shown.
@@ -22,11 +22,11 @@ function log(level: string, ...args: any[]): void {
|
||||
if (!args.length) {
|
||||
return;
|
||||
}
|
||||
const message = Bun.inspect(...args).replace(/\n/g, "\r");
|
||||
const messages = args.map(arg => Bun.inspect(arg).replace(/\n/g, "\r"));
|
||||
if (requestId === undefined) {
|
||||
logger(level, message);
|
||||
logger(level, ...messages);
|
||||
} else {
|
||||
logger(level, `RequestId: ${requestId}`, message);
|
||||
logger(level, `RequestId: ${requestId}`, ...messages);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,6 @@ function formatBody(body?: string, isBase64Encoded?: boolean): string | null {
|
||||
}
|
||||
|
||||
type HttpEventV1 = {
|
||||
readonly version: "1.0";
|
||||
readonly requestContext: {
|
||||
readonly requestId: string;
|
||||
readonly domainName: string;
|
||||
@@ -310,15 +309,12 @@ type HttpEventV1 = {
|
||||
};
|
||||
|
||||
function isHttpEventV1(event: any): event is HttpEventV1 {
|
||||
return event.version === "1.0" && typeof event.requestContext === "object";
|
||||
return !event.Records && event.version !== "2.0" && event.version !== "0" && typeof event.requestContext === "object";
|
||||
}
|
||||
|
||||
function formatHttpEventV1(event: HttpEventV1): Request {
|
||||
const request = event.requestContext;
|
||||
const headers = new Headers();
|
||||
for (const [name, value] of Object.entries(event.headers)) {
|
||||
headers.append(name, value);
|
||||
}
|
||||
for (const [name, values] of Object.entries(event.multiValueHeaders ?? {})) {
|
||||
for (const value of values) {
|
||||
headers.append(name, value);
|
||||
@@ -327,9 +323,6 @@ function formatHttpEventV1(event: HttpEventV1): Request {
|
||||
const hostname = headers.get("Host") ?? request.domainName;
|
||||
const proto = headers.get("X-Forwarded-Proto") ?? "http";
|
||||
const url = new URL(request.path, `${proto}://${hostname}/`);
|
||||
for (const [name, value] of new URLSearchParams(event.queryStringParameters)) {
|
||||
url.searchParams.append(name, value);
|
||||
}
|
||||
for (const [name, values] of Object.entries(event.multiValueQueryStringParameters ?? {})) {
|
||||
for (const value of values ?? []) {
|
||||
url.searchParams.append(name, value);
|
||||
@@ -360,7 +353,7 @@ type HttpEventV2 = {
|
||||
};
|
||||
|
||||
function isHttpEventV2(event: any): event is HttpEventV2 {
|
||||
return event.version === "2.0" && typeof event.requestContext === "object";
|
||||
return !event.Records && event.version === "2.0" && typeof event.requestContext === "object";
|
||||
}
|
||||
|
||||
function formatHttpEventV2(event: HttpEventV2): Request {
|
||||
@@ -389,6 +382,10 @@ function formatHttpEventV2(event: HttpEventV2): Request {
|
||||
});
|
||||
}
|
||||
|
||||
function isHttpEvent(event: any): boolean {
|
||||
return isHttpEventV1(event) || isHttpEventV2(event);
|
||||
}
|
||||
|
||||
type WebSocketEvent = {
|
||||
readonly headers: Record<string, string>;
|
||||
readonly multiValueHeaders: Record<string, string[]>;
|
||||
@@ -538,7 +535,7 @@ class LambdaServer implements Server {
|
||||
statusCode: 200,
|
||||
};
|
||||
}
|
||||
if (!request?.headers.has("Host")) {
|
||||
if (!isHttpEvent(event.event)) {
|
||||
return response.text();
|
||||
}
|
||||
return formatResponse(response);
|
||||
|
||||
@@ -12,7 +12,7 @@ Install the `bun-types` npm package:
|
||||
|
||||
```bash
|
||||
# yarn/npm/pnpm work too, "bun-types" is an ordinary npm package
|
||||
bun add bun-types
|
||||
bun add -d bun-types
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
2
packages/bun-types/bun-test.d.ts
vendored
2
packages/bun-types/bun-test.d.ts
vendored
@@ -1034,7 +1034,7 @@ declare module "bun:test" {
|
||||
* expect("bar").not.toSatisfy((val) => val === "bun");
|
||||
* @link https://vitest.dev/api/expect.html#tosatisfy
|
||||
* @link https://jest-extended.jestcommunity.dev/docs/matchers/toSatisfy
|
||||
*/
|
||||
*/
|
||||
toSatisfy(predicate: (value: T) => boolean): void;
|
||||
/**
|
||||
* Asserts that a value starts with a `string`.
|
||||
|
||||
32
packages/bun-types/bun.d.ts
vendored
32
packages/bun-types/bun.d.ts
vendored
@@ -3767,6 +3767,24 @@ declare module "bun" {
|
||||
*/
|
||||
error?: Errorlike,
|
||||
): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* When specified, Bun will open an IPC channel to the subprocess. The passed callback is called for
|
||||
* incoming messages, and `subprocess.send` can send messages to the subprocess. Messages are serialized
|
||||
* using the JSC serialize API, which allows for the same types that `postMessage`/`structuredClone` supports.
|
||||
*
|
||||
* The subprocess can send and recieve messages by using `process.send` and `process.on("message")`,
|
||||
* respectively. This is the same API as what Node.js exposes when `child_process.fork()` is used.
|
||||
*
|
||||
* Currently, this is only compatible with processes that are other `bun` instances.
|
||||
*/
|
||||
ipc?(
|
||||
message: any,
|
||||
/**
|
||||
* The {@link Subprocess} that sent the message
|
||||
*/
|
||||
subprocess: Subprocess<In, Out, Err>,
|
||||
): void;
|
||||
}
|
||||
|
||||
type OptionsToSubprocess<Opts extends OptionsObject> =
|
||||
@@ -3894,6 +3912,20 @@ declare module "bun" {
|
||||
* This method will tell Bun to not wait for this process to exit before shutting down.
|
||||
*/
|
||||
unref(): void;
|
||||
|
||||
/**
|
||||
* Send a message to the subprocess. This is only supported if the subprocess
|
||||
* was created with the `ipc` option, and is another instance of `bun`.
|
||||
*
|
||||
* Messages are serialized using the JSC serialize API, which allows for the same types that `postMessage`/`structuredClone` supports.
|
||||
*/
|
||||
send(message: any): void;
|
||||
|
||||
/**
|
||||
* Disconnect the IPC channel to the subprocess. This is only supported if the subprocess
|
||||
* was created with the `ipc` option.
|
||||
*/
|
||||
disconnect(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
36
packages/bun-types/ffi.d.ts
vendored
36
packages/bun-types/ffi.d.ts
vendored
@@ -447,9 +447,7 @@ declare module "bun:ffi" {
|
||||
["callback"]: FFIType.pointer; // for now
|
||||
}
|
||||
|
||||
export type FFITypeOrString =
|
||||
| FFIType
|
||||
| keyof FFITypeStringToType;
|
||||
export type FFITypeOrString = FFIType | keyof FFITypeStringToType;
|
||||
|
||||
interface FFIFunction {
|
||||
/**
|
||||
@@ -549,7 +547,9 @@ declare module "bun:ffi" {
|
||||
// */
|
||||
// export function callback(ffi: FFIFunction, cb: Function): number;
|
||||
|
||||
export interface Library<Fns extends Readonly<Record<string, Narrow<FFIFunction>>>> {
|
||||
export interface Library<
|
||||
Fns extends Readonly<Record<string, Narrow<FFIFunction>>>,
|
||||
> {
|
||||
symbols: ConvertFns<Fns>;
|
||||
|
||||
/**
|
||||
@@ -584,7 +584,9 @@ declare module "bun:ffi" {
|
||||
[K in keyof Fns]: (
|
||||
...args: Fns[K]["args"] extends infer A extends readonly FFITypeOrString[]
|
||||
? { [L in keyof A]: FFITypeToArgsType[ToFFIType<A[L]>] }
|
||||
: [unknown] extends [Fns[K]["args"]] ? [] : never
|
||||
: [unknown] extends [Fns[K]["args"]]
|
||||
? []
|
||||
: never
|
||||
) => [unknown] extends [Fns[K]["returns"]]
|
||||
? void
|
||||
: FFITypeToReturnsType[ToFFIType<NonNullable<Fns[K]["returns"]>>];
|
||||
@@ -759,7 +761,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -772,7 +774,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -785,7 +787,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -798,7 +800,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -811,7 +813,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -824,7 +826,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -837,7 +839,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -850,7 +852,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -863,7 +865,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -876,7 +878,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -889,7 +891,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
@@ -902,7 +904,7 @@ declare module "bun:ffi" {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
|
||||
262
packages/bun-types/fs.d.ts
vendored
262
packages/bun-types/fs.d.ts
vendored
@@ -3930,7 +3930,30 @@ declare module "fs" {
|
||||
*/
|
||||
recursive?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class: fs.StatWatcher
|
||||
* Extends `EventEmitter`
|
||||
* A successful call to {@link watchFile} method will return a new fs.StatWatcher object.
|
||||
*/
|
||||
export interface StatWatcher extends EventEmitter {
|
||||
/**
|
||||
* When called, requests that the Node.js event loop _not_ exit so long as the `fs.StatWatcher` is active. Calling `watcher.ref()` multiple times will have
|
||||
* no effect.
|
||||
*
|
||||
* By default, all `fs.StatWatcher` objects are "ref'ed", making it normally
|
||||
* unnecessary to call `watcher.ref()` unless `watcher.unref()` had been
|
||||
* called previously.
|
||||
*/
|
||||
ref(): this;
|
||||
/**
|
||||
* When called, the active `fs.StatWatcher` object will not require the Node.js
|
||||
* event loop to remain active. If there is no other activity keeping the
|
||||
* event loop running, the process may exit before the `fs.StatWatcher` object's
|
||||
* callback is invoked. Calling `watcher.unref()` multiple times will have
|
||||
* no effect.
|
||||
*/
|
||||
unref(): this;
|
||||
}
|
||||
export interface FSWatcher extends EventEmitter {
|
||||
/**
|
||||
* Stop watching for changes on the given `fs.FSWatcher`. Once stopped, the `fs.FSWatcher` object is no longer usable.
|
||||
@@ -4067,6 +4090,243 @@ declare module "fs" {
|
||||
filename: PathLike,
|
||||
listener?: WatchListener<string>,
|
||||
): FSWatcher;
|
||||
/**
|
||||
* Watch for changes on `filename`. The callback `listener` will be called each
|
||||
* time the file is accessed.
|
||||
*
|
||||
* The `options` argument may be omitted. If provided, it should be an object. The`options` object may contain a boolean named `persistent` that indicates
|
||||
* whether the process should continue to run as long as files are being watched.
|
||||
* The `options` object may specify an `interval` property indicating how often the
|
||||
* target should be polled in milliseconds.
|
||||
*
|
||||
* The `listener` gets two arguments the current stat object and the previous
|
||||
* stat object:
|
||||
*
|
||||
* ```js
|
||||
* import { watchFile } from 'fs';
|
||||
*
|
||||
* watchFile('message.text', (curr, prev) => {
|
||||
* console.log(`the current mtime is: ${curr.mtime}`);
|
||||
* console.log(`the previous mtime was: ${prev.mtime}`);
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* These stat objects are instances of `fs.Stat`. If the `bigint` option is `true`,
|
||||
* the numeric values in these objects are specified as `BigInt`s.
|
||||
*
|
||||
* To be notified when the file was modified, not just accessed, it is necessary
|
||||
* to compare `curr.mtimeMs` and `prev.mtimeMs`.
|
||||
*
|
||||
* When an `fs.watchFile` operation results in an `ENOENT` error, it
|
||||
* will invoke the listener once, with all the fields zeroed (or, for dates, the
|
||||
* Unix Epoch). If the file is created later on, the listener will be called
|
||||
* again, with the latest stat objects. This is a change in functionality since
|
||||
* v0.10.
|
||||
*
|
||||
* Using {@link watch} is more efficient than `fs.watchFile` and`fs.unwatchFile`. `fs.watch` should be used instead of `fs.watchFile` and`fs.unwatchFile` when possible.
|
||||
*
|
||||
* When a file being watched by `fs.watchFile()` disappears and reappears,
|
||||
* then the contents of `previous` in the second callback event (the file's
|
||||
* reappearance) will be the same as the contents of `previous` in the first
|
||||
* callback event (its disappearance).
|
||||
*
|
||||
* This happens when:
|
||||
*
|
||||
* * the file is deleted, followed by a restore
|
||||
* * the file is renamed and then renamed a second time back to its original name
|
||||
* @since v0.1.31
|
||||
*/
|
||||
export interface WatchFileOptions {
|
||||
bigint?: boolean | undefined;
|
||||
persistent?: boolean | undefined;
|
||||
interval?: number | undefined;
|
||||
}
|
||||
export type StatsListener = (current: Stats, previous: Stats) => void;
|
||||
export type BigIntStatsListener = (
|
||||
current: BigIntStats,
|
||||
previous: BigIntStats,
|
||||
) => void;
|
||||
/**
|
||||
* Watch for changes on `filename`. The callback `listener` will be called each
|
||||
* time the file is accessed.
|
||||
*
|
||||
* The `options` argument may be omitted. If provided, it should be an object. The`options` object may contain a boolean named `persistent` that indicates
|
||||
* whether the process should continue to run as long as files are being watched.
|
||||
* The `options` object may specify an `interval` property indicating how often the
|
||||
* target should be polled in milliseconds.
|
||||
*
|
||||
* The `listener` gets two arguments the current stat object and the previous
|
||||
* stat object:
|
||||
*
|
||||
* ```js
|
||||
* import { watchFile } from 'node:fs';
|
||||
*
|
||||
* watchFile('message.text', (curr, prev) => {
|
||||
* console.log(`the current mtime is: ${curr.mtime}`);
|
||||
* console.log(`the previous mtime was: ${prev.mtime}`);
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* These stat objects are instances of `fs.Stat`. If the `bigint` option is `true`,
|
||||
* the numeric values in these objects are specified as `BigInt`s.
|
||||
*
|
||||
* To be notified when the file was modified, not just accessed, it is necessary
|
||||
* to compare `curr.mtimeMs` and `prev.mtimeMs`.
|
||||
*
|
||||
* When an `fs.watchFile` operation results in an `ENOENT` error, it
|
||||
* will invoke the listener once, with all the fields zeroed (or, for dates, the
|
||||
* Unix Epoch). If the file is created later on, the listener will be called
|
||||
* again, with the latest stat objects. This is a change in functionality since
|
||||
* v0.10.
|
||||
*
|
||||
* Using {@link watch} is more efficient than `fs.watchFile` and`fs.unwatchFile`. `fs.watch` should be used instead of `fs.watchFile` and`fs.unwatchFile` when possible.
|
||||
*
|
||||
* When a file being watched by `fs.watchFile()` disappears and reappears,
|
||||
* then the contents of `previous` in the second callback event (the file's
|
||||
* reappearance) will be the same as the contents of `previous` in the first
|
||||
* callback event (its disappearance).
|
||||
*
|
||||
* This happens when:
|
||||
*
|
||||
* * the file is deleted, followed by a restore
|
||||
* * the file is renamed and then renamed a second time back to its original name
|
||||
*/
|
||||
export function watchFile(
|
||||
filename: PathLike,
|
||||
options:
|
||||
| (WatchFileOptions & {
|
||||
bigint?: false | undefined;
|
||||
})
|
||||
| undefined,
|
||||
listener: StatsListener,
|
||||
): StatWatcher;
|
||||
export function watchFile(
|
||||
filename: PathLike,
|
||||
options:
|
||||
| (WatchFileOptions & {
|
||||
bigint: true;
|
||||
})
|
||||
| undefined,
|
||||
listener: BigIntStatsListener,
|
||||
): StatWatcher;
|
||||
/**
|
||||
* Watch for changes on `filename`. The callback `listener` will be called each time the file is accessed.
|
||||
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
|
||||
*/
|
||||
export function watchFile(
|
||||
filename: PathLike,
|
||||
listener: StatsListener,
|
||||
): StatWatcher;
|
||||
/**
|
||||
* Stop watching for changes on `filename`. If `listener` is specified, only that
|
||||
* particular listener is removed. Otherwise, _all_ listeners are removed,
|
||||
* effectively stopping watching of `filename`.
|
||||
*
|
||||
* Calling `fs.unwatchFile()` with a filename that is not being watched is a
|
||||
* no-op, not an error.
|
||||
*
|
||||
* Using {@link watch} is more efficient than `fs.watchFile()` and`fs.unwatchFile()`. `fs.watch()` should be used instead of `fs.watchFile()`and `fs.unwatchFile()` when possible.
|
||||
* @since v0.1.31
|
||||
* @param listener Optional, a listener previously attached using `fs.watchFile()`
|
||||
*/
|
||||
export function unwatchFile(
|
||||
filename: PathLike,
|
||||
listener?: StatsListener,
|
||||
): void;
|
||||
export function unwatchFile(
|
||||
filename: PathLike,
|
||||
listener?: BigIntStatsListener,
|
||||
): void;
|
||||
interface CopyOptionsBase {
|
||||
/**
|
||||
* Dereference symlinks
|
||||
* @default false
|
||||
*/
|
||||
dereference?: boolean;
|
||||
/**
|
||||
* When `force` is `false`, and the destination
|
||||
* exists, throw an error.
|
||||
* @default false
|
||||
*/
|
||||
errorOnExist?: boolean;
|
||||
/**
|
||||
* Overwrite existing file or directory. _The copy
|
||||
* operation will ignore errors if you set this to false and the destination
|
||||
* exists. Use the `errorOnExist` option to change this behavior.
|
||||
* @default true
|
||||
*/
|
||||
force?: boolean;
|
||||
/**
|
||||
* Modifiers for copy operation. See `mode` flag of {@link copyFileSync()}
|
||||
*/
|
||||
mode?: number;
|
||||
/**
|
||||
* When `true` timestamps from `source` will
|
||||
* be preserved.
|
||||
* @default false
|
||||
*/
|
||||
preserveTimestamps?: boolean;
|
||||
/**
|
||||
* Copy directories recursively.
|
||||
* @default false
|
||||
*/
|
||||
recursive?: boolean;
|
||||
/**
|
||||
* When true, path resolution for symlinks will be skipped
|
||||
* @default false
|
||||
*/
|
||||
verbatimSymlinks?: boolean;
|
||||
}
|
||||
export interface CopyOptions extends CopyOptionsBase {
|
||||
/**
|
||||
* Function to filter copied files/directories. Return
|
||||
* `true` to copy the item, `false` to ignore it.
|
||||
*/
|
||||
filter?(source: string, destination: string): boolean | Promise<boolean>;
|
||||
}
|
||||
export interface CopySyncOptions extends CopyOptionsBase {
|
||||
/**
|
||||
* Function to filter copied files/directories. Return
|
||||
* `true` to copy the item, `false` to ignore it.
|
||||
*/
|
||||
filter?(source: string, destination: string): boolean;
|
||||
}
|
||||
/**
|
||||
* Asynchronously copies the entire directory structure from `src` to `dest`,
|
||||
* including subdirectories and files.
|
||||
*
|
||||
* When copying a directory to another directory, globs are not supported and
|
||||
* behavior is similar to `cp dir1/ dir2/`.
|
||||
*
|
||||
* @param source source path to copy.
|
||||
* @param destination destination path to copy to.
|
||||
*/
|
||||
export function cp(
|
||||
source: string | URL,
|
||||
destination: string | URL,
|
||||
callback: (error: ErrnoException | null) => void,
|
||||
): void;
|
||||
export function cp(
|
||||
source: string | URL,
|
||||
destination: string | URL,
|
||||
options: CopyOptions,
|
||||
callback: (error: ErrnoException | null) => void,
|
||||
): void;
|
||||
/**
|
||||
* Synchronously copies the entire directory structure from `src` to `dest`,
|
||||
* including subdirectories and files.
|
||||
*
|
||||
* When copying a directory to another directory, globs are not supported and
|
||||
* behavior is similar to `cp dir1/ dir2/`.
|
||||
*
|
||||
* @param source source path to copy.
|
||||
* @param destination destination path to copy to.
|
||||
*/
|
||||
export function cpSync(
|
||||
source: string | URL,
|
||||
destination: string | URL,
|
||||
options?: CopySyncOptions,
|
||||
): void;
|
||||
}
|
||||
|
||||
declare module "node:fs" {
|
||||
|
||||
16
packages/bun-types/fs/promises.d.ts
vendored
16
packages/bun-types/fs/promises.d.ts
vendored
@@ -780,6 +780,22 @@ declare module "fs/promises" {
|
||||
):
|
||||
| AsyncIterable<FileChangeInfo<string>>
|
||||
| AsyncIterable<FileChangeInfo<Buffer>>;
|
||||
/**
|
||||
* Asynchronously copies the entire directory structure from `source` to `destination`,
|
||||
* including subdirectories and files.
|
||||
*
|
||||
* When copying a directory to another directory, globs are not supported and
|
||||
* behavior is similar to `cp dir1/ dir2/`.
|
||||
*
|
||||
* @param source source path to copy.
|
||||
* @param destination destination path to copy to.
|
||||
* @return Fulfills with `undefined` upon success.
|
||||
*/
|
||||
function cp(
|
||||
source: string | URL,
|
||||
destination: string | URL,
|
||||
options?: CopyOptions,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
declare module "node:fs/promises" {
|
||||
|
||||
11
packages/bun-types/globals.d.ts
vendored
11
packages/bun-types/globals.d.ts
vendored
@@ -1,3 +1,5 @@
|
||||
// import * as tls from 'node:tls';
|
||||
|
||||
/**
|
||||
* "blob" is not supported yet
|
||||
*/
|
||||
@@ -1288,6 +1290,7 @@ interface RequestInit {
|
||||
}
|
||||
|
||||
interface FetchRequestInit extends RequestInit {
|
||||
|
||||
/**
|
||||
* Log the raw HTTP request & response to stdout. This API may be
|
||||
* removed in a future version of Bun without notice.
|
||||
@@ -1300,6 +1303,14 @@ interface FetchRequestInit extends RequestInit {
|
||||
* This is a custom property that is not part of the Fetch API specification.
|
||||
*/
|
||||
proxy?: string;
|
||||
|
||||
/**
|
||||
* Override the default TLS options
|
||||
*/
|
||||
tls?: {
|
||||
rejectUnauthorized?: boolean | undefined; // Defaults to true
|
||||
checkServerIdentity?: any | undefined; // TODO: change `any` to `checkServerIdentity`
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
2
packages/bun-types/module.d.ts
vendored
2
packages/bun-types/module.d.ts
vendored
@@ -4,7 +4,7 @@ declare module "node:module" {
|
||||
|
||||
declare module "module" {
|
||||
export function createRequire(filename: string): NodeJS.Require;
|
||||
export function _resolveFileName(
|
||||
export function _resolveFilename(
|
||||
path: string,
|
||||
parent: string,
|
||||
isMain: boolean,
|
||||
|
||||
@@ -86,7 +86,6 @@ struct us_internal_ssl_socket_context_t {
|
||||
/* Pointer to sni tree, created when the context is created and freed likewise when freed */
|
||||
void *sni;
|
||||
|
||||
int pending_handshake;
|
||||
void (*on_handshake)(struct us_internal_ssl_socket_t *, int success, struct us_bun_verify_error_t verify_error, void* custom_data);
|
||||
void* handshake_data;
|
||||
};
|
||||
@@ -97,6 +96,7 @@ struct us_internal_ssl_socket_t {
|
||||
SSL *ssl;
|
||||
int ssl_write_wants_read; // we use this for now
|
||||
int ssl_read_wants_write;
|
||||
int pending_handshake;
|
||||
};
|
||||
|
||||
int passphrase_cb(char *buf, int size, int rwflag, void *u) {
|
||||
@@ -164,6 +164,7 @@ int BIO_s_custom_read(BIO *bio, char *dst, int length) {
|
||||
struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s, int is_client, char *ip, int ip_length) {
|
||||
|
||||
struct us_internal_ssl_socket_context_t *context = (struct us_internal_ssl_socket_context_t *) us_socket_context(0, &s->s);
|
||||
|
||||
|
||||
struct us_loop_t *loop = us_socket_context_loop(0, &context->sc);
|
||||
struct loop_ssl_data *loop_ssl_data = (struct loop_ssl_data *) loop->data.ssl_data;
|
||||
@@ -186,7 +187,9 @@ struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s,
|
||||
struct us_internal_ssl_socket_t * result = (struct us_internal_ssl_socket_t *) context->on_open(s, is_client, ip, ip_length);
|
||||
|
||||
// Hello Message!
|
||||
if(context->pending_handshake) {
|
||||
// always handshake after open if on_handshake is set
|
||||
if(context->on_handshake || s->pending_handshake) {
|
||||
s->pending_handshake = 1;
|
||||
us_internal_ssl_handshake(s, context->on_handshake, context->handshake_data);
|
||||
}
|
||||
|
||||
@@ -195,7 +198,6 @@ struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s,
|
||||
|
||||
|
||||
void us_internal_on_ssl_handshake(struct us_internal_ssl_socket_context_t * context, void (*on_handshake)(struct us_internal_ssl_socket_t *, int success, struct us_bun_verify_error_t verify_error, void* custom_data), void* custom_data) {
|
||||
context->pending_handshake = 1;
|
||||
context->on_handshake = on_handshake;
|
||||
context->handshake_data = custom_data;
|
||||
}
|
||||
@@ -206,7 +208,7 @@ void us_internal_ssl_handshake(struct us_internal_ssl_socket_t *s, void (*on_han
|
||||
// will start on_open, on_writable or on_data
|
||||
if(!s->ssl) {
|
||||
|
||||
context->pending_handshake = 1;
|
||||
s->pending_handshake = 1;
|
||||
context->on_handshake = on_handshake;
|
||||
context->handshake_data = custom_data;
|
||||
return;
|
||||
@@ -218,9 +220,7 @@ void us_internal_ssl_handshake(struct us_internal_ssl_socket_t *s, void (*on_han
|
||||
loop_ssl_data->ssl_socket = &s->s;
|
||||
|
||||
if (us_socket_is_closed(0, &s->s) || us_internal_ssl_socket_is_shut_down(s)) {
|
||||
context->pending_handshake = 0;
|
||||
context->on_handshake = NULL;
|
||||
context->handshake_data = NULL;
|
||||
s->pending_handshake = 0;
|
||||
|
||||
struct us_bun_verify_error_t verify_error = (struct us_bun_verify_error_t) { .error = 0, .code = NULL, .reason = NULL };
|
||||
if(on_handshake != NULL) {
|
||||
@@ -236,9 +236,7 @@ void us_internal_ssl_handshake(struct us_internal_ssl_socket_t *s, void (*on_han
|
||||
int err = SSL_get_error(s->ssl, result);
|
||||
// as far as I know these are the only errors we want to handle
|
||||
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
|
||||
context->pending_handshake = 0;
|
||||
context->on_handshake = NULL;
|
||||
context->handshake_data = NULL;
|
||||
s->pending_handshake = 0;
|
||||
|
||||
struct us_bun_verify_error_t verify_error = us_internal_verify_error(s);
|
||||
// clear per thread error queue if it may contain something
|
||||
@@ -252,7 +250,7 @@ void us_internal_ssl_handshake(struct us_internal_ssl_socket_t *s, void (*on_han
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
context->pending_handshake = 1;
|
||||
s->pending_handshake = 1;
|
||||
context->on_handshake = on_handshake;
|
||||
context->handshake_data = custom_data;
|
||||
// Ensure that we'll cycle through internal openssl's state
|
||||
@@ -262,10 +260,7 @@ void us_internal_ssl_handshake(struct us_internal_ssl_socket_t *s, void (*on_han
|
||||
|
||||
}
|
||||
} else {
|
||||
context->pending_handshake = 0;
|
||||
context->on_handshake = NULL;
|
||||
context->handshake_data = NULL;
|
||||
|
||||
s->pending_handshake = 0;
|
||||
|
||||
struct us_bun_verify_error_t verify_error = us_internal_verify_error(s);
|
||||
// success
|
||||
@@ -283,16 +278,16 @@ void us_internal_ssl_handshake(struct us_internal_ssl_socket_t *s, void (*on_han
|
||||
|
||||
struct us_internal_ssl_socket_t *us_internal_ssl_socket_close(struct us_internal_ssl_socket_t *s, int code, void *reason) {
|
||||
struct us_internal_ssl_socket_context_t *context = (struct us_internal_ssl_socket_context_t *) us_socket_context(0, &s->s);
|
||||
if (context->pending_handshake) {
|
||||
context->pending_handshake = 0;
|
||||
if (s->pending_handshake) {
|
||||
s->pending_handshake = 0;
|
||||
}
|
||||
return (struct us_internal_ssl_socket_t *) us_socket_close(0, (struct us_socket_t *) s, code, reason);
|
||||
}
|
||||
|
||||
struct us_internal_ssl_socket_t *ssl_on_close(struct us_internal_ssl_socket_t *s, int code, void *reason) {
|
||||
struct us_internal_ssl_socket_context_t *context = (struct us_internal_ssl_socket_context_t *) us_socket_context(0, &s->s);
|
||||
if (context->pending_handshake) {
|
||||
context->pending_handshake = 0;
|
||||
if (s->pending_handshake) {
|
||||
s->pending_handshake = 0;
|
||||
}
|
||||
SSL_free(s->ssl);
|
||||
|
||||
@@ -300,11 +295,8 @@ struct us_internal_ssl_socket_t *ssl_on_close(struct us_internal_ssl_socket_t *s
|
||||
}
|
||||
|
||||
struct us_internal_ssl_socket_t *ssl_on_end(struct us_internal_ssl_socket_t *s) {
|
||||
if(&s->s) {
|
||||
struct us_internal_ssl_socket_context_t *context = (struct us_internal_ssl_socket_context_t *) us_socket_context(0, &s->s);
|
||||
if (context && context->pending_handshake) {
|
||||
context->pending_handshake = 0;
|
||||
}
|
||||
if(&s->s && s->pending_handshake) {
|
||||
s->pending_handshake = 0;
|
||||
}
|
||||
// whatever state we are in, a TCP FIN is always an answered shutdown
|
||||
|
||||
@@ -322,7 +314,7 @@ struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s,
|
||||
struct us_loop_t *loop = us_socket_context_loop(0, &context->sc);
|
||||
struct loop_ssl_data *loop_ssl_data = (struct loop_ssl_data *) loop->data.ssl_data;
|
||||
|
||||
if(context->pending_handshake) {
|
||||
if(s->pending_handshake) {
|
||||
us_internal_ssl_handshake(s, context->on_handshake, context->handshake_data);
|
||||
}
|
||||
|
||||
@@ -477,7 +469,7 @@ struct us_internal_ssl_socket_t *ssl_on_writable(struct us_internal_ssl_socket_t
|
||||
|
||||
struct us_internal_ssl_socket_context_t *context = (struct us_internal_ssl_socket_context_t *) us_socket_context(0, &s->s);
|
||||
|
||||
if(context->pending_handshake) {
|
||||
if(s->pending_handshake) {
|
||||
us_internal_ssl_handshake(s, context->on_handshake, context->handshake_data);
|
||||
}
|
||||
|
||||
@@ -1302,10 +1294,8 @@ struct us_internal_ssl_socket_context_t *us_internal_create_ssl_socket_context(s
|
||||
context->ssl_context = ssl_context;//create_ssl_context_from_options(options);
|
||||
context->is_parent = 1;
|
||||
|
||||
context->pending_handshake = 0;
|
||||
context->on_handshake = NULL;
|
||||
context->handshake_data = NULL;
|
||||
|
||||
/* We, as parent context, may ignore data */
|
||||
context->sc.is_low_prio = (int (*)(struct us_socket_t *)) ssl_is_low_prio;
|
||||
|
||||
@@ -1340,10 +1330,9 @@ struct us_internal_ssl_socket_context_t *us_internal_bun_create_ssl_socket_conte
|
||||
/* Then we extend its SSL parts */
|
||||
context->ssl_context = ssl_context;//create_ssl_context_from_options(options);
|
||||
context->is_parent = 1;
|
||||
context->pending_handshake = 0;
|
||||
|
||||
context->on_handshake = NULL;
|
||||
context->handshake_data = NULL;
|
||||
|
||||
/* We, as parent context, may ignore data */
|
||||
context->sc.is_low_prio = (int (*)(struct us_socket_t *)) ssl_is_low_prio;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// clang-format off
|
||||
|
||||
#ifndef us_malloc
|
||||
#define us_malloc malloc
|
||||
@@ -383,6 +384,8 @@ int us_socket_local_port(int ssl, struct us_socket_t *s);
|
||||
void us_socket_remote_address(int ssl, struct us_socket_t *s, char *buf, int *length);
|
||||
|
||||
/* Bun extras */
|
||||
struct us_socket_t *us_socket_pair(struct us_socket_context_t *ctx, int socket_ext_size, LIBUS_SOCKET_DESCRIPTOR* fds);
|
||||
struct us_socket_t *us_socket_from_fd(struct us_socket_context_t *ctx, int socket_ext_size, LIBUS_SOCKET_DESCRIPTOR fd);
|
||||
struct us_socket_t *us_socket_detach(int ssl, struct us_socket_t *s);
|
||||
struct us_socket_t *us_socket_attach(int ssl, LIBUS_SOCKET_DESCRIPTOR client_fd, struct us_socket_context_t *ctx, int flags, int socket_ext_size);
|
||||
struct us_socket_t *us_socket_wrap_with_tls(int ssl, struct us_socket_t *s, struct us_bun_socket_context_options_t options, struct us_socket_events_t events, int socket_ext_size);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// clang-format off
|
||||
|
||||
#include "libusockets.h"
|
||||
#include "internal/internal.h"
|
||||
@@ -192,6 +193,45 @@ struct us_socket_t *us_socket_attach(int ssl, LIBUS_SOCKET_DESCRIPTOR client_fd,
|
||||
return s;
|
||||
}
|
||||
|
||||
struct us_socket_t *us_socket_pair(struct us_socket_context_t *ctx, int socket_ext_size, LIBUS_SOCKET_DESCRIPTOR* fds) {
|
||||
#ifdef LIBUS_USE_LIBUV
|
||||
return 0;
|
||||
#endif
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return us_socket_from_fd(ctx, socket_ext_size, fds[0]);
|
||||
}
|
||||
|
||||
|
||||
struct us_socket_t *us_socket_from_fd(struct us_socket_context_t *ctx, int socket_ext_size, LIBUS_SOCKET_DESCRIPTOR fd) {
|
||||
#ifdef LIBUS_USE_LIBUV
|
||||
return 0;
|
||||
#endif
|
||||
struct us_poll_t *p1 = us_create_poll(ctx->loop, 0, sizeof(struct us_socket_t) + socket_ext_size);
|
||||
us_poll_init(p1, fd, POLL_TYPE_SOCKET);
|
||||
us_poll_start(p1, ctx->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
|
||||
|
||||
struct us_socket_t *s = (struct us_socket_t *) p1;
|
||||
s->context = ctx;
|
||||
s->timeout = 0;
|
||||
s->long_timeout = 0;
|
||||
s->low_prio_state = 0;
|
||||
|
||||
/* We always use nodelay */
|
||||
bsd_socket_nodelay(fd, 1);
|
||||
|
||||
us_internal_socket_context_link_socket(ctx, s);
|
||||
|
||||
if (ctx->on_open) {
|
||||
ctx->on_open(s, 0, 0, 0);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/* Not shared with SSL */
|
||||
|
||||
void *us_socket_get_native_handle(int ssl, struct us_socket_t *s) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user