diff options
Diffstat (limited to 'docs/runtime')
-rw-r--r-- | docs/runtime/hot.md | 93 | ||||
-rw-r--r-- | docs/runtime/index.md | 286 | ||||
-rw-r--r-- | docs/runtime/loaders.md | 28 | ||||
-rw-r--r-- | docs/runtime/modules.md | 259 | ||||
-rw-r--r-- | docs/runtime/nodejs.md | 682 | ||||
-rw-r--r-- | docs/runtime/plugins.md | 245 | ||||
-rw-r--r-- | docs/runtime/streams.md | 5 | ||||
-rw-r--r-- | docs/runtime/web-apis.md | 300 |
8 files changed, 1893 insertions, 5 deletions
diff --git a/docs/runtime/hot.md b/docs/runtime/hot.md new file mode 100644 index 000000000..bdd376011 --- /dev/null +++ b/docs/runtime/hot.md @@ -0,0 +1,93 @@ +{% callout %} +🚧 **Experimental** — Introduced in Bun v0.2.0. +{% /callout %} +Use `bun --hot` to enable hot reloading when executing code with Bun. + +```bash +$ bun --hot server.ts +``` + +Starting from the entrypoint (`server.ts` in the example above), Bun builds a registry of all imported source files (excluding those in `node_modules`) and watches them for changes. When a change is detected, Bun performs a "soft reload". All files are re-evaluated, but all global state (notably, the `globalThis` object) is persisted. + +```ts#server.ts +globalThis.count = globalThis.count ?? 0; +console.log(`Reloaded ${globalThis.count} times`); +globalThis.count++; + +setInterval(function () {}, 1000000); +``` + +If you run this file with `bun --hot server.ts`, you'll see the reload count increment every time you save the file. The call to `setInterval` is there to prevent the process from exiting. + +```bash +$ bun --hot index.ts +Reloaded 1 times +Reloaded 2 times +Reloaded 3 times +``` + +Traditional file watchers like `nodemon` restart the entire process, so HTTP servers and other stateful objects are lost. By contrast, `bun --hot` is able to reflect the updated code without restarting the process. + +### HTTP servers + +Bun provides the following simplified API for implementing HTTP servers. Refer to [API > HTTP](/docs/api/http) for full details. + +```ts#server.ts +globalThis.count = globalThis.count ?? 0; +globalThis.reloadCount++; + +export default { + fetch(req: Request) { + return new Response(`Reloaded ${globalThis.count} times`); + }, + port: 3000, +}; +``` + +The file above is simply exporting an object with a `fetch` handler defined. When this file is executed, Bun interprets this as an HTTP server and passes the exported object into `Bun.serve`. + +Unlike an explicit call to `Bun.serve`, the object-based syntax works out of the box with `bun --hot`. When you save the file, your HTTP server be reloaded with the updated code without the process being restarted. This results in seriously fast refresh speeds. + +{% image src="https://user-images.githubusercontent.com/709451/195477632-5fd8a73e-014d-4589-9ba2-e075ad9eb040.gif" alt="Bun vs Nodemon refresh speeds" caption="Bun on the left, Nodemon on the right." /%} + +For more fine-grained control, you can use the `Bun.serve` API directly and handle the server reloading manually. + +```ts#server.ts +import type {Serve} from "bun"; + +globalThis.count = globalThis.count ?? 0; +globalThis.reloadCount++; + +// define server parameters +const serverOptions: Serve = { + port: 3000, + fetch(req) { + return new Response(`Reloaded ${globalThis.count} times`); + } +}; + +if (!globalThis.server) { + globalThis.server = Bun.serve(serverOptions); +} else { + // reload server + globalThis.server.reload(serverOptions); +} +``` + +{% callout %} +**Note** — In a future version of Bun, support for Vite's `import.meta.hot` is planned to enable better lifecycle management for hot reloading and to align with the ecosystem. + +{% /callout %} + +{% details summary="Implementation `details`" %} + +On reload, Bun: + +- Resets the internal `require` cache and ES module registry (`Loader.registry`) +- Runs the garbage collector synchronously (to minimize memory leaks, at the cost of runtime performance) +- Re-transpiles all of your code from scratch (including sourcemaps) +- Re-evaluates the code with JavaScriptCore + +This implementation isn't particularly optimized. It re-transpiles files that haven't changed. It makes no attempt at incremental compilation. It's a starting point. + +{% /details %} diff --git a/docs/runtime/index.md b/docs/runtime/index.md new file mode 100644 index 000000000..29ea99c0f --- /dev/null +++ b/docs/runtime/index.md @@ -0,0 +1,286 @@ +Bun is a new JavaScript runtime designed to be a faster, leaner, more modern 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. + +## File types + +Bun natively supports TypeScript and JSX out of the box. + +```bash +$ bun server.tsx +``` + +<!-- 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. --> + +<!-- + +every file before execution. It's transpiler can directly run TypeScript and JSX `{.js|.jsx|.ts|.tsx}` files directly. During execution, Bun internally transpiles all files (including `.js` files) to vanilla JavaScript with it's fast native transpiler. --> + +<!-- A loader determines how to map imports & file extensions to transforms and output. --> + +<!-- Currently, Bun implements the following loaders: --> + +<!-- {% table %} + +- Extension +- Transforms +- Output (internal) + +--- + +- `.js` +- JSX + JavaScript +- `.js` + +--- + +- `.jsx` +- JSX + JavaScript +- `.js` + +--- + +- `.ts` +- TypeScript + JavaScript +- `.js` + +--- + +- `.tsx` +- TypeScript + JSX + JavaScript +- `.js` + +--- + +- `.mjs` +- JavaScript +- `.js` + +--- + +- `.cjs` +- JavaScript +- `.js` + +--- + +- `.mts` +- TypeScript +- `.js` + +--- + +- `.cts` +- TypeScript +- `.js` + + +{% /table %} --> + +Source files can import a `*.json` or `*.toml` file to load its contents as a plain old JavaScript object. + +```ts +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. + +```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 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). + +## 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 [Runtime > Node.js API](/docs/runtime/nodejs). + +Bun implements the Node.js module resolution algorithm, so dependencies can still be managed with `package.json`, `node_modules`, and CommonJS-style imports. + +{% callout %} +**Note** — We recommend using Bun's [built-in package manager](/docs/cli/install) for a performance boost over other npm clients. +{% /callout %} + +## Web-standard + +<!-- 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. --> + +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. + +{% table %} + +--- + +- 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) + +--- + +- 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) and associated classes + +--- + +- Blob +- [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) + +--- + +- WebSockets +- [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) + +--- + +- 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) + +--- + +- 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) + +--- + +- Microtasks +- [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) + +--- + +- 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) + +--- + +- 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) + +--- + +- 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) + +--- + +{% /table %} + +## Bun-native 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. + +{% 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/runtime/loaders.md b/docs/runtime/loaders.md new file mode 100644 index 000000000..c7977534c --- /dev/null +++ b/docs/runtime/loaders.md @@ -0,0 +1,28 @@ +A loader determines how to map imports & file extensions to transforms and output. + +Currently, Bun implements the following loaders: + +| Input | Loader | Output | +| ----- | ----------------------------- | ------ | +| .js | JSX + JavaScript | .js | +| .jsx | JSX + JavaScript | .js | +| .ts | TypeScript + JavaScript | .js | +| .tsx | TypeScript + JSX + JavaScript | .js | +| .mjs | JavaScript | .js | +| .cjs | JavaScript | .js | +| .mts | TypeScript | .js | +| .cts | TypeScript | .js | +| .toml | TOML | .js | +| .css | CSS | .css | +| .env | Env | N/A | +| .\* | file | string | + +Everything else is treated as `file`. `file` replaces the import with a URL (or a path). + +You can configure which loaders map to which extensions by passing `--loaders` to `bun`. For example: + +```sh +$ bun --loader=.js:js +``` + +This will disable JSX transforms for `.js` files. diff --git a/docs/runtime/modules.md b/docs/runtime/modules.md new file mode 100644 index 000000000..f10dad378 --- /dev/null +++ b/docs/runtime/modules.md @@ -0,0 +1,259 @@ +Module resolution in JavaScript is a complex topic. + +The ecosystem is currently in the midst of a years-long transition from CommonJS modules to native ES modules. TypeScript enforces its own set of rules around import extensions that aren't compatible with ESM. Different build tools support path re-mapping via disparate non-compatible mechanisms. + +Bun aims to provide a consistent and predictable module resolution system that just works. Unfortunately it's still quite complex. + +## Syntax + +Consider the following files. + +{% codetabs %} + +```ts#index.ts +import { hello } from "./hello"; + +hello(); +``` + +```ts#hello.ts +export function hello() { + console.log("Hello world!"); +} +``` + +{% /codetabs %} + +When we run `index.ts`, it prints "Hello world". + +```bash +$ bun index.ts +Hello world! +``` + +In this case, we are importing from `./hello`, a relative path with no extension. To resolve this import, Bun will check for the following files in order: + +- `./hello.ts` +- `./hello.tsx` +- `./hello.js` +- `./hello.mjs` +- `./hello.cjs` +- `./hello/index.ts` +- `./hello/index.js` +- `./hello/index.json` +- `./hello/index.mjs` + +Import paths are case-insensitive. + +```ts#index.ts +import { hello } from "./hello"; +import { hello } from "./HELLO"; +import { hello } from "./hElLo"; +``` + +Import paths can optionally include extensions. If an extension is present, Bun will only check for a file with that exact extension. + +```ts#index.ts +import { hello } from "./hello"; +import { hello } from "./hello.ts"; // this works +``` + +There is one exception: if you import `from "*.js{x}"`, Bun will additionally check for a matching `*.ts{x}` file, to be compatible with TypeScript's [ES module support](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#new-file-extensions). + +```ts#index.ts +import { hello } from "./hello"; +import { hello } from "./hello.ts"; // this works +import { hello } from "./hello.js"; // this also works +``` + +Bun supports both ES modules (`import`/`export` syntax) and CommonJS modules (`require()`/`module.exports`). The following CommonJS version would also work in Bun. + +{% codetabs %} + +```ts#index.js +const { hello } = require("./hello"); + +hello(); +``` + +```ts#hello.js +function hello() { + console.log("Hello world!"); +} + +exports.hello = hello; +``` + +{% /codetabs %} + +That said, using CommonJS is discouraged in new projects. + +## Resolution + +Bun implements the Node.js module resolution algorithm, so you can import packages from `node_modules` with a bare specifier. + +```ts +import { stuff } from "foo"; +``` + +The full specification of this algorithm are officially documented in the [Node.js documentation](https://nodejs.org/api/modules.html); we won't rehash it here. Briefly: if you import `from "foo"`, Bun scans up the file system for a `node_modules` directory containing the package `foo`. + +Once it finds the `foo` package, Bun reads the `package.json` to determine how the package should be imported. Unless `"type": "module"` is specified, Bun assumes the package is using CommonJS and transpiles into a synchronous ES module internally. To determine the package's entrypoint, Bun first reads the `exports` field in and checks the following conditions in order: + +```jsonc#package.json +{ + "name": "foo", + "exports": { + "bun": "./index.js", // highest priority + "worker": "./index.js", + "module": "./index.js", + "node": "./index.js", + "browser": "./index.js", + "default": "./index.js" // lowest priority + } +} +``` + +Bun respects subpath [`"exports"`](https://nodejs.org/api/packages.html#subpath-exports) and [`"imports"`](https://nodejs.org/api/packages.html#imports). Specifying any subpath in the `"exports"` map will prevent other subpaths from being importable. + +```jsonc#package.json +{ + "name": "foo", + "exports": { + ".": "./index.js", + "./package.json": "./package.json" # subpath + } +} +``` + +{% callout %} +**Shipping TypeScript** — Note that Bun supports the special `"bun"` export condition. If your library is written in TypeScript, you can publish your (un-transpiled!) TypeScript files to `npm` directly. If you specify your package's `*.ts` entrypoint in the `"bun"` condition, Bun will directly import and execute your TypeScript source files. +{% /callout %} + +If `exports` is not defined, Bun falls back to `"module"` (ESM imports only) then [`"main"`](https://nodejs.org/api/packages.html#main). + +```json#package.json +{ + "name": "foo", + "module": "./index.js", + "main": "./index.js" +} +``` + +## Path re-mapping + +In the spirit of treating TypeScript as a first-class citizen, the Bun runtime will re-map import paths according to the [`compilerOptions.paths`](https://www.typescriptlang.org/tsconfig#paths) field in `tsconfig.json`. This is a major divergence from Node.js, which doesn't support any form of import path re-mapping. + +```jsonc#tsconfig.json +{ + "compilerOptions": { + "paths": { + "config": ["./config.ts"], // map specifier to file + "components/*": ["components/*"], // wildcard matching + } + } +} +``` + +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. Additional, a symlink is created under `<cache>/<pkg>/<version>` to make it faster to look up all versions of a package 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/nodejs.md b/docs/runtime/nodejs.md new file mode 100644 index 000000000..a394ca3a3 --- /dev/null +++ b/docs/runtime/nodejs.md @@ -0,0 +1,682 @@ +Bun aims for complete Node.js API compatibility. Most `npm` packages intended for `Node.js` environments will work with Bun out of the box; the best way to know for certain is to try it. + +This page is updated regularly to reflect compatibility status of the latest version of Bun. + +## Built-in modules + +{% block className="ScrollFrame" %} +{% table %} + +- Module +- Status +- Notes + +--- + +- {% anchor id="node_assert" %} [`node:assert`](https://nodejs.org/api/assert.html) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_async_hooks" %} [`node:async_hooks`](https://nodejs.org/api/async_hooks.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_buffer" %} [`node:buffer`](https://nodejs.org/api/buffer.html) {% /anchor %} +- 🟡 +- Incomplete implementation of `base64` and `base64url` encodings. + +--- + +- {% anchor id="node_child_process" %} [`node:child_process`](https://nodejs.org/api/child_process.html) {% /anchor %} +- 🟡 +- Missing IPC, `Stream` stdio, `proc.gid`, `proc.uid`, advanced serialization + +--- + +- {% anchor id="node_cluster" %} [`node:cluster`](https://nodejs.org/api/cluster.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_console" %} [`node:console`](https://nodejs.org/api/console.html) {% /anchor %} +- 🟢 +- Recommended to use `console` global instead + +--- + +- {% anchor id="node_crypto" %} [`node:crypto`](https://nodejs.org/api/crypto.html) {% /anchor %} +- 🟡 +- Missing `crypto.Certificate` `crypto.ECDH` `crypto.KeyObject` `crypto.X509Certificate` `crypto.checkPrime{Sync}` `crypto.createPrivateKey` `crypto.createPublicKey` `crypto.createSecretKey` `crypto.diffieHellman` `crypto.generateKey{Sync}` `crypto.generateKeyPair{Sync}` `crypto.generatePrime{Sync}` `crypto.getCipherInfo` `crypto.getCurves` `crypto.{get|set}Fips` `crypto.hkdf` `crypto.hkdfSync` `crypto.randomInt` `crypto.secureHeapUsed` `crypto.setEngine` `crypto.sign` `crypto.verify` + +--- + +- {% anchor id="node_dgram" %} [`node:dgram`](https://nodejs.org/api/dgram.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_diagnostics_channel" %} [`node:diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_dns" %} [`node:dns`](https://nodejs.org/api/dns.html) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_domain" %} [`node:domain`](https://nodejs.org/api/domain.html) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_events" %} [`node:events`](https://nodejs.org/api/events.html) {% /anchor %} +- 🟡 +- Missing `EventEmitterAsyncResource`. `EventEmitter` is missing `{get}set}MaxListeners` `usingDomains` `init`. + +--- + +- {% anchor id="node_fs" %} [`node:fs`](https://nodejs.org/api/fs.html) {% /anchor %} +- 🟡 +- Missing `fs.constants` `fs.fdatasync{Sync}` `fs.opendir{Sync}` `fs.readv{Sync}` `fs.{watch|watchFile|unwatchFile}` `fs.writev{Sync}`. + +--- + +- {% anchor id="node_http" %} [`node:http`](https://nodejs.org/api/http.html) {% /anchor %} +- 🟡 +- Missing `http.Agent` `http.ClientRequest` `http.IncomingMessage` `http.OutgoingMessage` `http.globalAgent` `http.get` `http.maxHeaderSize` `http.request` `http.setMaxIdleHTTPParsers` `http.validateHeader{Name|Value}`. + +--- + +- {% anchor id="node_http2" %} [`node:http2`](https://nodejs.org/api/http2.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_https" %} [`node:https`](https://nodejs.org/api/https.html) {% /anchor %} +- 🟡 +- See `node:http`. + +--- + +- {% anchor id="node_inspector" %} [`node:inspector`](https://nodejs.org/api/inspector.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_module" %} [`node:module`](https://nodejs.org/api/module.html) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_net" %} [`node:net`](https://nodejs.org/api/net.html) {% /anchor %} +- 🟡 +- Missing `net.createServer` `net.{get|set}DefaultAutoSelectFamily` `net.SocketAddress` `net.BlockList`. + +--- + +- {% anchor id="node_os" %} [`node:os`](https://nodejs.org/api/os.html) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_path" %} [`node:path`](https://nodejs.org/api/path.html) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_perf_hooks" %} [`node:perf_hooks`](https://nodejs.org/api/perf_hooks.html) {% /anchor %} +- 🟡 +- Only `perf_hooks.performance.now()` and `perf_hooks.performance.timeOrigin` are implemented. Recommended to use `performance` global instead of `perf_hooks.performance`. + +--- + +- {% anchor id="node_process" %} [`node:process`](https://nodejs.org/api/process.html) {% /anchor %} +- 🟡 +- See `Globals > process`. + +--- + +- {% anchor id="node_punycode" %} [`node:punycode`](https://nodejs.org/api/punycode.html) {% /anchor %} +- 🟢 +- Fully implemented. _Deprecated by Node.js._ + +--- + +- {% anchor id="node_querystring" %} [`node:querystring`](https://nodejs.org/api/querystring.html) {% /anchor %} +- 🟡 +- Missing `querystring.escape` and `querystring.unescape`. + +--- + +- {% anchor id="node_readline" %} [`node:readline`](https://nodejs.org/api/readline.html) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_repl" %} [`node:repl`](https://nodejs.org/api/repl.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_stream" %} [`node:stream`](https://nodejs.org/api/stream.html) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_string_decoder" %} [`node:string_decoder`](https://nodejs.org/api/string_decoder.html) {% /anchor %} +- 🟢 + +--- + +- {% anchor id="node_sys" %} [`node:sys`](https://nodejs.org/api/util.html) {% /anchor %} +- 🟡 +- See `node:util`. + +--- + +- {% anchor id="node_timers" %} [`node:timers`](https://nodejs.org/api/timers.html) {% /anchor %} +- 🟢 +- Recommended to use global `setTimeout`, et. al. instead. + +--- + +- {% anchor id="node_tls" %} [`node:tls`](https://nodejs.org/api/tls.html) {% /anchor %} +- 🟡 +- Missing `tls.Server` `tls.createServer` `tls.createSecurePair` `tls.checkServerIdentity` `tls.rootCertificates` + +--- + +- {% anchor id="node_trace_events" %} [`node:trace_events`](https://nodejs.org/api/tracing.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_tty" %} [`node:tty`](https://nodejs.org/api/tty.html) {% /anchor %} +- 🟡 +- Missing `tty.ReadStream` and `tty.WriteStream`. + +--- + +- {% anchor id="node_url" %} [`node:url`](https://nodejs.org/api/url.html) {% /anchor %} +- 🟡 +- Missing `url.domainTo{ASCII|Unicode}` `url.urlToHttpOptions`. Recommended to use `URL` and `URLSearchParams` globals instead. + +--- + +- {% anchor id="node_util" %} [`node:util`](https://nodejs.org/api/util.html) {% /anchor %} +- 🟡 +- Missing `util.MIMEParams` `util.MIMEType` `util.formatWithOptions()` `util.getSystemErrorMap()` `util.getSystemErrorName()` `util.parseArgs()` `util.stripVTControlCharacters()` `util.toUSVString()` `util.transferableAbortController()` `util.transferableAbortSignal()`. + +--- + +- {% anchor id="node_v8" %} [`node:v8`](https://nodejs.org/api/v8.html) {% /anchor %} +- 🔴 +- Not implemented or planned. For profiling, use `bun:jsc` instead. + +--- + +- {% anchor id="node_vm" %} [`node:vm`](https://nodejs.org/api/vm.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_wasi" %} [`node:wasi`](https://nodejs.org/api/wasi.html) {% /anchor %} +- 🟡 +- Partially implemented. + +--- + +- {% anchor id="node_worker_threads" %} [`node:worker_threads`](https://nodejs.org/api/worker_threads.html) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_zlib" %} [`node:zlib`](https://nodejs.org/api/zlib.html) {% /anchor %} +- 🟡 +- Missing `zlib.brotli*` + +{% /table %} +{% /block %} + +## Globals + +The table below lists all globals implemented by Node.js and Bun's current compatibility status. + +{% table %} + +--- + +- {% anchor id="node_abortcontroller" %} [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_abortsignal" %} [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_blob" %} [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_buffer" %} [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) {% /anchor %} +- 🟡 +- Incomplete implementation of `base64` and `base64url` encodings. + +--- + +- {% anchor id="node_bytelengthqueuingstrategy" %} [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_dirname" %} [`__dirname`](https://nodejs.org/api/globals.html#__dirname) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_filename" %} [`__filename`](https://nodejs.org/api/globals.html#__filename) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_atob" %} [`atob()`](https://developer.mozilla.org/en-US/docs/Web/API/atob) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_broadcastchannel" %} [`BroadcastChannel`](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_btoa" %} [`btoa()`](https://developer.mozilla.org/en-US/docs/Web/API/btoa) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_clearimmediate" %} [`clearImmediate()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearImmediate) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_clearinterval" %} [`clearInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearInterval) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_cleartimeout" %} [`clearTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearTimeout) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_compressionstream" %} [`CompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_console" %} [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_countqueuingstrategy" %} [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_crypto" %} [`Crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_crypto" %} [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/crypto) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_cryptokey" %} [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_customevent" %} [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_decompressionstream" %} [`DecompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_event" %} [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_eventtarget" %} [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_exports" %} [`exports`](https://nodejs.org/api/globals.html#exports) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_fetch" %} [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_formdata" %} [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) {% /anchor %} +- 🟢 +- Fully implemented. Added in Bun 0.7.0. + +--- + +- {% anchor id="node_global" %} [`global`](https://nodejs.org/api/globals.html#global) {% /anchor %} +- 🟢 +- Implemented. This is an object containing all objects in the global namespace. It's rarely referenced directly, as its contents are available without an additional prefix, e.g. `__dirname` instead of `global.__dirname`. + +--- + +- {% anchor id="node_globalthis" %} [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis) {% /anchor %} +- 🟢 +- Aliases to `global`. + +--- + +- {% anchor id="node_headers" %} [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_messagechannel" %} [`MessageChannel`](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_messageevent" %} [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_messageport" %} [`MessagePort`](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_module" %} [`module`](https://nodejs.org/api/globals.html#module) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_performanceentry" %} [`PerformanceEntry`](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_performancemark" %} [`PerformanceMark`](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceMark) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_performancemeasure" %} [`PerformanceMeasure`](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceMeasure) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_performanceobserver" %} [`PerformanceObserver`](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_performanceobserverentrylist" %} [`PerformanceObserverEntryList`](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserverEntryList) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_performanceresourcetiming" %} [`PerformanceResourceTiming`](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_performance" %} [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/performance) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_process" %} [`process`](https://nodejs.org/api/process.html) {% /anchor %} +- 🟡 +- Missing `process.allowedNodeEnvironmentFlags` `process.channel()` `process.connected` `process.constrainedMemory()` `process.cpuUsage()` `process.debugPort` `process.disconnect()` `process.{get|set}ActiveResourcesInfo()` `process.{get|set}{uid|gid|egid|euid|groups}()` `process.hasUncaughtExceptionCaptureCallback` `process.initGroups()` `process.kill()` `process.listenerCount` `process.memoryUsage()` `process.report` `process.resourceUsage()` `process.setSourceMapsEnabled()` `process.send()`. + +--- + +- {% anchor id="node_queuemicrotask" %} [`queueMicrotask()`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_readablebytestreamcontroller" %} [`ReadableByteStreamController`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableByteStreamController) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_readablestream" %} [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_readablestreambyobreader" %} [`ReadableStreamBYOBReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBReader) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_readablestreambyobrequest" %} [`ReadableStreamBYOBRequest`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBRequest) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_readablestreamdefaultcontroller" %} [`ReadableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultController) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_readablestreamdefaultreader" %} [`ReadableStreamDefaultReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_require" %} [`require()`](https://nodejs.org/api/globals.html#require) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_response" %} [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_request" %} [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_setimmediate" %} [`setImmediate()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_setinterval" %} [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_settimeout" %} [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_structuredclone" %} [`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_subtlecrypto" %} [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_domexception" %} [`DOMException`](https://developer.mozilla.org/en-US/docs/Web/API/DOMException) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_textdecoder" %} [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_textdecoderstream" %} [`TextDecoderStream`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoderStream) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_textencoder" %} [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_textencoderstream" %} [`TextEncoderStream`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoderStream) {% /anchor %} +- 🔴 +- Not implemented. + +--- + +- {% anchor id="node_transformstream" %} [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_transformstreamdefaultcontroller" %} [`TransformStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStreamDefaultController) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_url" %} [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_urlsearchparams" %} [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_webassembly" %} [`WebAssembly`](https://nodejs.org/api/globals.html#webassembly) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_writablestream" %} [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_writablestreamdefaultcontroller" %} [`WritableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultController) {% /anchor %} +- 🟢 +- Fully implemented. + +--- + +- {% anchor id="node_writablestreamdefaultwriter" %} [`WritableStreamDefaultWriter`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter) {% /anchor %} +- 🟢 +- Fully implemented. + +{% /table %} diff --git a/docs/runtime/plugins.md b/docs/runtime/plugins.md new file mode 100644 index 000000000..c19ea9145 --- /dev/null +++ b/docs/runtime/plugins.md @@ -0,0 +1,245 @@ +{% callout %} +**Note** — Introduced in Bun v0.1.11. +{% /callout %} + +Bun's runtime can be extended to support additional file types using _plugins_. Plugins can intercept imports and perform custom loading logic: reading files, transpiling code, etc. They can be used to extend Bun's runtime with _loaders_ for additional file types. + +## Usage + +A plugin is defined as simple JavaScript object containing a `name` property and a `setup` function. Register a plugin with Bun using the `plugin` function. + +```tsx#yamlPlugin.ts +import { plugin } from "bun"; + +plugin({ + name: "YAML loader", + setup(build) { + // implementation + }, +}); +``` + +To consume this plugin, import it at the top of your project's entrypoint, before any application code is imported. + +```ts#app.ts +import "./yamlPlugin.ts"; +import { config } from "./config.yml"; + +console.log(config); +``` + +By convention, third-party plugins intended for consumption should export a factory function that accepts some configuration and returns a plugin object. + +```ts +import { plugin } from "bun"; +import fooPlugin from "bun-plugin-foo"; + +plugin( + fooPlugin({ + // configuration + }), +); + +// application code +``` + +Bun's plugin API is based on [esbuild](https://esbuild.github.io/plugins). Only a subset of the esbuild API is implemented, but some esbuild plugins "just work" in Bun, like the official [MDX loader](https://mdxjs.com/packages/esbuild/): + +```jsx +import { plugin } from "bun"; +import mdx from "@mdx-js/esbuild"; + +plugin(mdx()); + +import { renderToStaticMarkup } from "react-dom/server"; +import Foo from "./bar.mdx"; +console.log(renderToStaticMarkup(<Foo />)); +``` + +## Loaders + +<!-- The plugin logic is implemented in the `setup` function using the builder provided as the first argument (`build` in the example above). The `build` variable provides two methods: `onResolve` and `onLoad`. --> + +<!-- ## `onResolve` --> + +<!-- The `onResolve` method lets you intercept imports that match a particular regex and modify the resolution behavior, such as re-mapping the import to another file. In the simplest case, you can simply remap the matched import to a new path. + +```ts +import { plugin } from "bun"; + +plugin({ + name: "YAML loader", + setup(build) { + build.onResolve(); + // implementation + }, +}); +``` --> + +<!-- +Internally, Bun's transpiler automatically turns `plugin()` calls into separate files (at most 1 per file). This lets loaders activate before the rest of your application runs with zero configuration. --> + +Plugins are primarily used to extend Bun with loaders for additional file types. Let's look at a simple plugin that exposes envLet's look at a sample plugin that implements a loader for `.yaml` files. + +```ts#yamlPlugin.ts +import { plugin } from "bun"; + +plugin({ + name: "YAML", + async setup(build) { + const { load } = await import("js-yaml"); + const { readFileSync } = await import("fs"); + + // when a .yaml file is imported... + build.onLoad({ filter: /\.(yaml|yml)$/ }, (args) => { + + // read and parse the file + const text = readFileSync(args.path, "utf8"); + const exports = load(text) as Record<string, any>; + + // and returns it as a module + return { + exports, + loader: "object", // special loader for JS objects + }; + }); + }, +}); +``` + +With this plugin, data can be directly imported from `.yaml` files. + +{% codetabs %} + +```ts#index.ts +import "./yamlPlugin.ts" +import {name, releaseYear} from "./data.yml" + +console.log(name, releaseYear); +``` + +```yaml#data.yml +name: Fast X +releaseYear: 2023 +``` + +{% /codetabs %} + +Note that the returned object has a `loader` property. This tells Bun which of its internal loaders should be used to handle the result. Even though we're implementing a loader for `.yaml`, the result must still be understandable by one of Bun's built-in loaders. It's loaders all the way down. + +In this case we're using `"object"`—a special loader (intended for use by plugins) that converts a plain JavaScript object to an equivalent ES module. Any of Bun's built-in loaders are supported; these same loaders are used by Bun internally for handling files of various extensions. + +{% table %} + +- Loader +- Extensions +- Output + +--- + +- `js` +- `.js` `.mjs` `.cjs` +- Transpile to JavaScript files + +--- + +- `jsx` +- `.jsx` +- Transform JSX then transpile + +--- + +- `ts` +- `.ts` `.mts` `cts` +- Transform TypeScript then transpile + +--- + +- `tsx` +- `.tsx` +- Transform TypeScript, JSX, then transpile + +--- + +- `toml` +- `.toml` +- Parse using Bun's built-in TOML parser + +--- + +- `json` +- `.json` +- Parse using Bun's built-in JSON parser + +--- + +- `object` +- — +- A special loader intended for plugins that converts a plain JavaScript object to an equivalent ES module. Each key in the object corresponds to a named export. + +{% /callout %} + +Loading a YAML file is useful, but plugins support more than just data loading. Lets look at a plugin that lets Bun import `*.svelte` files. + +```ts#sveltePlugin.ts +import { plugin } from "bun"; + +await plugin({ + name: "svelte loader", + async setup(build) { + const { compile } = await import("svelte/compiler"); + const { readFileSync } = await import("fs"); + + // when a .svelte file is imported... + build.onLoad({ filter: /\.svelte$/ }, ({ path }) => { + + // read and compile it with the Svelte compiler + const file = readFileSync(path, "utf8"); + const contents = compile(file, { + filename: path, + generate: "ssr", + }).js.code; + + // and return the compiled source code as "js" + return { + contents, + loader: "js", + }; + }); + }, +}); +``` + +> Note: in a production implementation, you'd want to cache the compiled output and include additional error handling. + +The object returned from `build.onLoad` contains the compiled source code in `contents` and specifies `"js"` as its loader. That tells Bun to consider the returned `contents` to be a JavaScript module and transpile it using Bun's built-in `js` loader. + +With this plugin, Svelte components can now be directly imported and consumed. + +```js +import "./sveltePlugin.ts"; +import MySvelteComponent from "./component.svelte"; + +console.log(mySvelteComponent.render()); +``` + +## Reference + +```ts +namespace Bun { + function plugin(plugin: { name: string; setup: (build: PluginBuilder) => void }): void; +} + +type PluginBuilder = { + onLoad: ( + args: { filter: RegExp; namespace?: string }, + callback: (args: { path: string }) => { + loader?: "js" | "jsx" | "ts" | "tsx" | "json" | "yaml" | "object"; + contents?: string; + exports?: Record<string, any>; + }, + ) => void; +}; +``` + +The `onLoad` method optionally accepts a `namespace` in addition to the `filter` regex. This namespace will be be used to prefix the import in transpiled code; for instance, a loader with a `filter: /\.yaml$/` and `namespace: "yaml:"` will transform an import from `./myfile.yaml` into `yaml:./myfile.yaml`. diff --git a/docs/runtime/streams.md b/docs/runtime/streams.md deleted file mode 100644 index 733b99799..000000000 --- a/docs/runtime/streams.md +++ /dev/null @@ -1,5 +0,0 @@ -# Streams in Bun - -Bun supports Web Streams ([`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) and [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) first and partially supports Node.js [`"stream"`](https://nodejs.org/api/stream.html). - -## `ReadableStream` diff --git a/docs/runtime/web-apis.md b/docs/runtime/web-apis.md new file mode 100644 index 000000000..ebe0e6041 --- /dev/null +++ b/docs/runtime/web-apis.md @@ -0,0 +1,300 @@ +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. + +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) + +--- + +- 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) + +--- + +- 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) + +--- + +- [`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) + +--- + +- [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa) + +--- + +- [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) + +--- + +- [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) + +--- + +- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) + +--- + +- [`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) + +--- + +- [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) and [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) + +--- + +--- + +- [`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) + +--- + +- [`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) + +--- + +- [`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 %} --> |