diff options
author | 2023-04-13 18:26:45 -0700 | |
---|---|---|
committer | 2023-04-13 18:26:45 -0700 | |
commit | 011e157cac7698050370e24495a9002dacfceea9 (patch) | |
tree | ebb561dbda3e8f67302cc4d5b398f4a2744f7884 | |
parent | 0cc56e8efce9c7d4905b3649827bf9b40a677b25 (diff) | |
download | bun-011e157cac7698050370e24495a9002dacfceea9.tar.gz bun-011e157cac7698050370e24495a9002dacfceea9.tar.zst bun-011e157cac7698050370e24495a9002dacfceea9.zip |
Docs restructuring (#2638)
* Restructure
* Update nav
* Reorg
* Reshuffle ecosystem pages
* Split up runtime/runtime
* Back to runtime/index
* Fix issue
* Split up runtime/index
* Add Writing Tests page
* Prettier matcher table
* More updates
38 files changed, 1745 insertions, 926 deletions
diff --git a/docs/api/ffi.md b/docs/api/ffi.md index 13b50f9c7..d6ed23f47 100644 --- a/docs/api/ffi.md +++ b/docs/api/ffi.md @@ -1,5 +1,7 @@ Use the built-in `bun:ffi` module to efficiently call native libraries from JavaScript. It works with languages that support the C ABI (Zig, Rust, C/C++, C#, Nim, Kotlin, etc). +## Usage (`bun:ffi`) + To print the version number of `sqlite3`: ```ts @@ -227,11 +229,7 @@ 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 @@ -251,13 +249,10 @@ 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)) { @@ -278,7 +273,7 @@ When you're done with a JSCallback, you should call `close()` to free the memory **⚡️ Performance tip** — For a slight performance boost, directly pass `JSCallback.prototype.ptr` instead of the `JSCallback` object: ```ts -const onResolve = new JSCallback((arg) => arg === 42, { +const onResolve = new JSCallback(arg => arg === 42, { returns: "bool", args: ["i32"], }); diff --git a/docs/api/file-io.md b/docs/api/file-io.md index 35d639422..ca78338d2 100644 --- a/docs/api/file-io.md +++ b/docs/api/file-io.md @@ -1,10 +1,10 @@ {% callout %} -**Note** — The `Bun.file` and `Bun.write` APIs documented on this page are heavily optimized and represent the recommended way to perform file-system tasks using Bun. Existing Node.js projects may use Bun's [nearly complete](/docs/ecosystem/nodejs#node_fs) implementation of the [`node:fs`](https://nodejs.org/api/fs.html) module. +**Note** — The `Bun.file` and `Bun.write` APIs documented on this page are heavily optimized and represent the recommended way to perform file-system tasks using Bun. Existing Node.js projects may use Bun's [nearly complete](/docs/runtime/nodejs-apis#node_fs) implementation of the [`node:fs`](https://nodejs.org/api/fs.html) module. {% /callout %} Bun provides a set of optimized APIs for reading and writing files. -## Reading files +## Reading files (`Bun.file()`) `Bun.file(path): BunFile` @@ -56,7 +56,7 @@ Bun.stdout; Bun.stderr; ``` -## Writing files +## Writing files (`Bun.write()`) `Bun.write(destination, data): Promise<number>` diff --git a/docs/api/globals.md b/docs/api/globals.md index d49069590..f5fc411dc 100644 --- a/docs/api/globals.md +++ b/docs/api/globals.md @@ -34,7 +34,7 @@ Bun implements the following globals. - [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) - Node.js -- See [Node.js > `Buffer`](/docs/ecosystem/nodejs#node_buffer) +- See [Node.js > `Buffer`](/docs/runtime/nodejs-apis#node_buffer) --- @@ -172,7 +172,7 @@ Bun implements the following globals. - [`global`](https://nodejs.org/api/globals.html#global) - Node.js -- See [Node.js > `global`](/docs/ecosystem/nodejs#node_global). +- See [Node.js > `global`](/docs/runtime/nodejs-apis#node_global). --- @@ -214,7 +214,7 @@ Bun implements the following globals. - [`process`](https://nodejs.org/api/process.html) - Node.js -- See [Node.js > `process`](/docs/ecosystem/nodejs#node_process) +- See [Node.js > `process`](/docs/runtime/nodejs-apis#node_process) --- diff --git a/docs/api/http.md b/docs/api/http.md index 3e11299dd..3ebdafab9 100644 --- a/docs/api/http.md +++ b/docs/api/http.md @@ -1,8 +1,8 @@ {% callout %} -**Note** — This page documents the `Bun.serve` API. This API is heavily optimized and represents the recommended way to build HTTP servers in Bun. Existing Node.js projects may use Bun's [nearly complete](/docs/ecosystem/nodejs#node_http) implementation of the Node.js [`http`](https://nodejs.org/api/http.html) and [`https`](https://nodejs.org/api/https.html) modules. +**Note** — This page documents the `Bun.serve` API. This API is heavily optimized and represents the recommended way to build HTTP servers in Bun. Existing Node.js projects may use Bun's [nearly complete](/docs/runtime/nodejs-apis#node_http) implementation of the Node.js [`http`](https://nodejs.org/api/http.html) and [`https`](https://nodejs.org/api/https.html) modules. {% /callout %} -## Send a request +## Send a request (`fetch()`) Bun implements the Web `fetch` API for making HTTP requests. The `fetch` function is available in the global scope. @@ -13,7 +13,7 @@ console.log(result.icons[0].src); // => "/logo-square.jpg" ``` -## Start a server +## Start a server (`Bun.serve()`) Start an HTTP server in Bun with `Bun.serve`. diff --git a/docs/api/spawn.md b/docs/api/spawn.md index 100969aa3..1ef81f1b7 100644 --- a/docs/api/spawn.md +++ b/docs/api/spawn.md @@ -1,6 +1,6 @@ Spawn child processes with `Bun.spawn` or `Bun.spawnSync`. -## Spawn a process +## Spawn a process (`Bun.spawn()`) Provide a command as an array of strings. The result of `Bun.spawn()` is a `Bun.Subprocess` object. @@ -28,9 +28,7 @@ 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(); @@ -183,7 +181,7 @@ const proc = Bun.spawn(["echo", "hello"]); proc.unref(); ``` -## Blocking API +## Blocking API (`Bun.spawnSync()`) Bun provides a synchronous equivalent of `Bun.spawn` called `Bun.spawnSync`. This is a blocking API that supports the same inputs and parameters as `Bun.spawn`. It returns a `SyncSubprocess` object, which differs from `Subprocess` in a few ways. @@ -245,12 +243,7 @@ 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 = @@ -262,7 +255,7 @@ namespace SpawnOptions { | BunFile | ArrayBufferView | number; - + type Writable = | "pipe" | "inherit" @@ -307,10 +300,10 @@ interface SyncSubprocess<Stdout, Stderr> { type ReadableSubprocess = Subprocess<any, "pipe", "pipe">; type WritableSubprocess = Subprocess<"pipe", any, any>; type PipedSubprocess = Subprocess<"pipe", "pipe", "pipe">; -type NullSubprocess = Subprocess<null, null, null> +type NullSubprocess = Subprocess<null, null, null>; type ReadableSyncSubprocess = SyncSubprocess<"pipe", "pipe">; -type NullSyncSubprocess = SyncSubprocess<null, null> +type NullSyncSubprocess = SyncSubprocess<null, null>; type Signal = | "SIGABRT" diff --git a/docs/api/tcp.md b/docs/api/tcp.md index 5e04dd348..999464f3f 100644 --- a/docs/api/tcp.md +++ b/docs/api/tcp.md @@ -1,6 +1,6 @@ Use Bun's native TCP API implement performance sensitive systems like database clients, game servers, or anything that needs to communicate over TCP (instead of HTTP). This is a low-level API intended for library authors and for advanced use cases. -## Start a server +## Start a server (`Bun.listen()`) To start a TCP server with `Bun.listen`: @@ -90,7 +90,7 @@ server.stop(true); server.unref(); ``` -## Create a connection +## Create a connection (`Bun.connect()`) Use `Bun.connect` to connect to a TCP server. Specify the server to connect to with `hostname` and `port`. TCP clients can define the same set of handlers as `Bun.listen`, plus a couple client-specific handlers. @@ -136,7 +136,7 @@ const server = Bun.listen({ /* config */ }) // reloads handlers for all active server-side sockets server.reload({ - socket: + socket: { data(){ // new 'data' handler } diff --git a/docs/api/utils.md b/docs/api/utils.md index ce3d0d6f9..59167b2b7 100644 --- a/docs/api/utils.md +++ b/docs/api/utils.md @@ -94,9 +94,7 @@ test("peek", () => { // If we peek a rejected promise, it: // - returns the error // - does not mark the promise as handled - const rejected = Promise.reject( - new Error("Successfully tested promise rejection"), - ); + const rejected = Promise.reject(new Error("Successfully tested promise rejection")); expect(peek(rejected).message).toBe("Successfully tested promise rejection"); }); ``` @@ -128,7 +126,7 @@ const currentFile = import.meta.url; Bun.openInEditor(currentFile); ``` -You can override this via the `debug.editor` setting in your [`bunfig.toml`](/docs/project/configuration) +You can override this via the `debug.editor` setting in your [`bunfig.toml`](/docs/runtime/configuration) ```toml-diff#bunfig.toml + [debug] @@ -142,5 +140,5 @@ Bun.openInEditor(import.meta.url, { editor: "vscode", // or "subl" line: 10, column: 5, -}) +}); ``` diff --git a/docs/api/websockets.md b/docs/api/websockets.md index f04d10fc6..0c40a05c0 100644 --- a/docs/api/websockets.md +++ b/docs/api/websockets.md @@ -12,7 +12,7 @@ Internally Bun's WebSocket implementation is built on [uWebSockets](https://github.com/uNetworking/uWebSockets). {% /callout %} -## Create a client +## Connect to a WebSocket server To connect to an external socket server, create an instance of `WebSocket` with the constructor. @@ -46,7 +46,7 @@ socket.addEventListener("close", event => {}); socket.addEventListener("error", event => {}); ``` -## Create a server +## Create a WebSocket server Below is a simple WebSocket server built with `Bun.serve`, in which all incoming requests are [upgraded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism) to WebSocket connections in the `fetch` handler. The socket handlers are declared in the `websocket` parameter. diff --git a/docs/cli/bunx.md b/docs/cli/bunx.md index 0e6787fc1..fe7bd80a2 100644 --- a/docs/cli/bunx.md +++ b/docs/cli/bunx.md @@ -1,8 +1,8 @@ {% callout %} -**Note** — `bunx` is an alias for `bun x` +**Note** — `bunx` is an alias for `bun x`. The `bunx` CLI will be auto-installed when you install `bun`. {% /callout %} -Use `bunx` to auto-install and run packages from `npm`. The `bunx` CLI will be auto-installed when you install `bun`. +Use `bunx` to auto-install and run packages from `npm`. It's Bun's equivalent of `npx` or `yarn dlx`. ```bash $ bunx cowsay "Hello world!" @@ -50,7 +50,7 @@ $ bunx my-cli --foo bar ## Shebangs -By default, Bun respects shebangs. If an executable is marked with `#!/usr/bin/env node`, Bun will spin up a `node` process to execute the file. However, in some cases it may be desirable to run executables using [Bun's runtime](/docs/runtime), even if the executable indicates otherwise. To do so, include the `--bun` flag. +By default, Bun respects shebangs. If an executable is marked with `#!/usr/bin/env node`, Bun will spin up a `node` process to execute the file. However, in some cases it may be desirable to run executables using Bun's runtime, even if the executable indicates otherwise. To do so, include the `--bun` flag. ```bash $ bunx --bun my-cli @@ -66,7 +66,7 @@ $ bunx my-cli --bun # bad {% /callout %} -## Environment variables +<!-- ## Environment variables Bun automatically loads environment variables from `.env` files before running a file, script, or executable. The following files are checked, in order: @@ -74,4 +74,4 @@ Bun automatically loads environment variables from `.env` files before running a 2. `NODE_ENV` === `"production"` ? `.env.production` : `.env.development` 3. `.env` -To debug environment variables, run `bun run env` to view a list of resolved environment variables. +To debug environment variables, run `bun run env` to view a list of resolved environment variables. --> diff --git a/docs/cli/create.md b/docs/cli/create.md index a6dc90c2c..393378eed 100644 --- a/docs/cli/create.md +++ b/docs/cli/create.md @@ -1,3 +1,29 @@ +## `bun init` + +Scaffold an empty project with `bun init`. It's an interactive tool. + +```bash +$ bun init +bun init helps you get started with a minimal project and tries to +guess sensible defaults. Press ^C anytime to quit. + +package name (quickstart): +entry point (index.ts): + +Done! A package.json file was saved in the current directory. + + index.ts + + .gitignore + + tsconfig.json (for editor auto-complete) + + README.md + +To get started, run: + bun run index.ts +``` + +Press `enter` to accept the default answer for each prompt, or pass the `-y` flag to auto-accept the defaults. + +## `bun create` + Template a new Bun project with `bun create`. ```bash diff --git a/docs/cli/install.md b/docs/cli/install.md index 4018a1d19..811c9ec95 100644 --- a/docs/cli/install.md +++ b/docs/cli/install.md @@ -1,8 +1,8 @@ -The `bun` CLI contains an `npm`-compatible package manager designed to be a faster replacement for existing package management tools like `npm`, `yarn`, and `pnpm`. It's designed for Node.js compatibility; use it in any Bun or Node.js project. +The `bun` CLI contains a Node.js-compatible package manager designed to be a dramatically faster replacement for `npm`, `yarn`, and `pnpm`. It's a standalone tool that will work in pre-existing Node.js projects; if your project has a `package.json`, `bun install` can help you speed up your workflow. {% callout %} -**⚡️ 80x faster** — Switch from `npm install` to `bun install` in any Node.js project to make your installations up to 80x faster. +**⚡️ 25x faster** — Switch from `npm install` to `bun install` in any Node.js project to make your installations up to 25x faster. {% image src="https://user-images.githubusercontent.com/709451/147004342-571b6123-17a9-49a2-8bfd-dcfc5204047e.png" height="200" /%} @@ -23,7 +23,9 @@ sudo apt install --install-recommends linux-generic-hwe-20.04 {% /details %} -## Install dependencies +## Manage dependencies + +### `bun install` To install all dependencies of a project: @@ -84,13 +86,12 @@ dryRun = false {% /details %} -## Add and remove packages +### `bun add` -To add or remove a particular package: +To add a particular package: ```bash $ bun add preact -$ bun remove preact ``` To specify a version, version range, or tag: @@ -147,222 +148,15 @@ To view a complete list of options for a given command: $ bun add --help ``` -## Git dependencies +### `bun remove` -To add a dependency from a git repository: +To remove a dependency: ```bash -$ bun install git@github.com:moment/moment.git -``` - -Bun supports a variety of protocols, including [`github`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#github-urls), [`git`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#git-urls-as-dependencies), `git+ssh`, `git+https`, and many more. - -```json -{ - "dependencies": { - "dayjs": "git+https://github.com/iamkun/dayjs.git", - "lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21", - "moment": "git@github.com:moment/moment.git", - "zod": "github:colinhacks/zod" - } -} -``` - -## Global cache - -All packages downloaded from the registry are stored in a global cache at `~/.bun/install/cache`. They are stored in subdirectories named like `${name}@${version}`, so multiple versions of a package can be cached. - -{% details summary="Configuring cache behavior" %} - -```toml -[install.cache] -# the directory to use for the cache -dir = "~/.bun/install/cache" - -# when true, don't load from the global cache. -# Bun may still write to node_modules/.cache -disable = false - -# when true, always resolve the latest versions from the registry -disableManifest = false -``` - -{% /details %} - -### Minimizing re-downloads - -Bun strives to avoid re-downloading packages mutiple times. When installing a package, if the cache already contains a version in the range specified by `package.json`, Bun will use the cached package instead of downloading it again. - -{% details summary="Installation details" %} -If the semver version has pre-release suffix (`1.0.0-beta.0`) or a build suffix (`1.0.0+20220101`), it is replaced with a hash of that value instead, to reduce the chances of errors associated with long file paths. - -When the `node_modules` folder exists, before installing, Bun checks that `node_modules` contains all expected packages with appropriate versions. If so `bun install` completes. Bun uses a custom JSON parser which stops parsing as soon as it finds `"name"` and `"version"`. - -If a package is missing or has a version incompatible with the `package.json`, Bun checks for a compatible module in the cache. If found, it is installed into `node_modules`. Otherwise, the package will be downloaded from the registry then installed. -{% /details %} - -### Fast copying - -Once a package is downloaded into the cache, Bun still needs to copy those files into `node_modules`. Bun uses the fastest syscalls available to perform this task. On Linux, it uses hardlinks; on macOS, it uses `clonefile`. - -### Saving disk space - -Since Bun uses hardlinks to "copy" a module into a project's `node_modules` directory on Linux, the contents of the package only exist in a single location on disk, greatly reducing the amount of disk space dedicated to `node_modules`. - -This benefit does not extend to macOS, which uses `clonefile` for performance reasons. - -{% details summary="Installation strategies" %} -This behavior is configurable with the `--backend` flag, which is respected by all of Bun's package management commands. - -- **`hardlink`**: Default on Linux. -- **`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. - -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). - -```bash -$ bun install --backend symlink -$ node --preserve-symlinks ./foo.js -``` - -Bun's runtime does not currently expose an equivalent of `--preserve-symlinks`. -{% /details %} - -## Lockfile - -Running `bun install` will create a binary lockfile called `bun.lockb`. - -#### Why is it binary? - -In a word: Performance. Bun’s lockfile saves & loads incredibly quickly, and saves a lot more data than what is typically inside lockfiles. - -#### How do I inspect it? - -Run `bun install -y` to generate a Yarn-compatible `yarn.lock` (v1) that can be inspected more easily. - -#### Platform-specific dependencies? - -Bun stores normalized `cpu` and `os` values from npm in the lockfile, along with the resolved packages. It skips downloading, extracting, and installing packages disabled for the current target at runtime. This means the lockfile won’t change between platforms/architectures even if the packages ultimately installed do change. - -#### What does the lockfile store? - -Packages, metadata for those packages, the hoisted install order, dependencies for each package, what packages those dependencies resolved to, an integrity hash (if available), what each package was resolved to, and which version (or equivalent). - -#### Why is it fast? - -It uses linear arrays for all data. [Packages](https://github.com/oven-sh/bun/blob/be03fc273a487ac402f19ad897778d74b6d72963/src/install/install.zig#L1825) are referenced by an auto-incrementing integer ID or a hash of the package name. Strings longer than 8 characters are de-duplicated. Prior to saving on disk, the lockfile is garbage-collected & made deterministic by walking the package tree and cloning the packages in dependency order. - -#### Can I opt out? - -To install without creating a lockfile: - -```bash -$ bun install --no-save -``` - -To install a Yarn lockfile _in addition_ to `bun.lockb`. - -{% codetabs %} - -```bash#CLI flag -$ bun install --yarn -``` - -```toml#bunfig.toml -[install.lockfile] -# whether to save a non-Bun lockfile alongside bun.lockb -# only "yarn" is supported -print = "yarn" -``` - -{% /codetabs %} - -{% details summary="Configuring lockfile" %} - -```toml -[install.lockfile] - -# path to read bun.lockb from -path = "bun.lockb" - -# path to save bun.lockb to -savePath = "bun.lockb" - -# whether to save the lockfile to disk -save = true - -# whether to save a non-Bun lockfile alongside bun.lockb -# only "yarn" is supported -print = "yarn" -``` - -{% /details %} - -## Workspaces - -Bun supports [`workspaces`](https://docs.npmjs.com/cli/v9/using-npm/workspaces?v=true#description) in `package.json`. Workspaces make it easy to develop complex software as a _monorepo_ consisting of several independent packages. - -To try it, specify a list of sub-packages in the `workspaces` field of your `package.json`; it's conventional to place these sub-packages in a directory called `packages`. - -```json -{ - "name": "my-project", - "version": "1.0.0", - "workspaces": ["packages/*"] -} -``` - -{% callout %} -**Glob support** — Bun v0.5.8 added support for simple globs for workspace names, with a "*/" at the end. Nothing too fancy. -{% /callout %} - -This has a couple major benefits. - -- **Code can be split into logical parts.** If one package relies on another, you can simply add it as a dependency with `bun add`. If package `b` depends on `a`, `bun install` will symlink your local `packages/a` directory into the `node_modules` folder of `b`, instead of trying to download it from the npm registry. -- **Dependencies can be de-duplicated.** If `a` and `b` share a common dependency, it will be _hoisted_ to the root `node_modules` directory. This reduces redundant disk usage and minimizes "dependency hell" issues associated with having multiple versions of a package installed simultaneously. - -{% callout %} -⚡️ **Speed** — Installs are fast, even for big monorepos. Bun installs the [Remix](https://github.com/remix-run/remix) monorepo in about `500ms` on Linux. - -- 28x faster than `npm install` -- 12x faster than `yarn install` (v1) -- 8x faster than `pnpm install` - -{% image src="https://user-images.githubusercontent.com/709451/212829600-77df9544-7c9f-4d8d-a984-b2cd0fd2aa52.png" /%} -{% /callout %} - -## Registries - -The default registry is `registry.npmjs.org`. This can be globally configured in `bunfig.toml`: - -```toml -[install] -# set default registry as a string -registry = "https://registry.npmjs.org" -# set a token -registry = { url = "https://registry.npmjs.org", token = "123456" } -# set a username/password -registry = "https://username:password@registry.npmjs.org" -``` - -To configure a private registry scoped to a particular organization: - -```toml -[install.scopes] -# registry as string -"@myorg1" = "https://username:password@registry.myorg.com/" - -# registry with username/password -# you can reference environment variables -"@myorg2" = { username = "myusername", password = "$NPM_PASS", url = "https://registry.myorg.com/" } - -# registry with token -"@myorg3" = { token = "$npm_token", url = "https://registry.myorg.com/" } +$ bun remove preact ``` -## Linking and unlinking +## Local packages (`bun link`) Use `bun link` in a local directory to register the current package as a "linkable" package. @@ -403,44 +197,56 @@ This will add `cool-pkg` to the `dependencies` field of your app's package.json } ``` -## Utilities - -The `bun pm` command group provides a set of utilities for working with Bun's package manager. +## Git dependencies -To print the path to the `bin` directory for the local project: +To add a dependency from a git repository: ```bash -$ bun pm bin -/path/to/current/project/node_modules/.bin +$ bun install git@github.com:moment/moment.git ``` -To get the path to the global `bin` directory: +Bun supports a variety of protocols, including [`github`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#github-urls), [`git`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#git-urls-as-dependencies), `git+ssh`, `git+https`, and many more. -```bash -$ bun pm bin -<$HOME>/.bun/bin +```json +{ + "dependencies": { + "dayjs": "git+https://github.com/iamkun/dayjs.git", + "lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21", + "moment": "git@github.com:moment/moment.git", + "zod": "github:colinhacks/zod" + } +} ``` -To print a list of packages installed in the current project and their resolved versions, excluding their dependencies. Use the `--all` flag to print the entire tree, including all nth-order dependencies. +## Tarball dependencies -```bash -$ bun pm ls -/path/to/project node_modules (5) -├── eslint@8.33.0 -├── react@18.2.0 -├── react-dom@18.2.0 -├── typescript@4.8.4 -└── zod@3.20.1 -``` +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. -To print the path to Bun's global module cache: - -```bash -$ bun pm cache +```json#package.json +{ + "dependencies": { + "zod": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz" + } +} ``` -To clear Bun's global module cache: - -```bash -$ bun pm cache rm +## CI/CD + +Looking to speed up your CI? Use the official `oven-sh/setup-bun` action to install `bun` in a GitHub Actions pipeline. + +```yaml#.github/workflows/release.yml +name: bun-types +jobs: + build: + name: build-app + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Install bun + uses: oven-sh/setup-bun@v1 + - name: Install dependencies + run: bun install + - name: Build app + run: bun run build ``` diff --git a/docs/cli/run.md b/docs/cli/run.md index 133f3e1ec..7a5f8e9d2 100644 --- a/docs/cli/run.md +++ b/docs/cli/run.md @@ -1,31 +1,38 @@ The `bun` CLI can be used to execute JavaScript/TypeScript files, `package.json` scripts, and [executable packages](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#bin). -## Running a file +<!-- ## Speed --> + +<!-- +Performance sensitive APIs like `Buffer`, `fetch`, and `Response` are heavily profiled and optimized. Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. It starts and runs faster than V8, the engine used by Node.js and Chromium-based browsers. --> + +## Run a file {% callout %} Compare to `node <file>` {% /callout %} -Bun can execute `.js`, `.jsx`, `.ts`, and `.tsx` files. Every file is transpiled to vanilla JavaScript by Bun's fast native transpiler before being executed. For details on Bun's runtime, refer to the [Bun runtime](/docs/runtime) documentation. +Use `bun run` to execute a source file. -```ts#foo.ts -import { z } from "zod"; - -const schema = z.string() -const result = schema.parse("Billie Eilish"); -console.log(result); +```bash +$ bun run index.js ``` -To run a file in Bun: +Bun supports TypeScript and JSX out of the box. Every file is transpiled on the fly by Bun's fast native transpiler before being executed. ```bash -$ bun foo.ts -Billie Eilish +$ bun run index.js +$ bun run index.jsx +$ bun run index.ts +$ bun run index.tsx ``` -If no `node_modules` directory is found in the working directory or above, Bun will abandon Node.js-style module resolution in favor of the `Bun module resolution algorithm`. Under Bun-style module resolution, all packages are _auto-installed_ on the fly into a [global module cache](/docs/cli/install#global-cache). For full details on this algorithm, refer to [Runtime > Modules](/docs/runtime/modules). +The "naked" `bun` command is equivalent to `bun run`. -## Running a package script +```bash +$ bun index.tsx +``` + +## Run a `package.json` script {% note %} Compare to `npm run <script>` or `yarn <script>` @@ -80,3 +87,23 @@ quickstart scripts: ``` Bun respects lifecycle hooks. For instance, `bun run clean` will execute `preclean` and `postclean`, if defined. If the `pre<script>` fails, Bun will not execute the script itself. + +## Environment variables + +Bun automatically loads environment variables from `.env` files before running a file, script, or executable. The following files are checked, in order: + +1. `.env.local` (first) +2. `NODE_ENV` === `"production"` ? `.env.production` : `.env.development` +3. `.env` + +To debug environment variables, run `bun run env` to view a list of resolved environment variables. + +## Performance + +Bun is designed to start fast and run fast. + +Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. In most cases, the startup and running performance is faster than V8, the engine used by Node.js and Chromium-based browsers. 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. + +{% image src="/images/bun-run-speed.jpeg" caption="Bun vs Node.js vs Deno running Hello World" /%} + +<!-- If no `node_modules` directory is found in the working directory or above, Bun will abandon Node.js-style module resolution in favor of the `Bun module resolution algorithm`. Under Bun-style module resolution, all packages are _auto-installed_ on the fly into a [global module cache](/docs/cli/install#global-cache). For full details on this algorithm, refer to [Runtime > Modules](/docs/runtime/modules). --> diff --git a/docs/cli/test.md b/docs/cli/test.md index 2ac4cf208..ecae45377 100644 --- a/docs/cli/test.md +++ b/docs/cli/test.md @@ -1,10 +1,12 @@ Bun ships with a built-in test runner. +## Run tests + ```bash $ bun test ``` -Tests are written in JavaScript or TypeScript with a Jest-like API. +Tests are written in JavaScript or TypeScript with a Jest-like API. Refer to [Writing tests](/docs/test/writing) for full documentation. ```ts#math.test.ts import { expect, test } from "bun:test"; @@ -14,10 +16,6 @@ test("2 + 2", () => { }); ``` -It's fast. - -{% image src="/images/buntest.jpeg" caption="Bun runs 266 React SSR tests faster than Jest can print its version number." /%} - The runner recursively searches the working directory for files that match the following patterns: - `*.test.{js|jsx|ts|tsx}` @@ -31,208 +29,63 @@ You can filter the set of tests to run by passing additional positional argument $ bun test <filter> <filter> ... ``` -<!-- -Consider the following directory structure: +## Snapshot testing -``` -. -├── a.test.ts -├── b.test.ts -├── c.test.ts -└── foo - ├── a.test.ts - └── b.test.ts -``` +Snapshots are supported by `bun test`. First, write a test using the `.toMatchSnapshot()` matcher: -To run both `a.test.ts` files: +```ts +import { test, expect } from "bun:test"; -``` -$ bun test a +test("snap", () => { + expect("foo").toMatchSnapshot(); +}); ``` -To run all tests in the `foo` directory: +Then generate snapshots with the following command: +```bash +bun test --update-snapshots ``` -$ bun test foo -``` - -Any test file in the directory with an _absolute path_ that contains one of the targets will run. Glob patterns are not yet supported. --> -## Writing tests +Snapshots will be stored in a `__snapshots__` directory next to the test file. -Define tests with a Jest-like API imported from the built-in `bun:test` module. +## Watch mode -```ts#math.test.ts -import { expect, test } from "bun:test"; +Similar to `bun run`, you can pass the `--watch` flag to `bun test` to watch for changes and re-run tests. -test("2 + 2", () => { - expect(2 + 2).toBe(4); -}); +```bash +$ bun test --watch ``` -Group tests into suites with `describe`. - -```ts#math.test.ts -import { expect, test, describe } from "bun:test"; +## Performance -describe("arithmetic", () => { - test("2 + 2", () => { - expect(2 + 2).toBe(4); - }); - - test("2 * 2", () => { - expect(2 * 2).toBe(4); - }); -}); -``` +Bun's test runner is fast. -Tests can be `async`. +{% image src="/images/buntest.jpeg" caption="Running 266 React SSR tests faster than Jest can print its version number." /%} -```ts -import { expect, test } from "bun:test"; +<!-- +Consider the following directory structure: -test("2 * 2", async () => { - const result = await Promise.resolve(2 * 2); - expect(result).toEqual(4); -}); ``` - -Alternatively, use the `done` callback to signal completion. If you include the `done` callback as a parameter in your test definition, you _must_ call it or the test will hang. - -```ts -import { expect, test } from "bun:test"; - -test("2 * 2", done => { - Promise.resolve(2 * 2).then(result => { - expect(result).toEqual(4); - done(); - }); -}); +. +├── a.test.ts +├── b.test.ts +├── c.test.ts +└── foo + ├── a.test.ts + └── b.test.ts ``` -Perform per-test setup and teardown logic with `beforeEach` and `afterEach`. - -```ts -import { expect, test } from "bun:test"; - -beforeEach(() => { - console.log("running test."); -}); - -afterEach(() => { - console.log("done with test."); -}); +To run both `a.test.ts` files: -// tests... ``` - -Perform per-scope setup and teardown logic with `beforeAll` and `afterAll`. At the top-level, the _scope_ is the current file; in a `describe` block, the scope is the block itself. - -```ts -import { expect, test, beforeAll, afterAll } from "bun:test"; - -let db: Database; -beforeAll(() => { - // connect to database -}); - -afterAll(() => { - // close connection -}); - -// tests... +$ bun test a ``` -Skip individual tests with `test.skip`. - -```ts -import { expect, test } from "bun:test"; +To run all tests in the `foo` directory: -test.skip("wat", () => { - // TODO: fix this - expect(0.1 + 0.2).toEqual(0.3); -}); +``` +$ bun test foo ``` -## Expect matchers - -Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress [here](https://github.com/oven-sh/bun/issues/1825). - -- [x] [`.not`](https://jestjs.io/docs/expect#not) -- [x] [`.toBe()`](https://jestjs.io/docs/expect#tobevalue) -- [x] [`.toEqual()`](https://jestjs.io/docs/expect#toequalvalue) -- [x] [`.toBeNull()`](https://jestjs.io/docs/expect#tobenull) -- [x] [`.toBeUndefined()`](https://jestjs.io/docs/expect#tobeundefined) -- [x] [`.toBeNaN()`](https://jestjs.io/docs/expect#tobenan) -- [x] [`.toBeDefined()`](https://jestjs.io/docs/expect#tobedefined) -- [x] [`.toBeFalsy()`](https://jestjs.io/docs/expect#tobefalsy) -- [x] [`.toBeTruthy()`](https://jestjs.io/docs/expect#tobetruthy) -- [x] [`.toContain()`](https://jestjs.io/docs/expect#tocontainitem) -- [x] [`.toStrictEqual()`](https://jestjs.io/docs/expect#tostrictequalvalue) -- [x] [`.toThrow()`](https://jestjs.io/docs/expect#tothrowerror) -- [x] [`.toHaveLength()`](https://jestjs.io/docs/expect#tohavelengthnumber) -- [x] [`.toHaveProperty()`](https://jestjs.io/docs/expect#tohavepropertykeypath-value) -- [ ] [`.extend`](https://jestjs.io/docs/expect#expectextendmatchers) -- [ ] [`.anything()`](https://jestjs.io/docs/expect#expectanything) -- [ ] [`.any()`](https://jestjs.io/docs/expect#expectanyconstructor) -- [ ] [`.arrayContaining()`](https://jestjs.io/docs/expect#expectarraycontainingarray) -- [ ] [`.assertions()`](https://jestjs.io/docs/expect#expectassertionsnumber) -- [ ] [`.closeTo()`](https://jestjs.io/docs/expect#expectclosetonumber-numdigits) -- [ ] [`.hasAssertions()`](https://jestjs.io/docs/expect#expecthasassertions) -- [ ] [`.objectContaining()`](https://jestjs.io/docs/expect#expectobjectcontainingobject) -- [ ] [`.stringContaining()`](https://jestjs.io/docs/expect#expectstringcontainingstring) -- [ ] [`.stringMatching()`](https://jestjs.io/docs/expect#expectstringmatchingstring--regexp) -- [ ] [`.addSnapshotSerializer()`](https://jestjs.io/docs/expect#expectaddsnapshotserializerserializer) -- [ ] [`.resolves()`](https://jestjs.io/docs/expect#resolves) -- [ ] [`.rejects()`](https://jestjs.io/docs/expect#rejects) -- [ ] [`.toHaveBeenCalled()`](https://jestjs.io/docs/expect#tohavebeencalled) -- [ ] [`.toHaveBeenCalledTimes()`](https://jestjs.io/docs/expect#tohavebeencalledtimesnumber) -- [ ] [`.toHaveBeenCalledWith()`](https://jestjs.io/docs/expect#tohavebeencalledwitharg1-arg2-) -- [ ] [`.toHaveBeenLastCalledWith()`](https://jestjs.io/docs/expect#tohavebeenlastcalledwitharg1-arg2-) -- [ ] [`.toHaveBeenNthCalledWith()`](https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-) -- [ ] [`.toHaveReturned()`](https://jestjs.io/docs/expect#tohavereturned) -- [ ] [`.toHaveReturnedTimes()`](https://jestjs.io/docs/expect#tohavereturnedtimesnumber) -- [ ] [`.toHaveReturnedWith()`](https://jestjs.io/docs/expect#tohavereturnedwithvalue) -- [ ] [`.toHaveLastReturnedWith()`](https://jestjs.io/docs/expect#tohavelastreturnedwithvalue) -- [ ] [`.toHaveNthReturnedWith()`](https://jestjs.io/docs/expect#tohaventhreturnedwithnthcall-value) -- [ ] [`.toBeCloseTo()`](https://jestjs.io/docs/expect#tobeclosetonumber-numdigits) -- [x] [`.toBeGreaterThan()`](https://jestjs.io/docs/expect#tobegreaterthannumber--bigint) -- [x] [`.toBeGreaterThanOrEqual()`](https://jestjs.io/docs/expect#tobegreaterthanorequalnumber--bigint) -- [x] [`.toBeLessThan()`](https://jestjs.io/docs/expect#tobelessthannumber--bigint) -- [x] [`.toBeLessThanOrEqual()`](https://jestjs.io/docs/expect#tobelessthanorequalnumber--bigint) -- [x] [`.toBeInstanceOf()`](https://jestjs.io/docs/expect#tobeinstanceofclass) (Bun v0.5.8+) -- [ ] [`.toContainEqual()`](https://jestjs.io/docs/expect#tocontainequalitem) -- [ ] [`.toMatch()`](https://jestjs.io/docs/expect#tomatchregexp--string) -- [ ] [`.toMatchObject()`](https://jestjs.io/docs/expect#tomatchobjectobject) -- [x] [`.toMatchSnapshot()`](https://jestjs.io/docs/expect#tomatchsnapshotpropertymatchers-hint) (Bun v0.5.8+) -- [ ] [`.toMatchInlineSnapshot()`](https://jestjs.io/docs/expect#tomatchinlinesnapshotpropertymatchers-inlinesnapshot) -- [ ] [`.toThrowErrorMatchingSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchingsnapshothint) -- [ ] [`.toThrowErrorMatchingInlineSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchinginlinesnapshotinlinesnapshot) - -<!-- ```ts -test('matchers', ()=>{ - - expect(5).toBe(5); - expect("do re mi").toContain("mi"); - expect("do re mi").toEqual("do re mi"); - expect({}).toStrictEqual({}); // uses Bun.deepEquals() - expect([1,2,3]).toHaveLength(3); - expect({ name: "foo" }).toHaveProperty("name"); - expect({ name: "foo" }).toHaveProperty("name", "foo"); - expect(5).toBeTruthy(); - expect(0).toBeFalsy(); - expect("").toBeDefined(); - expect(undefined).toBeUndefined(); - expect(parseInt('tuna')).toBeNaN(); - expect(null).toBeNull(); - expect(5).toBeGreaterThan(4); - expect(5).toBeGreaterThanOrEqual(5); - expect(5).toBeLessThan(6); - expect(5).toBeLessThanOrEqual(5); - expect(()=>throw new Error()).toThrow(); - - // negation - expect(5).not.toBe(4) - -}) -``` --> +Any test file in the directory with an _absolute path_ that contains one of the targets will run. Glob patterns are not yet supported. --> diff --git a/docs/ecosystem/express.md b/docs/ecosystem/express.md index 856d2aafc..bbca048ab 100644 --- a/docs/ecosystem/express.md +++ b/docs/ecosystem/express.md @@ -1,7 +1,7 @@ -Projects that use Express and other major Node.js HTTP libraries should work out of the box. +Projects that use Express and other major Node.js HTTP libraries should work out of the box. {% callout %} -If you run into bugs, [please file an issue](https://bun.sh/issues) *in Bun's repo*, not the library. It is Bun's responsibility to address Node.js compatibility issues. +If you run into bugs, [please file an issue](https://bun.sh/issues) _in Bun's repo_, not the library. It is Bun's responsibility to address Node.js compatibility issues. {% /callout %} ```ts @@ -22,7 +22,7 @@ app.listen(port, () => { Bun implements the [`node:http`](https://nodejs.org/api/http.html) and [`node:https`](https://nodejs.org/api/https.html) modules that these libraries rely on. These modules can also be used directly, though [`Bun.serve`](/docs/api/http) is recommended for most use cases. {% callout %} -**Note** — Refer to the [Runtime > Node.js APIs](/docs/ecosystem/nodejs#node_http) page for more detailed compatibility information. +**Note** — Refer to the [Runtime > Node.js APIs](/docs/runtime/nodejs-apis#node_http) page for more detailed compatibility information. {% /callout %} ```ts diff --git a/docs/ecosystem/react.md b/docs/ecosystem/react.md index 197edb30f..84f1a4536 100644 --- a/docs/ecosystem/react.md +++ b/docs/ecosystem/react.md @@ -19,23 +19,23 @@ $ bun run react.tsx <Component message="Hello world!" /> ``` -### Prop punning +### Prop punning -The Bun runtime also supports "prop punning for JSX. This is a shorthand syntax useful for assigning a variable to a prop with the same name. +The Bun runtime also supports "prop punning" for JSX. This is a shorthand syntax useful for assigning a variable to a prop with the same name. ```tsx function Div(props: {className: string;}) { const {className} = props; - + // without punning return <div className={className} />; // with punning return <div {className} />; - } ``` ### Server-side rendering + To server-side render (SSR) React in an [HTTP server](/docs/api/http): ```tsx#ssr.tsx diff --git a/docs/index.md b/docs/index.md index 433cf577c..6fb692fb9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -19,7 +19,7 @@ $ bunx cowsay "Hello, world!" # execute a package **Bun is still under development.** Use it to speed up your development workflows or run simpler production code in resource-constrained environments like serverless functions. We're working on more complete Node.js compatibility and integration with existing frameworks. Join the [Discord](https://bun.sh/discord) and watch the [GitHub repository](https://github.com/oven-sh/bun) to keep tabs on future releases. {% /callout %} -### Get started +Get started with one of the quick links below, or read on to learn more about Bun. {% block className="gap-2 grid grid-flow-row grid-cols-1 md:grid-cols-2" %} {% arrowbutton href="/docs/installation" text="Install Bun" /%} diff --git a/docs/install/cache.md b/docs/install/cache.md new file mode 100644 index 000000000..6bd13d04a --- /dev/null +++ b/docs/install/cache.md @@ -0,0 +1,59 @@ +All packages downloaded from the registry are stored in a global cache at `~/.bun/install/cache`. They are stored in subdirectories named like `${name}@${version}`, so multiple versions of a package can be cached. + +{% details summary="Configuring cache behavior" %} + +```toml +[install.cache] +# the directory to use for the cache +dir = "~/.bun/install/cache" + +# when true, don't load from the global cache. +# Bun may still write to node_modules/.cache +disable = false + +# when true, always resolve the latest versions from the registry +disableManifest = false +``` + +{% /details %} + +## Minimizing re-downloads + +Bun strives to avoid re-downloading packages mutiple times. When installing a package, if the cache already contains a version in the range specified by `package.json`, Bun will use the cached package instead of downloading it again. + +{% details summary="Installation details" %} +If the semver version has pre-release suffix (`1.0.0-beta.0`) or a build suffix (`1.0.0+20220101`), it is replaced with a hash of that value instead, to reduce the chances of errors associated with long file paths. + +When the `node_modules` folder exists, before installing, Bun checks that `node_modules` contains all expected packages with appropriate versions. If so `bun install` completes. Bun uses a custom JSON parser which stops parsing as soon as it finds `"name"` and `"version"`. + +If a package is missing or has a version incompatible with the `package.json`, Bun checks for a compatible module in the cache. If found, it is installed into `node_modules`. Otherwise, the package will be downloaded from the registry then installed. +{% /details %} + +## Fast copying + +Once a package is downloaded into the cache, Bun still needs to copy those files into `node_modules`. Bun uses the fastest syscalls available to perform this task. On Linux, it uses hardlinks; on macOS, it uses `clonefile`. + +## Saving disk space + +Since Bun uses hardlinks to "copy" a module into a project's `node_modules` directory on Linux, the contents of the package only exist in a single location on disk, greatly reducing the amount of disk space dedicated to `node_modules`. + +This benefit does not extend to macOS, which uses `clonefile` for performance reasons. + +{% details summary="Installation strategies" %} +This behavior is configurable with the `--backend` flag, which is respected by all of Bun's package management commands. + +- **`hardlink`**: Default on Linux. +- **`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. + +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). + +```bash +$ bun install --backend symlink +$ node --preserve-symlinks ./foo.js +``` + +Bun's runtime does not currently expose an equivalent of `--preserve-symlinks`. +{% /details %} diff --git a/docs/install/index.md b/docs/install/index.md new file mode 100644 index 000000000..48e001275 --- /dev/null +++ b/docs/install/index.md @@ -0,0 +1,190 @@ +The `bun` CLI contains an `npm`-compatible package manager designed to be a faster replacement for existing package management tools like `npm`, `yarn`, and `pnpm`. It's designed for Node.js compatibility; use it in any Bun or Node.js project. + +{% callout %} + +**⚡️ 80x faster** — Switch from `npm install` to `bun install` in any Node.js project to make your installations up to 80x faster. + +{% image src="https://user-images.githubusercontent.com/709451/147004342-571b6123-17a9-49a2-8bfd-dcfc5204047e.png" height="200" /%} + +{% /callout %} + +{% details summary="For Linux users" %} +The minimum Linux Kernel version is 5.1. If you're on Linux kernel 5.1 - 5.5, `bun install` should still work, but HTTP requests will be slow due to a lack of support for io_uring's `connect()` operation. + +If you're using Ubuntu 20.04, here's how to install a [newer kernel](https://wiki.ubuntu.com/Kernel/LTSEnablementStack): + +```bash +# If this returns a version >= 5.6, you don't need to do anything +uname -r + +# Install the official Ubuntu hardware enablement kernel +sudo apt install --install-recommends linux-generic-hwe-20.04 +``` + +{% /details %} + +## Manage dependencies + +### `bun install` + +To install all dependencies of a project: + +```bash +$ bun install +``` + +On Linux, `bun install` tends to install packages 20-100x faster than `npm install`. On macOS, it's more like 4-80x. + + + +Running `bun install` will: + +- **Install** all `dependencies`, `devDependencies`, and `optionalDependencies`. Bun does not install `peerDependencies` by default. +- **Run** your project's `{pre|post}install` scripts at the appropriate time. For security reasons Bun _does not execute_ lifecycle scripts of installed dependencies. +- **Write** a `bun.lockb` lockfile to the project root. + +To install in production mode (i.e. without `devDependencies`): + +```bash +$ bun install --production +``` + +To perform a dry run (i.e. don't actually install anything): + +```bash +$ bun install --dry-run +``` + +To modify logging verbosity: + +```bash +$ bun install --verbose # debug logging +$ bun install --silent # no logging +``` + +{% details summary="Configuring behavior" %} +The default behavior of `bun install` can be configured in `bun.toml`: + +```toml +[install] + +# whether to install optionalDependencies +optional = true + +# whether to install devDependencies +dev = true + +# whether to install peerDependencies +peer = false + +# equivalent to `--production` flag +production = false + +# equivalent to `--dry-run` flag +dryRun = false +``` + +{% /details %} + +### `bun add` + +To add a particular package: + +```bash +$ bun add preact +``` + +To specify a version, version range, or tag: + +```bash +$ bun add zod@3.20.0 +$ bun add zod@^3.0.0 +$ bun add zod@latest +``` + +To add a package as a dev dependency (`"devDependencies"`): + +```bash +$ bun add --development @types/react +$ bun add -d @types/react +``` + +To add a package as an optional dependency (`"optionalDependencies"`): + +```bash +$ bun add --optional lodash +``` + +To install a package globally: + +```bash +$ bun add --global cowsay # or `bun add -g cowsay` +$ cowsay "Bun!" + ______ +< Bun! > + ------ + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || +``` + +{% details summary="Configuring global installation behavior" %} + +```toml +[install] +# where `bun install --global` installs packages +globalDir = "~/.bun/install/global" + +# where globally-installed package bins are linked +globalBinDir = "~/.bun/bin" +``` + +{% /details %} +To view a complete list of options for a given command: + +```bash +$ bun add --help +``` + +### `bun remove` + +To remove a dependency: + +```bash +$ bun remove preact +``` + +## Git dependencies + +To add a dependency from a git repository: + +```bash +$ bun install git@github.com:moment/moment.git +``` + +Bun supports a variety of protocols, including [`github`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#github-urls), [`git`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#git-urls-as-dependencies), `git+ssh`, `git+https`, and many more. + +```json +{ + "dependencies": { + "dayjs": "git+https://github.com/iamkun/dayjs.git", + "lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21", + "moment": "git@github.com:moment/moment.git", + "zod": "github:colinhacks/zod" + } +} +``` + +## 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. + +```json#package.json +{ + "dependencies": { + "zod": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz" + } +} +``` diff --git a/docs/install/lockfile.md b/docs/install/lockfile.md new file mode 100644 index 000000000..4ae9025ff --- /dev/null +++ b/docs/install/lockfile.md @@ -0,0 +1,67 @@ +Running `bun install` will create a binary lockfile called `bun.lockb`. + +#### Why is it binary? + +In a word: Performance. Bun’s lockfile saves & loads incredibly quickly, and saves a lot more data than what is typically inside lockfiles. + +#### How do I inspect it? + +Run `bun install -y` to generate a Yarn-compatible `yarn.lock` (v1) that can be inspected more easily. + +#### Platform-specific dependencies? + +Bun stores normalized `cpu` and `os` values from npm in the lockfile, along with the resolved packages. It skips downloading, extracting, and installing packages disabled for the current target at runtime. This means the lockfile won’t change between platforms/architectures even if the packages ultimately installed do change. + +#### What does the lockfile store? + +Packages, metadata for those packages, the hoisted install order, dependencies for each package, what packages those dependencies resolved to, an integrity hash (if available), what each package was resolved to, and which version (or equivalent). + +#### Why is it fast? + +It uses linear arrays for all data. [Packages](https://github.com/oven-sh/bun/blob/be03fc273a487ac402f19ad897778d74b6d72963/src/install/install.zig#L1825) are referenced by an auto-incrementing integer ID or a hash of the package name. Strings longer than 8 characters are de-duplicated. Prior to saving on disk, the lockfile is garbage-collected & made deterministic by walking the package tree and cloning the packages in dependency order. + +#### Can I opt out? + +To install without creating a lockfile: + +```bash +$ bun install --no-save +``` + +To install a Yarn lockfile _in addition_ to `bun.lockb`. + +{% codetabs %} + +```bash#CLI flag +$ bun install --yarn +``` + +```toml#bunfig.toml +[install.lockfile] +# whether to save a non-Bun lockfile alongside bun.lockb +# only "yarn" is supported +print = "yarn" +``` + +{% /codetabs %} + +{% details summary="Configuring lockfile" %} + +```toml +[install.lockfile] + +# path to read bun.lockb from +path = "bun.lockb" + +# path to save bun.lockb to +savePath = "bun.lockb" + +# whether to save the lockfile to disk +save = true + +# whether to save a non-Bun lockfile alongside bun.lockb +# only "yarn" is supported +print = "yarn" +``` + +{% /details %} diff --git a/docs/install/registries.md b/docs/install/registries.md new file mode 100644 index 000000000..e4090e3c9 --- /dev/null +++ b/docs/install/registries.md @@ -0,0 +1,26 @@ +The default registry is `registry.npmjs.org`. This can be globally configured in `bunfig.toml`: + +```toml +[install] +# set default registry as a string +registry = "https://registry.npmjs.org" +# set a token +registry = { url = "https://registry.npmjs.org", token = "123456" } +# set a username/password +registry = "https://username:password@registry.npmjs.org" +``` + +To configure a private registry scoped to a particular organization: + +```toml +[install.scopes] +# registry as string +"@myorg1" = "https://username:password@registry.myorg.com/" + +# registry with username/password +# you can reference environment variables +"@myorg2" = { username = "myusername", password = "$NPM_PASS", url = "https://registry.myorg.com/" } + +# registry with token +"@myorg3" = { token = "$npm_token", url = "https://registry.myorg.com/" } +``` diff --git a/docs/install/utilities.md b/docs/install/utilities.md new file mode 100644 index 000000000..689f177d8 --- /dev/null +++ b/docs/install/utilities.md @@ -0,0 +1,58 @@ +The `bun pm` command group provides a set of utilities for working with Bun's package manager. + +To print the path to the `bin` directory for the local project: + +```bash +$ bun pm bin +/path/to/current/project/node_modules/.bin +``` + +To print the path to the global `bin` directory: + +```bash +$ bun pm bin -g +<$HOME>/.bun/bin +``` + +To print a list of installed dependencies in the current project and their resolved versions, excluding their dependencies. + +```bash +$ bun pm ls +/path/to/project node_modules (135) +├── eslint@8.38.0 +├── react@18.2.0 +├── react-dom@18.2.0 +├── typescript@5.0.4 +└── zod@3.21.4 +``` + +To print all installed dependencies, including nth-order dependencies. + +```bash +$ bun pm ls --all +/path/to/project node_modules (135) +├── @eslint-community/eslint-utils@4.4.0 +├── @eslint-community/regexpp@4.5.0 +├── @eslint/eslintrc@2.0.2 +├── @eslint/js@8.38.0 +├── @nodelib/fs.scandir@2.1.5 +├── @nodelib/fs.stat@2.0.5 +├── @nodelib/fs.walk@1.2.8 +├── acorn@8.8.2 +├── acorn-jsx@5.3.2 +├── ajv@6.12.6 +├── ansi-regex@5.0.1 +├── ... +``` + +To print the path to Bun's global module cache: + +```bash +$ bun pm cache +``` + +To clear Bun's global module cache: + +```bash +$ bun pm cache rm +``` diff --git a/docs/install/workspaces.md b/docs/install/workspaces.md new file mode 100644 index 000000000..cf5a20e19 --- /dev/null +++ b/docs/install/workspaces.md @@ -0,0 +1,30 @@ +Bun supports [`workspaces`](https://docs.npmjs.com/cli/v9/using-npm/workspaces?v=true#description) in `package.json`. Workspaces make it easy to develop complex software as a _monorepo_ consisting of several independent packages. + +To try it, specify a list of sub-packages in the `workspaces` field of your `package.json`; it's conventional to place these sub-packages in a directory called `packages`. + +```json +{ + "name": "my-project", + "version": "1.0.0", + "workspaces": ["packages/*"] +} +``` + +{% 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!). +{% /callout %} + +This has a couple major benefits. + +- **Code can be split into logical parts.** If one package relies on another, you can simply add it as a dependency with `bun add`. If package `b` depends on `a`, `bun install` will symlink your local `packages/a` directory into the `node_modules` folder of `b`, instead of trying to download it from the npm registry. +- **Dependencies can be de-duplicated.** If `a` and `b` share a common dependency, it will be _hoisted_ to the root `node_modules` directory. This reduces redundant disk usage and minimizes "dependency hell" issues associated with having multiple versions of a package installed simultaneously. + +{% callout %} +⚡️ **Speed** — Installs are fast, even for big monorepos. Bun installs the [Remix](https://github.com/remix-run/remix) monorepo in about `500ms` on Linux. + +- 28x faster than `npm install` +- 12x faster than `yarn install` (v1) +- 8x faster than `pnpm install` + +{% image src="https://user-images.githubusercontent.com/709451/212829600-77df9544-7c9f-4d8d-a984-b2cd0fd2aa52.png" /%} +{% /callout %} diff --git a/docs/installation.md b/docs/installation.md index f6b983411..06ca2b34d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -125,7 +125,7 @@ Then include `"bun-types"` in the `compilerOptions.types` in your `tsconfig.json } ``` -Refer to [Ecosystem > TypeScript](/docs/ecosystem/typescript) for a complete guide to TypeScript support in Bun. +Refer to [Ecosystem > TypeScript](/docs/runtime/typescript) for a complete guide to TypeScript support in Bun. ## Completions diff --git a/docs/nav.ts b/docs/nav.ts index adf99bc6d..a693a04ef 100644 --- a/docs/nav.ts +++ b/docs/nav.ts @@ -33,32 +33,35 @@ export default { description: "Install Bun with npm, Homebrew, Docker, or the official install script.", }), page("quickstart", "Quickstart", { - description: "Get started with Bun by building and running a simple HTTP server in 5 lines of TypeScript.", + description: "Get started with Bun by building and running a simple HTTP server in 6 lines of TypeScript.", + }), + page("templates", "Templates", { + description: "Hit the ground running with one of Bun's official templates, or download a template from GitHub.", }), // page("typescript", "TypeScript"), - divider("CLI"), - page("cli/run", "`bun run`", { - description: - "Use `bun run` to execute JavaScript/TypeScript files, package.json scripts, and executable packages.", - }), - page("cli/install", "`bun install`", { - description: "A 100x faster npm client with workspaces, git dependencies, and private registry support.", - }), - page("cli/test", "`bun test`", { - description: "Bun's test runner uses Jest-compatible syntax but runs 100x faster.", - }), - page("cli/create", "`bun create`", { - description: "Scaffold a new Bun project from an official template or GitHub repo.", - }), - page("cli/bunx", "`bunx`", { - description: - "Use `bunx` to auto-install and run executable packages from npm, or use locally installed command-line tools.", - }), - page("cli/deploy", "`bun deploy`", { - disabled: true, - description: "Deploy your Bun app to the cloud (eventually)", - }), + // divider("CLI"), + // page("cli/run", "`bun run`", { + // description: + // "Use `bun run` to execute JavaScript/TypeScript files, package.json scripts, and executable packages.", + // }), + // page("cli/install", "`bun install`", { + // description: "A 100x faster npm client with workspaces, git dependencies, and private registry support.", + // }), + // page("cli/test", "`bun test`", { + // description: "Bun's test runner uses Jest-compatible syntax but runs 100x faster.", + // }), + // page("cli/create", "`bun create`", { + // description: "Scaffold a new Bun project from an official template or GitHub repo.", + // }), + // page("cli/bunx", "`bunx`", { + // description: + // "Use `bunx` to auto-install and run executable packages from npm, or use locally installed command-line tools.", + // }), + // page("cli/deploy", "`bun deploy`", { + // disabled: true, + // description: "Deploy your Bun app to the cloud (eventually)", + // }), // page("bundler", "Bundler"), // page("cli/bun-install", "`bun install`"), @@ -70,37 +73,113 @@ export default { // page("bundev", "Dev server"), // page("benchmarks", "Benchmarks"), + // divider("Runtime"), divider("Runtime"), - page("runtime/index", "Runtime", { - description: `Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js.`, + page("cli/run", "`bun run`", { + description: "Use `bun run` to execute JavaScript/TypeScript files and package.json scripts.", + }), + // page("runtime/index", "Overview", { + // description: `Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js.`, + // }), + // page("runtime/performance", "Performance", { + // description: `Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js.`, + // }), + page("runtime/loaders", "File types", { + description: `Bun's runtime supports JavaScript/TypeScript files, JSX syntax, Wasm, JSON/TOML imports, and more.`, }), + page("runtime/typescript", "TypeScript", { + description: `Bun can directly execute TypeScript files without additional configuration.`, + }), + // page("runtime/jsx", "JSX", { + // description: `Bun can directly execute TypeScript files without additional configuration.`, + // }), + // page("runtime/apis", "APIs", { + // description: `Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js.`, + // }), + page("runtime/bun-apis", "Bun APIs", { + description: `Bun provides a set of highly optimized native APIs for performing common tasks.`, + }), + page("runtime/web-apis", "Web APIs", { + description: `Bun implements an array of Web-standard APIs like fetch, URL, and WebSocket.`, + }), + + page("runtime/nodejs-apis", "Node.js compatibility", { + description: `Bun aims for full Node.js compatibility. This page tracks the current compatibility status.`, + }), + + // page("runtime/nodejs", "Node.js compatibility", { + // description: `Track the status of Bun's API compatibility with Node.js.`, + // }), // page("runtime/web-apis", "Web APIs"), + // page("runtime/loaders", "Loaders"), + + page("runtime/hot", "Watch mode", { + description: `Reload your application & tests automatically.`, + }), page("runtime/modules", "Module resolution", { description: `Bun uses ESM and implements an extended version of the Node.js module resolution algorithm.`, }), - page("runtime/hot", "Watch mode", { - description: `Reload your application & tests automatically.`, + page("runtime/autoimport", "Auto-install", { + description: `Never use node_modules again. Bun can optionally auto-install your dependencies on the fly.`, + }), + page("runtime/configuration", "Configuration", { + description: `Bun's runtime is configurable with environment variables and the bunfig.toml config file.`, }), - // page("runtime/loaders", "Loaders"), page("runtime/plugins", "Plugins", { description: `Implement custom loaders and module resolution logic with Bun's plugin system.`, }), + page("runtime/framework", "Framework API", { disabled: true, description: "Coming soon. Use the Framework API to build a fast, cloud-ready framework on top of Bun's bundler and runtime.", }), - // page("runtime/nodejs", "Node.js APIs"), - divider("Ecosystem"), - page("ecosystem/nodejs", "Node.js", { - description: `Track the status of Bun's API compatibility with Node.js.`, + divider("Package manager"), + page("cli/install", "`bun install`", { + description: + "Install all dependencies with `bun install`, or manage dependencies with `bun add` and `bun remove`.", }), - page("ecosystem/typescript", "TypeScript", { - description: `Bun can directly execute TypeScript files without additional configuration.`, + page("install/workspaces", "Workspaces", { + description: "Bun's package manager supports workspaces and mono-repo development workflows.", + }), + page("install/cache", "Global cache", { + description: + "Bun's package manager installs all packages into a shared global cache to avoid redundant re-downloads.", + }), + page("install/lockfile", "Lockfile", { + description: + "Bun's binary lockfile `bun.lockb` tracks your resolved dependency ytrr, making future installs fast and repeatable.", + }), + page("install/registries", "Scopes and registries", { + description: "How to configure private scopes and custom package registries.", + }), + page("install/utilities", "Utilities", { + description: "Use `bun pm` to introspect your global module cache or project dependency tree.", + }), + + divider("Test runner"), + page("cli/test", "`bun test`", { + description: "Bun's test runner uses Jest-compatible syntax but runs 100x faster.", + }), + page("test/writing", "Writing tests", { + description: + "Write your tests using Jest-like expect matchers, plus setup/teardown hooks, snapshot testing, and more", }), - page("ecosystem/react", "React", { - description: `The Bun runtime supports JSX syntax out of the box and optimizes server-side rendering.`, + + divider("Package runner"), + page("cli/bunx", "`bunx`", { + description: "Use `bunx` to auto-install and run executable packages from npm.", + }), + + // page("runtime/nodejs", "Node.js APIs"), + + divider("Ecosystem"), + // page("ecosystem/react", "React", { + // description: `The Bun runtime supports JSX syntax out of the box and optimizes server-side rendering.`, + // }), + page("ecosystem/express", "Express", { + description: `Servers built with Express and other major Node.js HTTP libraries work out of the box.`, }), page("ecosystem/elysia", "Elysia", { description: `Get started with Elysia, a Bun-native framework designed for the edge.`, @@ -111,9 +190,7 @@ export default { page("ecosystem/buchta", "Buchta", { description: `Buchta is a Bun-native fullstack framework for Svelte and Preact apps.`, }), - page("ecosystem/express", "Express", { - description: `Servers built with Express and other major Node.js HTTP libraries work out of the box.`, - }), + page("ecosystem/awesome", "Awesome", { href: "https://github.com/apvarun/awesome-bun", description: ``, @@ -180,9 +257,7 @@ export default { page("project/roadmap", "Roadmap", { description: `Track Bun's near-term and long-term goals.`, }), - page("project/configuration", "Configuration", { - description: `Bun's runtime is configurable with environment variables and the bunfig.toml config file.`, - }), + page("project/benchmarking", "Benchmarking", { description: `Bun is designed for performance. Learn how to benchmark Bun yourself.`, }), diff --git a/docs/project/benchmarking.md b/docs/project/benchmarking.md index b9672f325..96b06b640 100644 --- a/docs/project/benchmarking.md +++ b/docs/project/benchmarking.md @@ -12,17 +12,18 @@ To precisely measure time, Bun offers two runtime APIs functions: When writing your own benchmarks, it's important to choose the right tool. - For microbenchmarks, a great general-purpose tool is [`mitata`](https://github.com/evanwashere/mitata). -- For load testing, you *must use* an HTTP benchmarking tool that is at least as fast as `Bun.serve()`, or your results will be skewed. Some popular Node.js-based benchmarking tools like [`autocannon`](https://github.com/mcollina/autocannon) are not fast enough. We recommend one of the following: +- For load testing, you _must use_ an HTTP benchmarking tool that is at least as fast as `Bun.serve()`, or your results will be skewed. Some popular Node.js-based benchmarking tools like [`autocannon`](https://github.com/mcollina/autocannon) are not fast enough. We recommend one of the following: - [`bombardier`](https://github.com/codesenberg/bombardier) - [`oha`](https://github.com/hatoo/oha) - [`http_load_test`](https://github.com/uNetworking/uSockets/blob/master/examples/http_load_test.c) -- For benchmarking scripts or CLI commands, we recommend [`hyperfine`](https://github.com/sharkdp/hyperfine). It's an easy way to compare - +- For benchmarking scripts or CLI commands, we recommend [`hyperfine`](https://github.com/sharkdp/hyperfine). ## Measuring memory usage Bun has two heaps. One heap is for the JavaScript runtime and the other heap is for everything else. +{% anchor id="bunjsc" /%} + ### JavaScript heap stats The `bun:jsc` module exposes a few functions for measuring memory usage: @@ -31,7 +32,9 @@ The `bun:jsc` module exposes a few functions for measuring memory usage: import { heapStats } from "bun:jsc"; console.log(heapStats()); ``` + {% details summary="View example statistics" %} + ```ts { heapSize: 1657575, @@ -134,6 +137,7 @@ console.log(heapStats()); } } ``` + {% /details %} JavaScript is a garbage-collected language, not reference counted. It's normal and correct for objects to not be freed immediately in all cases, though it's not normal for objects to never be freed. @@ -141,7 +145,7 @@ JavaScript is a garbage-collected language, not reference counted. It's normal a Tp force garbage collection to run manually: ```js -Bun.gc(true); // synchronous +Bun.gc(true); // synchronous Bun.gc(false); // asynchronous ``` @@ -161,15 +165,12 @@ To view the snapshot, open the `heap.json` file in Safari's Developer Tools (or 3. Click "JavaScript Allocations" in the menu on the left. It might not be visible until you click the pencil icon to show all the timelines 4. Click "Import" and select your heap snapshot JSON - {% image alt="Import heap json" src="https://user-images.githubusercontent.com/709451/204428943-ba999e8f-8984-4f23-97cb-b4e3e280363e.png" caption="Importing a heap snapshot" /%} Once imported, you should see something like this: - {% image alt="Viewing heap snapshot in Safari" src="https://user-images.githubusercontent.com/709451/204429337-b0d8935f-3509-4071-b991-217794d1fb27.png" caption="Viewing heap snapshot in Safari Dev Tools" /%} - ### Native heap stats Bun uses mimalloc for the other heap. To report a summary of non-JavaScript memory usage, set the `MIMALLOC_SHOW_STATS=1` environment variable. and stats will print on exit. diff --git a/docs/runtime/autoimport.md b/docs/runtime/autoimport.md new file mode 100644 index 000000000..70af18e1f --- /dev/null +++ b/docs/runtime/autoimport.md @@ -0,0 +1,98 @@ +{% 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/cli/install#global-cache) during execution (the same cache used by [`bun install`](/docs/cli/install)). + +```ts +import { foo } from "foo"; // install `latest` version + +foo(); +``` + +The first time you run this script, Bun will auto-install `"foo"` and cache it. The next time you run the script, it will use the cached version. + +## Version resolution + +To determine which version to install, Bun follows the following algorithm: + +1. Check for a `bun.lockb` file in the project root. If it exists, use the version specified in the lockfile. +2. Otherwise, scan up the tree for a `package.json` that includes `"foo"` as a dependency. If found, use the specified semver version or version range. +3. Otherwise, use `latest`. + +## Cache behavior + +Once a version or version range has been determined, Bun will: + +1. Check the module cache for a compatible version. If one exists, use it. +2. When resolving `latest`, Bun will check if `package@latest` has been downloaded and cached in the last _24 hours_. If so, use it. +3. Otherwise, download and install the appropriate version from the `npm` registry. + +## Installation + +Packages are installed and cached into `<cache>/<pkg>@<version>`, so multiple versions of the same package can be cached at once. Additionally, a symlink is created under `<cache>/<pkg>/<version>` to make it faster to look up all versions of a package that exist in the cache. + +## Version specifiers + +This entire resolution algorithm can be short-circuited by specifying a version or version range directly in your import statement. + +```ts +import { z } from "zod@3.0.0"; // specific version +import { z } from "zod@next"; // npm tag +import { z } from "zod@^3.20.0"; // semver range +``` + +## Benefits + +This auto-installation approach is useful for a few reasons: + +- **Space efficiency** — Each version of a dependency only exists in one place on disk. This is a huge space and time savings compared to redundant per-project installations. +- **Portability** — To share simple scripts and gists, your source file is _self-contained_. No need to `zip` together a directory containing your code and config files. With version specifiers in `import` statements, even a `package.json` isn't necessary. +- **Convenience** — There's no need to run `npm install` or `bun install` before running a file or script. Just `bun run` it. +- **Backwards compatibility** — Because Bun still respects the versions specified in `package.json` if one exists, you can switch to Bun-style resolution with a single command: `rm -rf node_modules`. + +## Limitations + +- No Intellisense. TypeScript auto-completion in IDEs relies on the existence of type declaration files inside `node_modules`. We are investigating various solutions to this. +- No [patch-package](https://github.com/ds300/patch-package) support + +<!-- - The implementation details of Bun's install cache will change between versions. Don't think of it as an API. To reliably resolve packages, use Bun's builtin APIs (such as `Bun.resolveSync` or `import.meta.resolve`) instead of relying on the filesystem directly. Bun will likely move to a binary archive format where packages may not correspond to files/folders on disk at all - so if you depend on the filesystem structure instead of the JavaScript API, your code will eventually break. --> + +<!-- ## Customizing behavior + +To prefer locally-installed versions of packages. Instead of checking npm for latest versions, you can pass the `--prefer-offline` flag to prefer locally-installed versions of packages. + +```bash +$ bun run --prefer-offline my-script.ts +``` + +This will check the install cache for installed versions of packages before checking the npm registry. If no matching version of a package is installed, only then will it check npm for the latest version. + +#### Prefer latest + +To always use the latest version of a package, you can pass the `--prefer-latest` flag. + +```bash +$ bun run --prefer-latest my-script.ts +``` --> + +## FAQ + +{% details summary="How is this different from what pnpm does?" %} + +With pnpm, you have to run `pnpm install`, which creates a `node_modules` folder of symlinks for the runtime to resolve. By contrast, Bun resolves dependencies on the fly when you run a file; there's no need to run any `install` command ahead of time. Bun also doesn't create a `node_modules` folder. + +{% /details %} + +{% details summary="How is this different from Yarn Plug'N'Play does?" %} +With Yarn, you must run `yarn install` before you run a script. By contrast, Bun resolves dependencies on the fly when you run a file; there's no need to run any `install` command ahead of time. + +Yarn Plug'N'Play also uses zip files to store dependencies. This makes dependency loading [slower at runtime](https://twitter.com/jarredsumner/status/1458207919636287490), as random access reads on zip files tend to be slower than the equivalent disk lookup. +{% /details %} + +{% details summary="How is this different from what Deno does?" %} + +Deno requires an `npm:` specifier before each npm `import`, lacks support for import maps via `compilerOptions.paths` in `tsconfig.json`, and has incomplete support for `package.json` settings. Unlike Deno, Bun does not currently support URL imports. +{% /details %} diff --git a/docs/runtime/bun-apis.md b/docs/runtime/bun-apis.md new file mode 100644 index 000000000..90f1d2b41 --- /dev/null +++ b/docs/runtime/bun-apis.md @@ -0,0 +1,75 @@ +Bun implements a set of native APIs on the `Bun` global object and through a number of built-in modules. These APIs represent the canonical "Bun-native" way to perform some common development tasks. They are all heavily optimized for performance. Click the link in the left column to view the associated documentation. + +{% table %} + +- Topic +- APIs + +--- + +- [HTTP](/docs/api/http) +- `Bun.serve` + +--- + +- [File I/O](/docs/api/file-io) +- `Bun.file` `Bun.write` + +--- + +- [Processes](/docs/api/spawn) +- `Bun.spawn` `Bun.spawnSync` + +--- + +- [TCP](/docs/api/tcp) +- `Bun.listen` `Bun.connect` + +--- + +- [Transpiler](/docs/api/transpiler) +- `Bun.Transpiler` + +--- + +- [Routing](/docs/api/file-system-router) +- `Bun.FileSystemRouter` + +--- + +- [HTMLRewriter](/docs/api/html-rewriter) +- `HTMLRewriter` + +--- + +- [Utils](/docs/api/utils) +- `Bun.peek` `Bun.which` + +--- + +- [SQLite](/docs/api/sqlite) +- `bun:sqlite` + +--- + +- [FFI](/docs/api/ffi) +- `bun:ffi` + +--- + +- [DNS](/docs/api/dns) +- `bun:dns` + +--- + +- [Testing](/docs/api/test) +- `bun:test` + +--- + +- [Node-API](/docs/api/node-api) +- `Node-API` + +--- + +{% /table %} diff --git a/docs/project/configuration.md b/docs/runtime/configuration.md index c70689b94..7c4da480b 100644 --- a/docs/project/configuration.md +++ b/docs/runtime/configuration.md @@ -1,23 +1,27 @@ -## Environment variables - -- `GOMAXPROCS`: For `bun bun`, this sets the maximum number of threads to use. If you’re experiencing an issue with `bun bun`, try setting `GOMAXPROCS=1` to force Bun to run single-threaded -- `DISABLE_BUN_ANALYTICS=1` this disables Bun's analytics. Bun records bundle timings (so we can answer with data, "is Bun getting faster?") and feature usage (e.g., "are people actually using macros?"). The request body size is about 60 bytes, so it’s not a lot of data -- `TMPDIR`: Before `bun bun` completes, it stores the new `.bun` in `$TMPDIR`. If unset, `TMPDIR` defaults to the platform-specific temporary directory (on Linux, `/tmp` and on macOS `/private/tmp`) +There are two primary mechanisms for configuring the behavior of Bun. -## `bunfig.toml` +- environment variables +- `bunfig.toml`: Bun's configuration file -Bun's configuration file is called `bunfig.toml`. Configuring with `bunfig.toml` is optional. Bun aims to be zero-configuration out of the box, but is also highly configurable for advanced use cases.. +Configuring with `bunfig.toml` is optional. Bun aims to be zero-configuration out of the box, but is also highly configurable for advanced use cases. Your `bunfig.toml` should live in your project root alongside `package.json`. -Your `bunfig.toml` should live in your project root alongside `package.json`. You can also create a global configuration file at the following paths: +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. +## Environment variables + +<!-- - `GOMAXPROCS`: For `bun bun`, this sets the maximum number of threads to use. If you’re experiencing an issue with `bun bun`, try setting `GOMAXPROCS=1` to force Bun to run single-threaded --> + +- `DISABLE_BUN_ANALYTICS=1` this disables Bun's analytics. Bun records bundle timings (so we can answer with data, "is Bun getting faster?") and feature usage (e.g., "are people actually using macros?"). The request body size is about 60 bytes, so it’s not a lot of data +- `TMPDIR`: Bun occasionally requires a directory to store intermediate assets during bundling or other operations. If unset, `TMPDIR` defaults to the platform-specific temporary directory (on Linux, `/tmp` and on macOS `/private/tmp`). + ## Configure `bun install` -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/project/configuration). +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). ### Default flags @@ -42,7 +46,7 @@ production = false dryRun = false ``` -### Registries +### Private scopes and registries The default registry is `https://registry.npmjs.org/`. This can be globally configured in `bunfig.toml`: diff --git a/docs/runtime/index.md b/docs/runtime/index.md index 600389223..b835ba464 100644 --- a/docs/runtime/index.md +++ b/docs/runtime/index.md @@ -1,17 +1,28 @@ -Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js. +Bun is a new JavaScript & TypeScript runtime designed to be a faster, leaner, and more modern drop-in replacement for Node.js. ## 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. Performance sensitive APIs like `Buffer`, `fetch`, and `Response` are heavily profiled and optimized. Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. It starts and runs faster than V8, the engine used by Node.js and Chromium-based browsers. +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. -## File types +{% image src="/images/bun-run-speed.jpeg" caption="Bun vs Node.js vs Deno running Hello World" /%} -Bun natively supports TypeScript and JSX out of the box. +<!-- If no `node_modules` directory is found in the working directory or above, Bun will abandon Node.js-style module resolution in favor of the `Bun module resolution algorithm`. Under Bun-style module resolution, all packages are _auto-installed_ on the fly into a [global module cache](/docs/cli/install#global-cache). For full details on this algorithm, refer to [Runtime > Modules](/docs/runtime/modules). --> + +Performance sensitive APIs like `Buffer`, `fetch`, and `Response` are heavily profiled and optimized. Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. It starts and runs faster than V8, the engine used by Node.js and Chromium-based browsers. + +## TypeScript + +Bun natively supports TypeScript out of the box. All files are transpiled on the fly by Bun's fast native transpiler before being executed. Similar to other build tools, Bun does not perform typechecking; it simply removes type annotations from the file. ```bash -$ bun server.tsx +$ bun index.js +$ bun index.jsx +$ bun index.ts +$ bun index.tsx ``` +Some aspects of Bun's runtime behavior are affected by the contents of your `tsconfig.json` file. Refer to [Runtime > TypeScript](/docs/runtime/typescript) page for details. + <!-- Before execution, Bun internally transforms all source files to vanilla JavaScript using its fast native transpiler. The transpiler looks at the files extension to determine how to handle it. --> <!-- @@ -79,6 +90,10 @@ every file before execution. It's transpiler can directly run TypeScript and JS {% /table %} --> +## JSX + +## JSON and TOML + Source files can import a `*.json` or `*.toml` file to load its contents as a plain old JavaScript object. ```ts @@ -86,7 +101,9 @@ import pkg from "./package.json"; import bunfig from "./bunfig.toml"; ``` -As of v0.5.2, experimental support has been for the [WebAssembly System Interface](https://github.com/WebAssembly/WASI) (WASI), you can run `.wasm` binaries. +## 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: ```bash $ bun ./my-wasm-app.wasm @@ -95,14 +112,13 @@ $ 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 optimized for performance, but if this feature gets popular, we'll definitely invest time in making it faster. -{% /callout %} -Support for additional file types can be implemented with [Plugins](/docs/runtime/plugins). +**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. +{% /callout %} ## Node.js compatibility -Long-term, Bun aims for complete Node.js compatibility. Most Node.js packages already work with Bun out of the box, but certain low-level APIs like `dgram` are still unimplemented. Track the current compatibility status at [Ecosystem > Node.js](/docs/ecosystem/nodejs). +Long-term, Bun aims for complete Node.js compatibility. Most Node.js packages already work with Bun out of the box, but certain low-level APIs like `dgram` are still unimplemented. Track the current compatibility status at [Ecosystem > Node.js](/docs/runtime/nodejs-apis). Bun implements the Node.js module resolution algorithm, so dependencies can still be managed with `package.json`, `node_modules`, and CommonJS-style imports. @@ -110,7 +126,7 @@ Bun implements the Node.js module resolution algorithm, so dependencies can stil **Note** — We recommend using Bun's [built-in package manager](/docs/cli/install) for a performance boost over other npm clients. {% /callout %} -## Web-standard +## Web APIs <!-- When prudent, Bun attempts to implement Web-standard APIs instead of introducing new APIs. Refer to [Runtime > Web APIs](/docs/web-apis) for a list of Web APIs that are available in Bun. --> @@ -207,7 +223,7 @@ The following Web APIs are partially or completely supported. {% /table %} -## Bun-native APIs +## Bun APIs Bun exposes a set of Bun-specific APIs on the `Bun` global object and through a number of built-in modules. These APIs represent the canonical "Bun-native" way to perform some common development tasks. They are all heavily optimized for performance. Click the link in the left column to view the associated documentation. @@ -284,3 +300,7 @@ Bun exposes a set of Bun-specific APIs on the `Bun` global object and through a --- {% /table %} + +## Plugins + +Support for additional file types can be implemented with plugins. Refer to [Runtime > Plugins](/docs/runtime/plugins) for full documentation. diff --git a/docs/runtime/jsx.md b/docs/runtime/jsx.md new file mode 100644 index 000000000..1ace6e367 --- /dev/null +++ b/docs/runtime/jsx.md @@ -0,0 +1,35 @@ +Bun supports `.jsx` and `.tsx` files out of the box. Bun's internal transpiler converts JSX syntax into vanilla JavaScript before execution. + +```tsx#react.tsx +function Component(props: {message: string}) { + return ( + <body> + <h1 style={{color: 'red'}}>{props.message}</h1> + </body> + ); +} + +console.log(<Component message="Hello world!" />); +``` + +Bun implements special logging for JSX to make debugging easier. + +```bash +$ bun run react.tsx +<Component message="Hello world!" /> +``` + +<!-- ### Prop punning + +The Bun runtime also supports "prop punning" for JSX. This is a shorthand syntax useful for assigning a variable to a prop with the same name. + +```tsx +function Div(props: {className: string;}) { + const {className} = props; + + // without punning + return <div className={className} />; + // with punning + return <div {className} />; +} +``` --> diff --git a/docs/runtime/loaders.md b/docs/runtime/loaders.md index c7977534c..78f1b44c0 100644 --- a/docs/runtime/loaders.md +++ b/docs/runtime/loaders.md @@ -1,3 +1,82 @@ +## TypeScript + +Bun natively supports TypeScript out of the box. All files are transpiled on the fly by Bun's fast native transpiler before being executed. Similar to other build tools, Bun does not perform typechecking; it simply removes type annotations from the file. + +```bash +$ bun index.js +$ bun index.jsx +$ bun index.ts +$ bun index.tsx +``` + +Some aspects of Bun's runtime behavior are affected by the contents of your `tsconfig.json` file. Refer to [Runtime > TypeScript](/docs/runtime/typescript) page for details. + +## JSX + +Bun supports `.jsx` and `.tsx` files out of the box. Bun's internal transpiler converts JSX syntax into vanilla JavaScript before execution. + +```tsx#react.tsx +function Component(props: {message: string}) { + return ( + <body> + <h1 style={{color: 'red'}}>{props.message}</h1> + </body> + ); +} + +console.log(<Component message="Hello world!" />); +``` + +Bun implements special logging for JSX to make debugging easier. + +```bash +$ bun run react.tsx +<Component message="Hello world!" /> +``` + +## JSON and TOML + +JSON and TOML files can be directly imported from a source file. The contents will be loaded and returned as a JavaScript object. + +```ts +import pkg from "./package.json"; +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: + +```bash +$ bun ./my-wasm-app.wasm +# if the filename doesn't end with ".wasm" +$ 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. +{% /callout %} + +## Unknown file types + +By default, when Bun encounters an import with an unsupported file extension, it returns an absolute path to the location on disk. + +```ts +import file from "./movie.mp4"; + +file; +// /path/to/movie.mp4 +``` + +Note: This behavior only applies when executing a file with `bun run`! When using Bun's bundler, the behavior may be different depending on your bundler configuration. + +## Custom loaders + +Support for additional file types can be implemented with plugins. Refer to [Runtime > Plugins](/docs/runtime/plugins) for full documentation. + +<!-- + A loader determines how to map imports & file extensions to transforms and output. Currently, Bun implements the following loaders: @@ -25,4 +104,4 @@ You can configure which loaders map to which extensions by passing `--loaders` t $ bun --loader=.js:js ``` -This will disable JSX transforms for `.js` files. +This will disable JSX transforms for `.js` files. --> diff --git a/docs/runtime/modules.md b/docs/runtime/modules.md index d7f85d925..6c33f7336 100644 --- a/docs/runtime/modules.md +++ b/docs/runtime/modules.md @@ -156,104 +156,3 @@ 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. - -## Bun-style resolution - -{% 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/cli/install#global-cache) during execution (the same cache used by [`bun install`](/docs/cli/install)). - -```ts -import { foo } from "foo"; // install `latest` version - -foo(); -``` - -The first time you run this script, Bun will auto-install `"foo"` and cache it. The next time you run the script, it will use the cached version. - -### Version resolution - -To determine which version to install, Bun follows the following algorithm: - -1. Check for a `bun.lockb` file in the project root. If it exists, use the version specified in the lockfile. -2. Otherwise, scan up the tree for a `package.json` that includes `"foo"` as a dependency. If found, use the specified semver version or version range. -3. Otherwise, use `latest`. - -### Cache behavior - -Once a version or version range has been determined, Bun will: - -1. Check the module cache for a compatible version. If one exists, use it. -2. When resolving `latest`, Bun will check if `package@latest` has been downloaded and cached in the last _24 hours_. If so, use it. -3. Otherwise, download and install the appropriate version from the `npm` registry. - -### Installation - -Packages are installed and cached into `<cache>/<pkg>@<version>`, so multiple versions of the same package can be cached at once. Additionally, a symlink is created under `<cache>/<pkg>/<version>` to make it faster to look up all versions of a package that exist in the cache. - -### Version specifiers - -This entire resolution algorithm can be short-circuited by specifying a version or version range directly in your import statement. - -```ts -import { z } from "zod@3.0.0"; // specific version -import { z } from "zod@next"; // npm tag -import { z } from "zod@^3.20.0"; // semver range -``` - -### Benefits - -This auto-installation approach is useful for a few reasons: - -- **Space efficiency** — Each version of a dependency only exists in one place on disk. This is a huge space and time savings compared to redundant per-project installations. -- **Portability** — To share simple scripts and gists, your source file is _self-contained_. No need to `zip` together a directory containing your code and config files. With version specifiers in `import` statements, even a `package.json` isn't necessary. -- **Convenience** — There's no need to run `npm install` or `bun install` before running a file or script. Just `bun run` it. -- **Backwards compatibility** — Because Bun still respects the versions specified in `package.json` if one exists, you can switch to Bun-style resolution with a single command: `rm -rf node_modules`. - -### Limitations - -- No Intellisense. TypeScript auto-completion in IDEs relies on the existence of type declaration files inside `node_modules`. We are investigating various solutions to this. -- No [patch-package](https://github.com/ds300/patch-package) support - -<!-- - The implementation details of Bun's install cache will change between versions. Don't think of it as an API. To reliably resolve packages, use Bun's builtin APIs (such as `Bun.resolveSync` or `import.meta.resolve`) instead of relying on the filesystem directly. Bun will likely move to a binary archive format where packages may not correspond to files/folders on disk at all - so if you depend on the filesystem structure instead of the JavaScript API, your code will eventually break. --> - -<!-- ### Customizing behavior - -To prefer locally-installed versions of packages. Instead of checking npm for latest versions, you can pass the `--prefer-offline` flag to prefer locally-installed versions of packages. - -```bash -$ bun run --prefer-offline my-script.ts -``` - -This will check the install cache for installed versions of packages before checking the npm registry. If no matching version of a package is installed, only then will it check npm for the latest version. - -#### Prefer latest - -To always use the latest version of a package, you can pass the `--prefer-latest` flag. - -```bash -$ bun run --prefer-latest my-script.ts -``` --> - -### FAQ - -{% details summary="How is this different from what pnpm does?" %} - -With pnpm, you have to run `pnpm install`, which creates a `node_modules` folder of symlinks for the runtime to resolve. By contrast, Bun resolves dependencies on the fly when you run a file; there's no need to run any `install` command ahead of time. Bun also doesn't create a `node_modules` folder. - -{% /details %} - -{% details summary="How is this different from Yarn Plug'N'Play does?" %} -With Yarn, you must run `yarn install` before you run a script. By contrast, Bun resolves dependencies on the fly when you run a file; there's no need to run any `install` command ahead of time. - -Yarn Plug'N'Play also uses zip files to store dependencies. This makes dependency loading [slower at runtime](https://twitter.com/jarredsumner/status/1458207919636287490), as random access reads on zip files tend to be slower than the equivalent disk lookup. -{% /details %} - -{% details summary="How is this different from what Deno does?" %} - -Deno requires an `npm:` specifier before each npm `import`, lacks support for import maps via `compilerOptions.paths` in `tsconfig.json`, and has incomplete support for `package.json` settings. Unlike Deno, Bun does not currently support URL imports. -{% /details %} diff --git a/docs/ecosystem/nodejs.md b/docs/runtime/nodejs-apis.md index c821d3d9a..cbb264486 100644 --- a/docs/ecosystem/nodejs.md +++ b/docs/runtime/nodejs-apis.md @@ -183,6 +183,7 @@ This page is updated regularly to reflect compatibility status of the latest ver - {% anchor id="node_string_decoder" %} [`node:string_decoder`](https://nodejs.org/api/string_decoder.html) {% /anchor %} - 🟢 +- Fully implemented. --- @@ -230,7 +231,7 @@ This page is updated regularly to reflect compatibility status of the latest ver - {% anchor id="node_v8" %} [`node:v8`](https://nodejs.org/api/v8.html) {% /anchor %} - 🔴 -- Not implemented or planned. For profiling, use `bun:jsc` instead. +- Not implemented or planned. For profiling, use [`bun:jsc`](/docs/project/benchmarking#bunjsc) instead. --- diff --git a/docs/runtime/plugins.md b/docs/runtime/plugins.md index a7edb0c7b..788bfb3ef 100644 --- a/docs/runtime/plugins.md +++ b/docs/runtime/plugins.md @@ -19,13 +19,13 @@ plugin({ }); ``` -To consume this plugin, add this file to the `preload` option in your [`bunfig.toml`](/docs/project/configuration). Bun automatically loads the files/modules specified in `preload` before running a file. +To consume this plugin, add this file to the `preload` option in your [`bunfig.toml`](/docs/runtime/configuration). Bun automatically loads the files/modules specified in `preload` before running a file. ```toml preload = ["./yamlPlugin.ts"] ``` -{% details summary="Usage without preload" %} +{% details summary="Usage without preload" %} Alternatively, you can import this file manually at the top of your project's entrypoint, before any application code is imported. diff --git a/docs/ecosystem/typescript.md b/docs/runtime/typescript.md index dfedfb850..6ac1d991a 100644 --- a/docs/ecosystem/typescript.md +++ b/docs/runtime/typescript.md @@ -1,12 +1,14 @@ -Bun can directly execute `.ts` and `.tsx` files just like vanilla JavaScript, with no extra configuration. If you import a `.ts` or `.tsx` file (or an `npm` module that exports these files), Bun internally transpiles it into JavaScript then executes the file. +Bun can directly execute `.ts` and `.tsx` files with no extra configuration. If you import a `.ts` or `.tsx` file, Bun internally transpiles it into JavaScript then executes the file. {% callout %} **Note** — Similar to other build tools, Bun does not typecheck the files. Use [`tsc --noEmit`](https://www.typescriptlang.org/docs/handbook/compiler-options.html) (the official TypeScript CLI) if you're looking to catch static type errors. {% /callout %} -## Type definitions +## Configuring `tsconfig.json` -To install TypeScript definitions for Bun's built-in APIs, first install `bun-types`. +When using TypeScript and Bun together, it's important to properly configure your `tsconfig.json`. + +First, install the TypeScript definitions for Bun's built-in APIs: ```sh $ bun add -d bun-types # dev dependency @@ -22,13 +24,9 @@ Then include `"bun-types"` in the `compilerOptions.types` in your `tsconfig.json } ``` -## Compiler options - -Bun's runtime implements [modern ECMAScript features](https://github.com/sudheerj/ECMAScript-features), like bigint literals, nullish coalescing, dynamic imports, `import.meta`, `globalThis`, ES modules, top-level await, and more. To use these features without seeing TypeScript errors in your IDE, your `tsconfig.json` needs to be properly configured. +This is the most important step, as it allows you to use Bun's built in APIs without seeing TypeScript errors in your IDE. -These are the recommended `compilerOptions` for a Bun project. - -> The config below sets `moduleResolution` to `bundler` which requires TypeScript option is set to `"bundler"` to support [path mapping](#path-mapping). +Bun implements a range of [modern ECMAScript features](https://github.com/sudheerj/ECMAScript-features), like bigint literals, nullish coalescing, dynamic imports, `import.meta`, `globalThis`, ES modules, top-level await, and more. To use these features without seeing TypeScript errors in your IDE, set the following `compilerOptions`: ```jsonc { @@ -37,10 +35,11 @@ These are the recommended `compilerOptions` for a Bun project. "lib": ["esnext"], "module": "esnext", "target": "esnext", - - // requires typescript 5.x+ - // use "nodenext" for earlier versions + + // typescript 5.x+ "moduleResolution": "bundler", + // typescript 4.x or earlier + "moduleResolution": "nodenext", // support JSX, CommonJS "jsx": "react-jsx", // support JSX (value doesn't matter) diff --git a/docs/runtime/web-apis.md b/docs/runtime/web-apis.md index ebe0e6041..8ebc070b8 100644 --- a/docs/runtime/web-apis.md +++ b/docs/runtime/web-apis.md @@ -1,300 +1,92 @@ -Many web APIs aren't relevant in the context of a server-first runtime like Bun, such as the [DOM API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API#html_dom_api_interfaces), [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), and [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History_API). Many others, though, are broadly useful outside of the browser context; when possible, Bun implements these Web-standard APIs instead of introducing new APIs. +Some Web APIs aren't relevant in the context of a server-first runtime like Bun, such as the [DOM API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API#html_dom_api_interfaces) or [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API). Many others, though, are broadly useful outside of the browser context; when possible, Bun implements these Web-standard APIs instead of introducing new APIs. The following Web APIs are partially or completely supported. -## Globals - {% table %} --- -- Crypto -- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) - [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) - ---- - -- Debugging - -- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)[`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance) - ---- - -- Encoding and decoding -- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob) [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa) [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) - ---- - -- Timeouts -- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) - ---- - -- Intervals -- [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval)[`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) - ---- - - HTTP - [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) --- -- Microtasks -- [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) +- URLs +- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) --- -- Errors -- [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError) [`ResolveError`](https://developer.mozilla.org/en-US/docs/Web/API/ResolveError) - [`BuildError`](https://developer.mozilla.org/en-US/docs/Web/API/BuildError) +- Streams +- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy) [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) and associated classes --- -- User interaction -- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) - -<!-- - Blocking. Prints the alert message to terminal and awaits `[ENTER]` before proceeding. --> -<!-- - Blocking. Prints confirmation message and awaits `[y/N]` input from user. Returns `true` if user entered `y` or `Y`, `false` otherwise. -- Blocking. Prints prompt message and awaits user input. Returns the user input as a string. --> - - Blob - [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) --- -- Realms -- [`ShadowRealm`](https://github.com/tc39/proposal-shadowrealm) - ---- - -- Events -- [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) - [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event) [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) [`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent) - ---- - - WebSockets - [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) --- -- URLs -- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) - ---- - -- Streams -- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy) [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) plus associated `*Reader`, `*Writer`, and `*Controller` classes. - -<!-- ## Globals - -{% table %} - ---- - ---- - -- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) - ---- - -- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) +- Encoding and decoding +- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob) [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa) [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) --- -- [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance) - -{% /table %} - -## Functions - -{% table %} - -- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob) +- Timeouts +- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) --- -- [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa) +- Intervals +- [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval)[`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) --- -- [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) +- Crypto +- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) + [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) --- -- [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) - ---- +- Debugging -- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) +- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance) --- +- Microtasks - [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) --- -- [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError) - ---- - -- [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) - ---- - -- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) - ---- - -- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/alert) -- Blocking. Prints the alert message to terminal and awaits `[ENTER]` before proceeding. - ---- - -- [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/confirm) -- Blocking. Prints confirmation message and awaits `[y/N]` input from user. Returns `true` if user entered `y` or `Y`, `false` otherwise. - ---- - -- [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/prompt) -- Blocking. Prints prompt message and awaits user input. Returns the user input as a string. - ---- - -- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) - -{% /table %} - -## Classes - -{% table %} - ---- - -- [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) - ---- - -- [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) - ---- - -- [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) +- Errors +- [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError) [`ResolveError`](https://developer.mozilla.org/en-US/docs/Web/API/ResolveError) + [`BuildError`](https://developer.mozilla.org/en-US/docs/Web/API/BuildError) --- -- [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) and [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) +- User interaction +- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) (intended for interactive CLIs) ---- +<!-- - Blocking. Prints the alert message to terminal and awaits `[ENTER]` before proceeding. --> +<!-- - Blocking. Prints confirmation message and awaits `[y/N]` input from user. Returns `true` if user entered `y` or `Y`, `false` otherwise. +- Blocking. Prints prompt message and awaits user input. Returns the user input as a string. --> --- +- Realms - [`ShadowRealm`](https://github.com/tc39/proposal-shadowrealm) -- A ["better `eval`](https://2ality.com/2022/04/shadow-realms.html). Currently a Stage 3 TC39 proposal - ---- - -- [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) --- +- Events - [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) + [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event) [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) [`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent) --- -- [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event) - ---- - -- [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) - ---- - -- [`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) - ---- - -- [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent) - ---- - -- [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) - ---- - -- [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) - ---- - -- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) - ---- - -- [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) - ---- - -- [`Loader`](https://developer.mozilla.org/en-US/docs/Web/API/Loader) - ---- - -- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) - ---- - -- [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) - ---- - -- [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy) - ---- - -- [`ReadableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultController) - ---- - -- [`ReadableStreamDefaultReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader) - ---- - -- [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) - ---- - -- [`WritableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultController) - ---- - -- [`WritableStreamDefaultWriter`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter) - ---- - -- [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) - ---- - -- [`TransformStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStreamDefaultController) - ---- - -- [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) - ---- - -- [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) - ---- - -- [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) - ---- - -- [`ResolveError`](https://developer.mozilla.org/en-US/docs/Web/API/ResolveError) - ---- - -- [`BuildError`](https://developer.mozilla.org/en-US/docs/Web/API/BuildError) - -{% /table %} --> +{% /table %} diff --git a/docs/templates.md b/docs/templates.md new file mode 100644 index 000000000..e80e95eda --- /dev/null +++ b/docs/templates.md @@ -0,0 +1,256 @@ +## `bun init` + +Scaffold an empty project with the interactive `bun init` command. + +```bash +$ bun init +bun init helps you get started with a minimal project and tries to +guess sensible defaults. Press ^C anytime to quit. + +package name (quickstart): +entry point (index.ts): + +Done! A package.json file was saved in the current directory. + + index.ts + + .gitignore + + tsconfig.json (for editor auto-complete) + + README.md + +To get started, run: + bun run index.ts +``` + +Press `enter` to accept the default answer for each prompt, or pass the `-y` flag to auto-accept the defaults. + +## `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: + +```bash +$ bun create <template> # an official template (remote) +$ bun create <username>/<repo> # a GitHub repo (remote) +$ bun create <local-template> # a custom template (local) +``` + +Running `bun create` performs the following steps: + +- 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. +- 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 + +The following official templates are available. + +```bash +bun create next ./myapp +bun create react ./myapp +bun create svelte-kit ./myapp +bun create elysia ./myapp +bun create hono ./myapp +bun create kingworld ./myapp +``` + +Each of these corresponds to a directory in the [bun-community/create-templates](https://github.com/bun-community/create-templates) repo. If you think a major framework is missing, please open a PR there. This list will change over time as additional examples are added. To see an up-to-date list, run `bun create` with no arguments. + +```bash +$ bun create +Welcome to bun! Create a new project by pasting any of the following: + <list of templates> +``` + +{% 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 %} + +### GitHub repos + +A template of the form `<username>/<repo>` will be downloaded from GitHub. + +```bash +$ bun create ahfarmer/calculator ./myapp +``` + +Complete GitHub URLs will also work: + +```bash +$ 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. + +### Local templates + +{% callout %} +**⚠️ Warning** — Unlike remote templates, running `bun create` with a local template will delete the entire destination folder if it already exists! Be careful. +{% /callout %} +Bun's templater can be extended to support custom templates defined on your local file system. These templates should live in one of the following directories: + +- `$HOME/.bun-create/<name>`: global templates +- `<project root>/.bun-create/<name>`: project-specific templates + +{% callout %} +**Note** — You can customize the global template path by setting the `BUN_CREATE_DIR` environment variable. +{% /callout %} + +To create a local template, navigate to `$HOME/.bun-create` and create a new directory with the desired name of your template. + +```bash +$ cd $HOME/.bun-create +$ mkdir foo +$ cd foo +``` + +Then, create a `package.json` file in that directory with the following contents: + +```json +{ + "name": "foo" +} +``` + +You can run `bun create foo` elsewhere on your file system to verify that Bun is correctly finding your local template. + +{% table %} + +--- + +- `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: + +```json +{ + "name": "@bun-examples/simplereact", + "version": "0.0.1", + "main": "index.js", + "dependencies": { + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "bun-create": { + "preinstall": "echo 'Installing...'", // a single command + "postinstall": ["echo 'Done!'"], // an array of commands + "start": "bun run echo 'Hello world!'" + } +} +``` + +When 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 %} + +- Flag +- Description + +--- + +- `--force` +- Overwrite existing files + +--- + +- `--no-install` +- Skip installing `node_modules` & tasks + +--- + +- `--no-git` +- Don’t initialize a git repository + +--- + +- `--open` +- Start & open in-browser after finish + +{% /table %} + +#### Environment variables + +{% table %} + +- Name +- Description + +--- + +- `GITHUB_API_DOMAIN` +- If you’re using a GitHub enterprise or a proxy, you can customize the GitHub domain Bun pings for downloads + +--- + +- `GITHUB_API_TOKEN` +- This lets `bun create` work with private repositories or if you get rate-limited + +{% /table %} + +{% details summary="How `bun create` works" %} + +When you run `bun create ${template} ${destination}`, here’s what happens: + +IF remote template + +1. GET `registry.npmjs.org/@bun-examples/${template}/latest` and parse it +2. GET `registry.npmjs.org/@bun-examples/${template}/-/${template}-${latestVersion}.tgz` +3. Decompress & extract `${template}-${latestVersion}.tgz` into `${destination}` + + - If there are files that would overwrite, warn and exit unless `--force` is passed + +IF GitHub repo + +1. Download the tarball from GitHub’s API +2. Decompress & extract into `${destination}` + + - If there are files that would overwrite, warn and exit unless `--force` is passed + +ELSE IF local template + +1. Open local template folder +2. Delete destination directory recursively +3. Copy files recursively using the fastest system calls available (on macOS `fcopyfile` and Linux, `copy_file_range`). Do not copy or traverse into `node_modules` folder if exists (this alone makes it faster than `cp`) + +4. Parse the `package.json` (again!), update `name` to be `${basename(destination)}`, remove the `bun-create` section from the `package.json` and save the updated `package.json` to disk. + - IF Next.js is detected, add `bun-framework-next` to the list of dependencies + - IF Create React App is detected, add the entry point in /src/index.{js,jsx,ts,tsx} to `public/index.html` + - IF Relay is detected, add `bun-macro-relay` so that Relay works +5. Auto-detect the npm client, preferring `pnpm`, `yarn` (v1), and lastly `npm` +6. Run any tasks defined in `"bun-create": { "preinstall" }` with the npm client +7. Run `${npmClient} install` unless `--no-install` is passed OR no dependencies are in package.json +8. Run any tasks defined in `"bun-create": { "preinstall" }` with the npm client +9. Run `git init; git add -A .; git commit -am "Initial Commit";` + + - Rename `gitignore` to `.gitignore`. NPM automatically removes `.gitignore` files from appearing in packages. + - If there are dependencies, this runs in a separate thread concurrently while node_modules are being installed + - Using libgit2 if available was tested and performed 3x slower in microbenchmarks + +{% /details %} diff --git a/docs/test/writing.md b/docs/test/writing.md new file mode 100644 index 000000000..b79f88a0f --- /dev/null +++ b/docs/test/writing.md @@ -0,0 +1,357 @@ +Define tests with a Jest-like API imported from the built-in `bun:test` module. Long term, Bun aims for complete Jest compatibility; at the moment, a [limited set](#matchers) of `expect` matchers are supported. + +## Basic usage + +To define a simple test: + +```ts#math.test.ts +import { expect, test } from "bun:test"; + +test("2 + 2", () => { + expect(2 + 2).toBe(4); +}); +``` + +Tests can be grouped into suites with `describe`. + +```ts#math.test.ts +import { expect, test, describe } from "bun:test"; + +describe("arithmetic", () => { + test("2 + 2", () => { + expect(2 + 2).toBe(4); + }); + + test("2 * 2", () => { + expect(2 * 2).toBe(4); + }); +}); +``` + +Tests can be `async`. + +```ts +import { expect, test } from "bun:test"; + +test("2 * 2", async () => { + const result = await Promise.resolve(2 * 2); + expect(result).toEqual(4); +}); +``` + +Alternatively, use the `done` callback to signal completion. If you include the `done` callback as a parameter in your test definition, you _must_ call it or the test will hang. + +```ts +import { expect, test } from "bun:test"; + +test("2 * 2", done => { + Promise.resolve(2 * 2).then(result => { + expect(result).toEqual(4); + done(); + }); +}); +``` + +Skip individual tests with `test.skip`. + +```ts +import { expect, test } from "bun:test"; + +test.skip("wat", () => { + // TODO: fix this + expect(0.1 + 0.2).toEqual(0.3); +}); +``` + +## Setup and teardown + +Perform per-test setup and teardown logic with `beforeEach` and `afterEach`. + +```ts +import { expect, test } from "bun:test"; + +beforeEach(() => { + console.log("running test."); +}); + +afterEach(() => { + console.log("done with test."); +}); + +// tests... +``` + +Perform per-scope setup and teardown logic with `beforeAll` and `afterAll`. At the top-level, the _scope_ is the current file; in a `describe` block, the scope is the block itself. + +```ts +import { expect, test, beforeAll, afterAll } from "bun:test"; + +let db: Database; +beforeAll(() => { + // connect to database + db = initializeDatabase(); +}); + +afterAll(() => { + // close connection + db.close(); +}); + +// tests... +``` + +## Matchers + +Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress [here](https://github.com/oven-sh/bun/issues/1825). + +{% table %} + +- 🟢 +- [`.not`](https://jestjs.io/docs/expect#not) + +--- + +- 🟢 +- [`.toBe()`](https://jestjs.io/docs/expect#tobevalue) + +--- + +- 🟢 +- [`.toEqual()`](https://jestjs.io/docs/expect#toequalvalue) + +--- + +- 🟢 +- [`.toBeNull()`](https://jestjs.io/docs/expect#tobenull) + +--- + +- 🟢 +- [`.toBeUndefined()`](https://jestjs.io/docs/expect#tobeundefined) + +--- + +- 🟢 +- [`.toBeNaN()`](https://jestjs.io/docs/expect#tobenan) + +--- + +- 🟢 +- [`.toBeDefined()`](https://jestjs.io/docs/expect#tobedefined) + +--- + +- 🟢 +- [`.toBeFalsy()`](https://jestjs.io/docs/expect#tobefalsy) + +--- + +- 🟢 +- [`.toBeTruthy()`](https://jestjs.io/docs/expect#tobetruthy) + +--- + +- 🟢 +- [`.toContain()`](https://jestjs.io/docs/expect#tocontainitem) + +--- + +- 🟢 +- [`.toStrictEqual()`](https://jestjs.io/docs/expect#tostrictequalvalue) + +--- + +- 🟢 +- [`.toThrow()`](https://jestjs.io/docs/expect#tothrowerror) + +--- + +- 🟢 +- [`.toHaveLength()`](https://jestjs.io/docs/expect#tohavelengthnumber) + +--- + +- 🟢 +- [`.toHaveProperty()`](https://jestjs.io/docs/expect#tohavepropertykeypath-value) + +--- + +- 🔴 +- [`.extend`](https://jestjs.io/docs/expect#expectextendmatchers) + +--- + +- 🔴 +- [`.anything()`](https://jestjs.io/docs/expect#expectanything) + +--- + +- 🔴 +- [`.any()`](https://jestjs.io/docs/expect#expectanyconstructor) + +--- + +- 🔴 +- [`.arrayContaining()`](https://jestjs.io/docs/expect#expectarraycontainingarray) + +--- + +- 🔴 +- [`.assertions()`](https://jestjs.io/docs/expect#expectassertionsnumber) + +--- + +- 🔴 +- [`.closeTo()`](https://jestjs.io/docs/expect#expectclosetonumber-numdigits) + +--- + +- 🔴 +- [`.hasAssertions()`](https://jestjs.io/docs/expect#expecthasassertions) + +--- + +- 🔴 +- [`.objectContaining()`](https://jestjs.io/docs/expect#expectobjectcontainingobject) + +--- + +- 🔴 +- [`.stringContaining()`](https://jestjs.io/docs/expect#expectstringcontainingstring) + +--- + +- 🔴 +- [`.stringMatching()`](https://jestjs.io/docs/expect#expectstringmatchingstring--regexp) + +--- + +- 🔴 +- [`.addSnapshotSerializer()`](https://jestjs.io/docs/expect#expectaddsnapshotserializerserializer) + +--- + +- 🔴 +- [`.resolves()`](https://jestjs.io/docs/expect#resolves) + +--- + +- 🔴 +- [`.rejects()`](https://jestjs.io/docs/expect#rejects) + +--- + +- 🔴 +- [`.toHaveBeenCalled()`](https://jestjs.io/docs/expect#tohavebeencalled) + +--- + +- 🔴 +- [`.toHaveBeenCalledTimes()`](https://jestjs.io/docs/expect#tohavebeencalledtimesnumber) + +--- + +- 🔴 +- [`.toHaveBeenCalledWith()`](https://jestjs.io/docs/expect#tohavebeencalledwitharg1-arg2-) + +--- + +- 🔴 +- [`.toHaveBeenLastCalledWith()`](https://jestjs.io/docs/expect#tohavebeenlastcalledwitharg1-arg2-) + +--- + +- 🔴 +- [`.toHaveBeenNthCalledWith()`](https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-) + +--- + +- 🔴 +- [`.toHaveReturned()`](https://jestjs.io/docs/expect#tohavereturned) + +--- + +- 🔴 +- [`.toHaveReturnedTimes()`](https://jestjs.io/docs/expect#tohavereturnedtimesnumber) + +--- + +- 🔴 +- [`.toHaveReturnedWith()`](https://jestjs.io/docs/expect#tohavereturnedwithvalue) + +--- + +- 🔴 +- [`.toHaveLastReturnedWith()`](https://jestjs.io/docs/expect#tohavelastreturnedwithvalue) + +--- + +- 🔴 +- [`.toHaveNthReturnedWith()`](https://jestjs.io/docs/expect#tohaventhreturnedwithnthcall-value) + +--- + +- 🔴 +- [`.toBeCloseTo()`](https://jestjs.io/docs/expect#tobeclosetonumber-numdigits) + +--- + +- 🟢 +- [`.toBeGreaterThan()`](https://jestjs.io/docs/expect#tobegreaterthannumber--bigint) + +--- + +- 🟢 +- [`.toBeGreaterThanOrEqual()`](https://jestjs.io/docs/expect#tobegreaterthanorequalnumber--bigint) + +--- + +- 🟢 +- [`.toBeLessThan()`](https://jestjs.io/docs/expect#tobelessthannumber--bigint) + +--- + +- 🟢 +- [`.toBeLessThanOrEqual()`](https://jestjs.io/docs/expect#tobelessthanorequalnumber--bigint) + +--- + +- 🟢 +- [`.toBeInstanceOf()`](https://jestjs.io/docs/expect#tobeinstanceofclass) (Bun v0.5.8+) + +--- + +- 🔴 +- [`.toContainEqual()`](https://jestjs.io/docs/expect#tocontainequalitem) + +--- + +- 🔴 +- [`.toMatch()`](https://jestjs.io/docs/expect#tomatchregexp--string) + +--- + +- 🔴 +- [`.toMatchObject()`](https://jestjs.io/docs/expect#tomatchobjectobject) + +--- + +- 🟢 +- [`.toMatchSnapshot()`](https://jestjs.io/docs/expect#tomatchsnapshotpropertymatchers-hint) (Bun v0.5.8+) + +--- + +- 🔴 +- [`.toMatchInlineSnapshot()`](https://jestjs.io/docs/expect#tomatchinlinesnapshotpropertymatchers-inlinesnapshot) + +--- + +- 🔴 +- [`.toThrowErrorMatchingSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchingsnapshothint) + +--- + +- 🔴 +- [`.toThrowErrorMatchingInlineSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchinginlinesnapshotinlinesnapshot) + +{% /table %} |