diff options
Diffstat (limited to 'docs/runtime')
-rw-r--r-- | docs/runtime/bunfig.md | 429 | ||||
-rw-r--r-- | docs/runtime/configuration.md | 210 | ||||
-rw-r--r-- | docs/runtime/env.md | 147 | ||||
-rw-r--r-- | docs/runtime/hot.md | 21 | ||||
-rw-r--r-- | docs/runtime/jsx.md | 4 | ||||
-rw-r--r-- | docs/runtime/modules.md | 189 | ||||
-rw-r--r-- | docs/runtime/nodejs-apis.md | 725 | ||||
-rw-r--r-- | docs/runtime/plugins.md | 104 | ||||
-rw-r--r-- | docs/runtime/typescript.md | 109 |
9 files changed, 844 insertions, 1094 deletions
diff --git a/docs/runtime/bunfig.md b/docs/runtime/bunfig.md new file mode 100644 index 000000000..6950d8233 --- /dev/null +++ b/docs/runtime/bunfig.md @@ -0,0 +1,429 @@ +Bun's behavior can be configured using its configuration file, `bunfig.toml`. + +In general, Bun relies on pre-existing configuration files like `package.json` and `tsconfig.json` to configure its behavior. `bunfig.toml` is only necessary for configuring Bun-specific things. This file is optional, and Bun will work out of the box without it. + +## Global vs. local + +In general, it's recommended to add a `bunfig.toml` file to your project root, alongside your `package.json`. + +To configure Bun globally, you can also create a `.bunfig.toml` file at one of 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 overriding global. CLI flags will override `bunfig` setting where applicable. + +## Runtime + +Bun's runtime behavior is configured using top-level fields in the `bunfig.toml` file. + +### `preload` + +An array of scripts/plugins to execute before running a file or script. + +```toml +# scripts to run before `bun run`-ing a file or script +# register plugins by adding them to this list +preload = ["./preload.ts"] +``` + +### `jsx` + +Configure how Bun handles JSX. You can also set these fields in the `compilerOptions` of your `tsconfig.json`, but they are supported here as well for non-TypeScript projects. + +```toml +jsx = "react" +jsxFactory = "h" +jsxFragment = "Fragment" +jsxImportSource = "react" +``` + +Refer to the tsconfig docs for more information on these fields. + +- [jsx](https://www.typescriptlang.org/tsconfig#jsx) +- [jsxFactory](https://www.typescriptlang.org/tsconfig#jsxFactory) +- [jsxFragment](https://www.typescriptlang.org/tsconfig#jsxFragment) +- [jsxImportSource](https://www.typescriptlang.org/tsconfig#jsxImportSource) + +### `smol` + +Enable `smol` mode. This reduces memory usage at the cost of performance. + +```toml +# Reduce memory usage at the cost of performance +smol = true +``` + +### `logLevel` + +Set the log level. This can be one of `"debug"`, `"warn"`, or `"error"`. + +```toml +logLevel = "debug" # "debug" | "warn" | "error" +``` + +### `define` + +The `define` field allows you to replace certain global identifiers with constant expressions. Bun will replace any usage of the identifier with the expression. The expression should be a JSON string. + +```toml +[define] +# Replace any usage of "process.env.bagel" with the string `lox`. +# The values are parsed as JSON, except single-quoted strings are supported and `'undefined'` becomes `undefined` in JS. +# This will probably change in a future release to be just regular TOML instead. It is a holdover from the CLI argument parsing. +"process.env.bagel" = "'lox'" +``` + +### `loader` + +Configure how Bun maps file extensions to loaders. This is useful for loading files that aren't natively supported by Bun. If + +```toml +[loader] +# when a .bagel file is imported, treat it like a tsx file +".bagel" = "tsx" +``` + +Bun supports the following loaders: + +- `jsx` +- `js` +- `ts` +- `tsx` +- `css` +- `file` +- `json` +- `toml` +- `wasm` +- `napi` +- `base64` +- `dataurl` +- `text` + +### `telemetry` + +The `telemetry` field permit to enable/disable the analytics records. 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. By default the telemetry is enabled. Equivalent of `DO_NOT_TRACK` env variable. + +```toml +telemetry = false +``` + +## Test runner + +The test runner is configured under the `[test]` section of your bunfig.toml. + +```toml +[test] +# configuration goes here +``` + +### `test.root` + +The root directory to run tests from. Default `.`. + +```toml +[test] +root = "./__tests__" +``` + +### `test.preload` + +Same as the top-level `preload` field, but only applies to `bun test`. + +```toml +[test] +preload = ["./setup.ts"] +``` + +### `test.smol` + +Same as the top-level `smol` field, but only applies to `bun test`. + +```toml +[test] +smol = true +``` + +### `test.coverage` + +Enables coverage reporting. Default `false`. Use `--coverage` to override. + +```toml +[test] +coverage = false +``` + +### `test.coverageThreshold` + +To specify a coverage threshold. By default, no threshold is set. If your test suite does not meet or exceed this threshold, `bun test` will exit with a non-zero exit code to indicate the failure. + +```toml +[test] + +# to require 90% line-level and function-level coverage +coverageThreshold = 0.9 +``` + +Different thresholds can be specified for line-wise, function-wise, and statement-wise coverage. + +```toml +[test] +coverageThreshold = { line = 0.7, function = 0.8, statement = 0.9 } +``` + +### `test.coverageSkipTestFiles` + +Whether to skip test files when computing coverage statistics. Default `false`. + +```toml +[test] +coverageSkipTestFiles = false +``` + +## Package manager + +Package management is a complex issue; to support a range of use cases, the behavior of `bun install` can be configured under the `[install]` section. + +```toml +[install] +# configuration here +``` + +### `install.optional` + +Whether to install optional dependencies. Default `true`. + +```toml +[install] +optional = true +``` + +### `install.dev` + +Whether to install development dependencies. Default `true`. + +```toml +[install] +dev = true +``` + +### `install.peer` + +Whether to install peer dependencies. Default `true`. + +```toml +[install] +peer = false +``` + +### `install.production` + +Whether `bun install` will run in "production mode". Default `false`. + +In production mode, `"devDependencies"` are not installed. You can use `--production` in the CLI to override this setting. + +```toml +[install] +production = false +``` + +### `install.exact` + +Whether to set an exact version in `package.json`. Default `false`. + +By default Bun uses caret ranges; if the `latest` version of a package is `2.4.1`, the version range in your `package.json` will be `^2.4.1`. This indicates that any version from `2.4.1` up to (but not including) `3.0.0` is acceptable. + +```toml +[install] +exact = false +``` + +<!-- +### `install.prefer` + +Whether the package manager should prefer offline or online dependency resolution. Default `"online"`. + +```toml +[install] +prefer = "online" +``` + +Valid values are: + +{% table %} + +--- + +- `"online"` +- Prefer online resolution. This is the default. If a package is not found in the local cache, it will be downloaded from the registry. + +--- + +- `"offline"` +- Prefer offline resolution. When possible, packages will be installed from the global cache. This minimizes the fraction of the time Bun will check for newer versions from the registry. If a package is not found in the global cache, it will be downloaded from the registry. + +{% /table %} --> + +### `install.auto` + +To configure Bun's package auto-install behavior. Default `"auto"` β when no `node_modules` folder is found, Bun will automatically install dependencies on the fly during execution. + +```toml +[install] +auto = "auto" +``` + +Valid values are: + +{% table %} + +- Value +- Description + +--- + +- `"auto"` +- Resolve modules from local `node_modules` if it exists. Otherwise, auto-install dependencies on the fly. + +--- + +- `"force"` +- Always auto-install dependencies, even if `node_modules` exists. + +--- + +- `"disable"` +- Never auto-install dependencies. + +--- + +- `"fallback"` +- Check local `node_modules` first, the auto-install any packages that aren't found. You can enable this from the CLI with `bun -i`. + +{% /table %} + +### `install.frozenLockfile` + +When true, `bun install` will not update `bun.lockb`. Default `false`. If `package.json` and the existing `bun.lockb` are not in agreement, this will error. + +```toml +[install] +frozenLockfile = false +``` + +### `install.dryRun` + +Whether to install optional dependencies. Default `false`. When true, it's equivalent to setting `--dry-run` on all `bun install` commands. + +```toml +[install] +dryRun = false +``` + +### `install.globalDir` + +To configure the directory where Bun puts globally installed packages. + +```toml +[install] +# where `bun install --global` installs packages +globalDir = "~/.bun/install/global" +``` + +### `install.globalBinDir` + +To configure the directory where Bun installs globally installed binaries and CLIs. + +```toml +# where globally-installed package bins are linked +globalBinDir = "~/.bun/bin" +``` + +### `install.registry` + +The default registry is `https://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" +``` + +### `install.scopes` + +To configure a registry for a particular scope (e.g. `@myorg/<package>`) use `install.scopes`. You can reference environment variables with `$variable` notation. + +```toml +[install.scopes] +# registry as string +myorg = "https://username:password@registry.myorg.com/" + +# registry with username/password +# you can reference environment variables +myorg = { username = "myusername", password = "$npm_password", url = "https://registry.myorg.com/" } + +# registry with token +myorg = { token = "$npm_token", url = "https://registry.myorg.com/" } +``` + +### `install.cache` + +To configure the 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 +``` + +### `install.lockfile` + +To configure lockfile behavior, use the `install.lockfile` section. + +Whether to generate a lockfile on `bun install`. Default `true`. + +```toml +[install.lockfile] +save = true +``` + +Whether to generate a non-Bun lockfile alongside `bun.lockb`. (A `bun.lockb` will always be created.) Currently `"yarn"` is the only supported value. + +```toml +[install.lockfile] +print = "yarn" +``` + +<!-- ## Debugging --> + +<!-- +```toml +[debug] +# When navigating to a blob: or src: link, open the file in your editor +# If not, it tries $EDITOR or $VISUAL +# If that still fails, it will try Visual Studio Code, then Sublime Text, then a few others +# This is used by Bun.openInEditor() +editor = "code" + +# List of editors: +# - "subl", "sublime" +# - "vscode", "code" +# - "textmate", "mate" +# - "idea" +# - "webstorm" +# - "nvim", "neovim" +# - "vim","vi" +# - "emacs" +``` --> diff --git a/docs/runtime/configuration.md b/docs/runtime/configuration.md deleted file mode 100644 index 96385b87d..000000000 --- a/docs/runtime/configuration.md +++ /dev/null @@ -1,210 +0,0 @@ -There are two primary mechanisms for configuring the behavior of Bun. - -- environment variables -- `bunfig.toml`: Bun's configuration file - -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`. - -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. - -## Runtime - -```toml -# scripts to run before `bun run`ning a file or script -# useful for registering plugins -preload = ["./preload.ts"] - -# equivalent to corresponding tsconfig compilerOptions -jsx = "react" -jsxFactory = "h" -jsxFragment = "Fragment" -jsxImportSource = "react" - -# Reduce memory usage at the cost of performance -smol = true - -# Set Bun's log level -logLevel = "debug" # "debug", "warn", "error" - -[define] -# Replace any usage of "process.env.bagel" with the string `lox`. -# The values are parsed as JSON, except single-quoted strings are supported and `'undefined'` becomes `undefined` in JS. -# This will probably change in a future release to be just regular TOML instead. It is a holdover from the CLI argument parsing. -"process.env.bagel" = "'lox'" - -[loader] -# When loading a .bagel file, run the JS parser -".bagel" = "js" -``` - -## Test runner - -```toml -[test] -# Scripts to run before all test files -preload = ["./setup.ts"] - -# Reduce memory usage at the cost of performance -smol = true -``` - -## Package manager - -Package management is a complex issue; to support a range of use cases, the behavior of `bun install` can be configured in [`bunfig.toml`](/docs/runtime/configuration). - -### Default flags - -The following settings modify the core behavior of Bun's package management commands. **The default values are shown below.** - -```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 `--frozen-lockfile` flag -frozenLockfile = false - -# equivalent to `--dry-run` flag -dryRun = false -``` - -### Private scopes and registries - -The default registry is `https://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 scoped registries: - -```toml -[install.scopes] -# registry as string -myorg1 = "https://username:password@registry.myorg.com/" - -# registry with username/password -# you can reference environment variables -myorg12 = { username = "myusername", password = "$NPM_PASS", url = "https://registry.myorg.com/" } - -# registry with token -myorg3 = { token = "$npm_token", url = "https://registry.myorg.com/" } -``` - -### Cache - -To configure caching behavior: - -```toml -[install] -# where `bun install --global` installs packages -globalDir = "~/.bun/install/global" - -# where globally-installed package bins are linked -globalBinDir = "~/.bun/bin" - -[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 -``` - -### Lockfile - -To configure lockfile behavior: - -```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" -``` - -### Debugging - -```toml -[debug] -# When navigating to a blob: or src: link, open the file in your editor -# If not, it tries $EDITOR or $VISUAL -# If that still fails, it will try Visual Studio Code, then Sublime Text, then a few others -# This is used by Bun.openInEditor() -editor = "code" - -# List of editors: -# - "subl", "sublime" -# - "vscode", "code" -# - "textmate", "mate" -# - "idea" -# - "webstorm" -# - "nvim", "neovim" -# - "vim","vi" -# - "emacs" -``` - -## Environment variables - -These environment variables are checked by Bun to detect functionality and toggle features. - -{% table %} - -- Name -- Description - ---- - -- `TMPDIR` -- Bun occasionally requires a directory to store intermediate assets during bundling or other operations. If unset, defaults to the platform-specific temporary directory: `/tmp` on Linux, `/private/tmp` on macOS. - ---- - -- `NO_COLOR` -- If `NO_COLOR=1`, then ANSI color output is [disabled](https://no-color.org/). - ---- - -- `FORCE_COLOR` -- If `FORCE_COLOR=1`, then ANSI color output is force enabled, even if `NO_COLOR` is set. - ---- - -- `DO_NOT_TRACK` -- If `DO_NOT_TRACK=1`, then analytics are [disabled](https://do-not-track.dev/). 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. - -{% /table %} diff --git a/docs/runtime/env.md b/docs/runtime/env.md new file mode 100644 index 000000000..e38eabffd --- /dev/null +++ b/docs/runtime/env.md @@ -0,0 +1,147 @@ +Bun reads your `.env` files automatically and provides idiomatic ways to read and write your environment variables programmatically. Plus, some aspects of Bun's runtime behavior can be configured with Bun-specific environment variables. + +## Setting environment variables + +Bun reads the following files automatically (listed in order of increasing precedence). + +- `.env` +- `.env.production`, `.env.development`, `.env.test` (depending on value of `NODE_ENV`) +- `.env.local` + +```txt#.env +FOO=hello +BAR=world +``` + +Variables can also be set via the command line. + +```sh +$ FOO=helloworld bun run dev +``` + +Or programmatically by assigning a property to `process.env`. + +```ts +process.env.FOO = "hello"; +``` + +### Quotation marks + +Bun supports double quotes, single quotes, and + +### Expansion + +Environment variables are automatically _expanded_. This means you can reference previously-defined variables in your environment variables. + +```txt#.env +FOO=world +BAR=hello$FOO +``` + +```ts +process.env.BAR; // => "helloworld" +``` + +This is useful for constructing connection strings or other compound values. + +```txt#.env +DB_USER=postgres +DB_PASSWORD=secret +DB_HOST=localhost +DB_PORT=5432 +DB_URL=postgres://$DB_USER:$DB_PASSWORD@$DB_HOST:$DB_PORT/$DB_NAME +``` + +This can be disabled by escaping the `$` with a backslash. + +```txt#.env +FOO=world +BAR=hello\$FOO +``` + +```ts +process.env.BAR; // => "hello$FOO" +``` + +### `dotenv` + +Generally speaking, you won't need `dotenv` or `dotenv-expand` anymore, because Bun reads `.env` files automatically. + +## Reading environment variables + +The current environment variables can be accessed via `process.env`. + +```ts +process.env.API_TOKEN; // => "secret" +``` + +Bun also exposes these variables via `Bun.env`, which is a simple alias of `process.env`. + +```ts +Bun.env.API_TOKEN; // => "secret" +``` + +To print all currently-set environment variables to the command line, run `bun run env`. This is useful for debugging. + +```sh +$ bun run env +BAZ=stuff +FOOBAR=aaaaaa +<lots more lines> +``` + +## TypeScript + +In TypeScript, all properties of `process.env` are typed as `string | undefined`. + +```ts +Bun.env.whatever; +// string | undefined +``` + +To get autocompletion and tell TypeScript to treat a variable as a non-optional string, we'll use [interface merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces). + +```ts +declare module "bun" { + interface Env { + AWESOME: string; + } +} +``` + +Add this line to any file in your project. It will globally add the `AWESOME` property to `process.env` and `Bun.env`. + +```ts +process.env.AWESOME; // => string +``` + +## Configuring Bun + +These environment variables are read by Bun and configure aspects of its behavior. + +{% table %} + +- Name +- Description + +--- + +- `TMPDIR` +- Bun occasionally requires a directory to store intermediate assets during bundling or other operations. If unset, defaults to the platform-specific temporary directory: `/tmp` on Linux, `/private/tmp` on macOS. + +--- + +- `NO_COLOR` +- If `NO_COLOR=1`, then ANSI color output is [disabled](https://no-color.org/). + +--- + +- `FORCE_COLOR` +- If `FORCE_COLOR=1`, then ANSI color output is force enabled, even if `NO_COLOR` is set. + +--- + +- `DO_NOT_TRACK` +- If `DO_NOT_TRACK=1`, then analytics are [disabled](https://do-not-track.dev/). 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. Equivalent of `telemetry=false` in bunfig. + +{% /table %} diff --git a/docs/runtime/hot.md b/docs/runtime/hot.md index 07f3f0f66..c54868689 100644 --- a/docs/runtime/hot.md +++ b/docs/runtime/hot.md @@ -1,6 +1,6 @@ Bun supports two kinds of automatic reloading via CLI flags: -- `--watch` mode, which hard restarts Bun's process when imported files change/ +- `--watch` mode, which hard restarts Bun's process when imported files change. - `--hot` mode, which soft reloads the code (without restarting the process) when imported files change. ## `--watch` mode @@ -52,6 +52,7 @@ serve({ {% /codetabs %} +In this example, Bun is  Running `bun test` in watch mode and `save-on-keypress` enabled: @@ -64,7 +65,9 @@ $ bun --watch test ## `--hot` mode -Use `bun --hot` to enable hot reloading when executing code with Bun. +Use `bun --hot` to enable hot reloading when executing code with Bun. This is distinct from `--watch` mode in that Bun does not hard-restart the entire process. Instead, it detects code changes and updates its internal module cache with the new code. + +**Note** β This is not the same as hot reloading in the browser! Many frameworks provide a "hot reloading" experience, where you can edit & save your frontend code (say, a React component) and see the changes reflected in the browser without refreshing the page. Bun's `--hot` is the server-side equivalent of this experience. To get hot reloading in the browser, use a framework like [Vite](https://vitejs.dev). ```bash $ bun --hot server.ts @@ -99,15 +102,13 @@ Traditional file watchers like `nodemon` restart the entire process, so HTTP ser ### HTTP servers -Bun provides the following simplified API for implementing HTTP servers. Refer to [API > HTTP](/docs/api/http) for full details. +This makes it possible, for instance, to update your HTTP request handler without shutting down the server itself. When you save the file, your HTTP server will be reloaded with the updated code without the process being restarted. This results in seriously fast refresh speeds. ```ts#server.ts -import {serve} from "bun"; - globalThis.count ??= 0; globalThis.count++; -serve({ +Bun.serve({ fetch(req: Request) { return new Response(`Reloaded ${globalThis.count} times`); }, @@ -115,18 +116,16 @@ serve({ }); ``` -The file above is simply exporting an object with a `fetch` handler defined. When this file is executed, Bun interprets this as an HTTP server and passes the exported object into `Bun.serve`. - -When you save the file, your HTTP server be reloaded with the updated code without the process being restarted. This results in seriously fast refresh speeds. +<!-- 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`. --> -{% 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." /%} +<!-- {% 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." /%} --> {% 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`" %} +{% details summary="Implementation details" %} On hot reload, Bun: diff --git a/docs/runtime/jsx.md b/docs/runtime/jsx.md index ab9a14a8d..31a61652b 100644 --- a/docs/runtime/jsx.md +++ b/docs/runtime/jsx.md @@ -14,7 +14,7 @@ console.log(<Component message="Hello world!" />); ## Configuration -Bun reads your `tsconfig.json` or `jsconfig.json` configuration files to determines how to perform the JSX transform internally. To avoid using either of these, the following options can also be defined in [`bunfig.toml`](/docs/runtime/configuration). +Bun reads your `tsconfig.json` or `jsconfig.json` configuration files to determines how to perform the JSX transform internally. To avoid using either of these, the following options can also be defined in [`bunfig.toml`](/docs/runtime/bunfig). The following compiler options are respected. @@ -175,7 +175,7 @@ The function name used to represent [JSX fragments](https://react.dev/reference/ // output import { myjsx, MyFragment } from "react"; - createElement("Box", { width: 5 }, "Hello"); + myjsx(MyFragment, null, "Hello"); ``` {% /table %} diff --git a/docs/runtime/modules.md b/docs/runtime/modules.md index 380903c6f..486ddea5f 100644 --- a/docs/runtime/modules.md +++ b/docs/runtime/modules.md @@ -24,24 +24,29 @@ export function hello() { {% /codetabs %} -When we run `index.ts`, it prints "Hello world". +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: +In this case, we are importing from `./hello`, a relative path with no extension. **Extensioned imports are optional but supported.** To resolve this import, Bun will check for the following files in order: -- `./hello.ts` - `./hello.tsx` -- `./hello.js` +- `./hello.jsx` +- `./hello.ts` - `./hello.mjs` +- `./hello.js` - `./hello.cjs` +- `./hello.json` +- `./hello/index.tsx` +- `./hello/index.jsx` - `./hello/index.ts` +- `./hello/index.mjs` - `./hello/index.js` +- `./hello/index.cjs` - `./hello/index.json` -- `./hello/index.mjs` Import paths are case-insensitive, meaning these are all valid imports: @@ -58,7 +63,7 @@ import { hello } from "./hello"; import { hello } from "./hello.ts"; // this works ``` -There is one exception: if you import `from "*.js{x}"`, Bun will additionally check for a matching `*.ts{x}` file, to be compatible with TypeScript's [ES module support](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#new-file-extensions). +If you import `from "*.js{x}"`, Bun will additionally check for a matching `*.ts{x}` file, to be compatible with TypeScript's [ES module support](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#new-file-extensions). ```ts#index.ts import { hello } from "./hello"; @@ -88,7 +93,86 @@ exports.hello = hello; That said, using CommonJS is discouraged in new projects. -## Resolution +## Module systems + +Bun has native support for CommonJS and ES modules. ES Modules are the recommended module format for new projects, but CommonJS modules are still widely used in the Node.js ecosystem. + +In Bun's JavaScript runtime, `require` can be used by both ES Modules and CommonJS modules. If the target module is an ES Module, `require` returns the module namespace object (equivalent to `import * as`). If the target module is a CommonJS module, `require` returns the `module.exports` object (as in Node.js). + +| Module Type | `require()` | `import * as` | +| ----------- | ---------------- | ----------------------------------------------------------------------- | +| ES Module | Module Namespace | Module Namespace | +| CommonJS | module.exports | `default` is `module.exports`, keys of module.exports are named exports | + +### Using `require()` + +You can `require()` any file or package, even `.ts` or `.mjs` files. + +```ts +const { foo } = require("./foo"); // extensions are optional +const { bar } = require("./bar.mjs"); +const { baz } = require("./baz.tsx"); +``` + +{% details summary="What is a CommonJS module?" %} + +In 2016, ECMAScript added support for [ES Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). ES Modules are the standard for JavaScript modules. However, millions of npm packages still use CommonJS modules. + +CommonJS modules are modules that use `module.exports` to export values. Typically, `require` is used to import CommonJS modules. + +```ts +// my-commonjs.cjs +const stuff = require("./stuff"); +module.exports = { stuff }; +``` + +The biggest difference between CommonJS and ES Modules is that CommonJS modules are synchronous, while ES Modules are asynchronous. There are other differences too. + +- ES Modules support top-level `await` and CommonJS modules don't. +- ES Modules are always in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), while CommonJS modules are not. +- Browsers do not have native support for CommonJS modules, but they do have native support for ES Modules via `<script type="module">`. +- CommonJS modules are not statically analyzable, while ES Modules only allow static imports and exports. + +**CommonJS Modules:** These are a type of module system used in JavaScript. One key feature of CommonJS modules is that they load and execute synchronously. This means that when you import a CommonJS module, the code in that module runs immediately, and your program waits for it to finish before moving on to the next task. It's similar to reading a book from start to finish without skipping pages. + +**ES Modules (ESM):** These are another type of module system introduced in JavaScript. They have a slightly different behavior compared to CommonJS. In ESM, static imports (imports made using `import` statements) are synchronous, just like CommonJS. This means that when you import an ESM using a regular `import` statement, the code in that module runs immediately, and your program proceeds in a step-by-step manner. Think of it like reading a book page by page. + +**Dynamic imports:** Now, here comes the part that might be confusing. ES Modules also support importing modules on the fly via the `import()` function. This is called a "dynamic import" and it's asynchronous, so it doesn't block the main program execution. Instead, it fetches and loads the module in the background while your program continues to run. Once the module is ready, you can use it. This is like getting additional information from a book while you're still reading it, without having to pause your reading. + +**In summary:** + +- CommonJS modules and static ES Modules (`import` statements) work in a similar synchronous way, like reading a book from start to finish. +- ES Modules also offer the option to import modules asynchronously using the `import()` function. This is like looking up additional information in the middle of reading the book without stopping. + +{% /details %} + +### Using `import` + +You can `import` any file or package, even `.cjs` files. + +```ts +import { foo } from "./foo"; // extensions are optional +import bar from "./bar.ts"; +import { stuff } from "./my-commonjs.cjs"; +``` + +### Using `import` and `require()` together + +In Bun, you can use `import` or `require` in the same fileβthey both work, all the time. + +```ts +import { stuff } from "./my-commonjs.cjs"; +import Stuff from "./my-commonjs.cjs"; +const myStuff = require("./my-commonjs.cjs"); +``` + +### Top level await + +The only exception to this rule is top-level await. You can't `require()` a file that uses top-level await, since the `require()` function is inherently synchronous. + +Fortunately, very few libraries use top-level await, so this is rarely a problem. But if you're using top-level await in your application code, make sure that file isn't being `require()` from elsewhere in your application. Instead, you should use `import` or [dynamic `import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import). + +## Importing packages Bun implements the Node.js module resolution algorithm, so you can import packages from `node_modules` with a bare specifier. @@ -107,8 +191,8 @@ Once it finds the `foo` package, Bun reads the `package.json` to determine how t "bun": "./index.js", "worker": "./index.js", "node": "./index.js", - "require": "./index.js", # if importer is CommonJS - "import": "./index.mjs", # if importer is ES module + "require": "./index.js", // if importer is CommonJS + "import": "./index.mjs", // if importer is ES module "default": "./index.js", } } @@ -116,18 +200,38 @@ Once it finds the `foo` package, Bun reads the `package.json` to determine how t Whichever one of these conditions occurs _first_ in the `package.json` is used to determine the package's entrypoint. -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. +Bun respects subpath [`"exports"`](https://nodejs.org/api/packages.html#subpath-exports) and [`"imports"`](https://nodejs.org/api/packages.html#imports). ```jsonc#package.json { "name": "foo", "exports": { - ".": "./index.js", - "./package.json": "./package.json" // subpath + ".": "./index.js" } } ``` +Subpath imports and conditional imports work in conjunction with each other. + +```json +{ + "name": "foo", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + } + } +} +``` + +As in Node.js, Specifying any subpath in the `"exports"` map will prevent other subpaths from being importable; you can only import files that are explicitly exported. Given the `package.json` above: + +```ts +import stuff from "foo"; // this works +import stuff from "foo/index.mjs"; // this doesn't +``` + {% 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 %} @@ -159,67 +263,6 @@ In the spirit of treating TypeScript as a first-class citizen, the Bun runtime w If you aren't a TypeScript user, you can create a [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) in your project root to achieve the same behavior. -## CommonJS - -Bun has native support for CommonJS modules. ES Modules are the recommended module format, but CommonJS modules are still widely used in the Node.js ecosystem. Bun supports both module formats. - -In Bun's JavaScript runtime, `require` can be used by both ES Modules and CommonJS modules. If the target module is an ES Module, `require` returns the module namespace object (equivalent to `import * as`). If the target module is a CommonJS module, `require` returns the `module.exports` object (as in Node.js). - -| Module Type | `require()` | `import * as` | -| ----------- | ---------------- | ----------------------------------------------------------------------- | -| ES Module | Module Namespace | Module Namespace | -| CommonJS | module.exports | `default` is `module.exports`, keys of module.exports are named exports | - -### What is a CommonJS module? - -In 2016, ECMAScript added support for [ES Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). ES Modules are the standard for JavaScript modules. However, millions of npm packages still use CommonJS modules. - -CommonJS modules are modules that use `module.exports` to export values. Typically, `require` is used to import CommonJS modules. - -```ts -// my-commonjs.cjs -const stuff = require("./stuff"); -module.exports = { stuff }; -``` - -The biggest difference between CommonJS and ES Modules is that CommonJS modules are synchronous, while ES Modules are asynchronous. There are other differences too, like ES Modules support top-level `await` and CommonJS modules don't. ES Modules are always in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), while CommonJS modules are not. Browsers do not have native support for CommonJS modules, but they do have native support for ES Modules (`<script type="module">`). CommonJS modules are not statically analyzable, while ES Modules only allow static imports and exports. - -### Importing CommonJS from ESM - -You can `import` or `require` CommonJS modules from ESM modules. - -```ts -import { stuff } from "./my-commonjs.cjs"; -import Stuff from "./my-commonjs.cjs"; -const myStuff = require("./my-commonjs.cjs"); -``` - -### Importing ESM from CommonJS - -```ts -// this works in Bun but not Node.js -const { stuff } = require("./my-esm.mjs"); -``` - -### Importing CommonJS from CommonJS - -```ts -const { stuff } = require("./my-commonjs.cjs"); -``` - -#### Top-level await - -If you are using top-level await, you must use `import()` to import ESM modules from CommonJS modules. - -```ts -import("./my-esm.js").then(({ stuff }) => { - // ... -}); - -// this will throw an error if "my-esm.js" uses top-level await -const { stuff } = require("./my-esm.js"); -``` - {% details summary="Low-level details of CommonJS interop in Bun" %} Bun's JavaScript runtime has native support for CommonJS. When Bun's JavaScript transpiler detects usages of `module.exports`, it treats the file as CommonJS. The module loader will then wrap the transpiled module in a function shaped like this: diff --git a/docs/runtime/nodejs-apis.md b/docs/runtime/nodejs-apis.md index 72504e664..4b58343e0 100644 --- a/docs/runtime/nodejs-apis.md +++ b/docs/runtime/nodejs-apis.md @@ -1,16 +1,16 @@ 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. If you run into any bugs with a particular package, please [open an issue](https://bun.sh/issues). Opening issues for compatibility bugs helps us prioritize what to work on next. +This page is updated regularly to reflect compatibility status of the latest version of Bun. The information below reflects Bun's compatibility with _Node.js v20_. If you run into any bugs with a particular package, please [open an issue](https://bun.sh/issues). Opening issues for compatibility bugs helps us prioritize what to work on next. ## Built-in modules ### [`node:assert`](https://nodejs.org/api/assert.html) -π’ Fully implemented. +π‘ Missing `doesNotMatch` ### [`node:async_hooks`](https://nodejs.org/api/async_hooks.html) -π‘ Only `AsyncLocalStorage`, and `AsyncResource` are implemented. +π‘ Only `AsyncLocalStorage`, and `AsyncResource` are implemented. `AsyncResource` is missing `bind`. ### [`node:buffer`](https://nodejs.org/api/buffer.html) @@ -18,7 +18,7 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:child_process`](https://nodejs.org/api/child_process.html) -π‘ Missing `Stream` stdio, `proc.gid`, `proc.uid`. IPC has partial support and only current only works with other `bun` processes. +π‘ Missing `Stream` stdio, `proc.gid` `proc.uid`. IPC has partial support and only current only works with other `bun` processes. ### [`node:cluster`](https://nodejs.org/api/cluster.html) @@ -26,11 +26,13 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:console`](https://nodejs.org/api/console.html) -π‘ Missing `Console` constructor. +π’ Fully implemented. ### [`node:crypto`](https://nodejs.org/api/crypto.html) -π‘ 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.{get|set}Fips` `crypto.hkdf` `crypto.hkdfSync` `crypto.secureHeapUsed` `crypto.setEngine` `crypto.sign` `crypto.verify`. Some methods are not optimized yet. +π‘ Missing `Certificate` `ECDH` `X509Certificate` `checkPrime` `checkPrimeSync` `diffieHellman` `generatePrime` `generatePrimeSync` `getCipherInfo` `getFips` `hkdf` `hkdfSync` `secureHeapUsed` `setEngine` `setFips` + +Some methods are not optimized yet. ### [`node:dgram`](https://nodejs.org/api/dgram.html) @@ -42,19 +44,19 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:dns`](https://nodejs.org/api/dns.html) -π’ Fully implemented. +π‘ Missing `cancel` `setServers` `getDefaultResultOrder` ### [`node:domain`](https://nodejs.org/api/domain.html) -π’ Fully implemented. +π‘ Missing `Domain` `active` ### [`node:events`](https://nodejs.org/api/events.html) -π‘ Missing `on` +π‘ Missing `on` `addAbortListener` `getMaxListeners` ### [`node:fs`](https://nodejs.org/api/fs.html) -π‘ Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}`. `fs.promises.open` incorrectly returns a file descriptor instead of a `FileHandle`. +π‘ Missing `Dir` `fdatasync` `fdatasyncSync` `openAsBlob` `opendir` `opendirSync` `statfs` `statfsSync`. `fs.promises.open` incorrectly returns a file descriptor instead of a `FileHandle`. ### [`node:http`](https://nodejs.org/api/http.html) @@ -74,11 +76,11 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:module`](https://nodejs.org/api/module.html) -π’ Fully implemented. +π’ Missing `runMain` `syncBuiltinESMExports`, `Module#load()`. Attempts to override or patch the module cache will fail. ### [`node:net`](https://nodejs.org/api/net.html) -π‘ Missing `net.{get|set}DefaultAutoSelectFamily` `net.SocketAddress` `net.BlockList`. +π‘ Missing `BlockList` `SocketAddress` `Stream` `getDefaultAutoSelectFamily` `getDefaultAutoSelectFamilyAttemptTimeout` `setDefaultAutoSelectFamily` `setDefaultAutoSelectFamilyAttemptTimeout` `Server#ref()` `Server#unref()` `Socket#ref()` `Socket#unref()`. ### [`node:os`](https://nodejs.org/api/os.html) @@ -90,11 +92,11 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:perf_hooks`](https://nodejs.org/api/perf_hooks.html) -π‘ Only `perf_hooks.performance.now()` and `perf_hooks.performance.timeOrigin` are implemented. Recommended to use `performance` global instead of `perf_hooks.performance`. +π‘ Only `perf_hooks.performance.now()` and `perf_hooks.performance.timeOrigin` are implemented. Missing `Performance` `PerformanceMark` `PerformanceMeasure` `PerformanceObserverEntryList` `PerformanceResourceTiming` `createHistogram` `monitorEventLoopDelay`. It's recommended to use `performance` global instead of `perf_hooks.performance`. ### [`node:process`](https://nodejs.org/api/process.html) -π‘ See `Globals > process`. +π‘ See [`process`](#process) Global. ### [`node:punycode`](https://nodejs.org/api/punycode.html) @@ -114,7 +116,7 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:stream`](https://nodejs.org/api/stream.html) -π’ Fully implemented. +π‘ Missing `getDefaultHighWaterMark` `setDefaultHighWaterMark` ### [`node:string_decoder`](https://nodejs.org/api/string_decoder.html) @@ -122,7 +124,7 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:sys`](https://nodejs.org/api/util.html) -π‘ See `node:util`. +π‘ See [`node:util`](#node-util). ### [`node:timers`](https://nodejs.org/api/timers.html) @@ -130,7 +132,7 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:tls`](https://nodejs.org/api/tls.html) -π‘ Missing `tls.createSecurePair` +π‘ Missing `tls.createSecurePair`. ### [`node:trace_events`](https://nodejs.org/api/tracing.html) @@ -142,11 +144,11 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:url`](https://nodejs.org/api/url.html) -π‘ Missing `url.domainTo{ASCII|Unicode}`. Recommended to use `URL` and `URLSearchParams` globals instead. +π‘ Missing `domainToASCII` `domainToUnicode`. It's recommended to use `URL` and `URLSearchParams` globals instead. ### [`node:util`](https://nodejs.org/api/util.html) -π‘ Missing `util.MIMEParams` `util.MIMEType` `util.getSystemErrorMap()` `util.getSystemErrorName()` `util.parseArgs()` `util.stripVTControlCharacters()` `util.transferableAbortController()` `util.transferableAbortSignal()`. +π‘ Missing `MIMEParams` `MIMEType` `aborted` `debug` `getSystemErrorMap` `getSystemErrorName` `parseArgs` `transferableAbortController` `transferableAbortSignal` `stripVTControlCharacters` ### [`node:v8`](https://nodejs.org/api/v8.html) @@ -154,7 +156,7 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:vm`](https://nodejs.org/api/vm.html) -π‘ Core functionality works, but VM modules are not implemented. `ShadowRealm` can be used. +π‘ Core functionality works, but VM modules are not implemented. Missing `createScript`. `ShadowRealm` can be used. ### [`node:wasi`](https://nodejs.org/api/wasi.html) @@ -162,266 +164,11 @@ This page is updated regularly to reflect compatibility status of the latest ver ### [`node:worker_threads`](https://nodejs.org/api/worker_threads.html) -π‘ `Worker` doesn't support the following options: `eval`, `argv`, `execArgv`, `stdin`, `stdout`, `stderr`, `trackedUnmanagedFds`, `resourceLimits`. Missing `markAsUntransferable`, `moveMessagePortToContext`, `getHeapSnapshot`. +π‘ `Worker` doesn't support the following options: `eval` `argv` `execArgv` `stdin` `stdout` `stderr` `trackedUnmanagedFds` `resourceLimits`. Missing `markAsUntransferable` `moveMessagePortToContext` `getHeapSnapshot`. ### [`node:zlib`](https://nodejs.org/api/zlib.html) -π‘ Missing `zlib.brotli*`. Has not been optimized. - -<!-- {% 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 %} -- π’ - ---- - -- {% 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.{get|set}Fips` `crypto.hkdf` `crypto.hkdfSync` `crypto.secureHeapUsed` `crypto.setEngine` `crypto.sign` `crypto.verify`. Some methods are not optimized yet. - ---- - -- {% 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` `events.on`. - ---- - -- {% anchor id="node_fs" %} [`node:fs`](https://nodejs.org/api/fs.html) {% /anchor %} -- π‘ -- Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}`. `fs.promises.open` incorrectly returns a file descriptor instead of a `FileHandle`. - ---- - -- {% anchor id="node_http" %} [`node:http`](https://nodejs.org/api/http.html) {% /anchor %} -- π’ -- Fully implemented. - ---- - -- {% 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 %} -- π’ -- Fully implemented. - ---- - -- {% 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.{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 %} -- π’ -- Fully implemented. - ---- - -- {% 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 %} -- π’ -- Fully implemented. - ---- - -- {% 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.createSecurePair` - ---- - -- {% 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}`. 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.transferableAbortController()` `util.transferableAbortSignal()`. - ---- - -- {% anchor id="node_v8" %} [`node:v8`](https://nodejs.org/api/v8.html) {% /anchor %} -- π΄ -- `serialize` and `deserialize` use JavaScriptCore's wire format instead of V8's. Otherwise, not implemented. For profiling, use [`bun:jsc`](/docs/project/benchmarking#bunjsc) instead. - ---- - -- {% anchor id="node_vm" %} [`node:vm`](https://nodejs.org/api/vm.html) {% /anchor %} -- π‘ -- Core functionality works, but VM modules are not implemented. `ShadowRealm` can be used. - ---- - -- {% 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, but coming soon. - ---- - -- {% anchor id="node_zlib" %} [`node:zlib`](https://nodejs.org/api/zlib.html) {% /anchor %} -- π‘ -- Missing `zlib.brotli*` - -{% /table %} -{% /block %} --> +π‘ Missing `BrotliCompress` `BrotliDecompress` `brotliCompressSync` `brotliDecompress` `brotliDecompressSync` `createBrotliCompress` `createBrotliDecompress`. Unoptimized. ## Globals @@ -485,7 +232,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa ### [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) -π‘ Missing `Console` constructor. +π’ Fully implemented. ### [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) @@ -589,7 +336,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa ### [`process`](https://nodejs.org/api/process.html) -π‘ Missing `process.allowedNodeEnvironmentFlags` `process.channel` `process.constrainedMemory()` `process.getActiveResourcesInfo/setActiveResourcesInfo()` `process.setuid/setgid/setegid/seteuid/setgroups()` `process.hasUncaughtExceptionCaptureCallback` `process.initGroups()` `process.report` `process.resourceUsage()`. +π‘ Missing `domain` `hasUncaughtExceptionCaptureCallback` `initgroups` `report` `resourceUsage` `setUncaughtExceptionCaptureCallback` `setegid` `seteuid` `setgid` `setgroups` `setuid` `allowedNodeEnvironmentFlags` `getActiveResourcesInfo` `setActiveResourcesInfo` `moduleLoadList` `setSourceMapsEnabled` `channel`. `process.binding` is partially implemented. ### [`queueMicrotask()`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) @@ -621,7 +368,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa ### [`require()`](https://nodejs.org/api/globals.html#require) -π’ Fully implemented, as well as [`require.main`](https://nodejs.org/api/modules.html#requiremain), [`require.cache`](https://nodejs.org/api/modules.html#requirecache), and [`require.resolve`](https://nodejs.org/api/modules.html#requireresolverequest-options) +π’ Fully implemented, including [`require.main`](https://nodejs.org/api/modules.html#requiremain), [`require.cache`](https://nodejs.org/api/modules.html#requirecache), [`require.resolve`](https://nodejs.org/api/modules.html#requireresolverequest-options) ### [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) @@ -702,421 +449,3 @@ The table below lists all globals implemented by Node.js and Bun's current compa ### [`WritableStreamDefaultWriter`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter) π’ Fully implemented. - -<!-- {% 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" %} [`SubtleCrypto (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. - ---- - -- {% 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 %} -- π’ -- Fully 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 %} -- π’ -- Fully 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.disconnect()` `process.getActiveResourcesInfo/setActiveResourcesInfo()` `process.setuid/setgid/setegid/seteuid/setgroups()` `process.hasUncaughtExceptionCaptureCallback` `process.initGroups()` `process.report` `process.resourceUsage()` `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, as well as [`require.main`](https://nodejs.org/api/modules.html#requiremain), [`require.cache`](https://nodejs.org/api/modules.html#requirecache), and [`require.resolve`](https://nodejs.org/api/modules.html#requireresolverequest-options) - ---- - -- {% 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 %} -- π’ -- Fully 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 index 0286c7887..f2e0d7c77 100644 --- a/docs/runtime/plugins.md +++ b/docs/runtime/plugins.md @@ -17,7 +17,7 @@ const myPlugin: BunPlugin = { }; ``` -Plugins have to be registered before any other code runs! To achieve this, use the `preload` option in your [`bunfig.toml`](/docs/runtime/configuration). Bun automatically loads the files/modules specified in `preload` before running a file. +Plugins have to be registered before any other code runs! To achieve this, use the `preload` option in your [`bunfig.toml`](/docs/runtime/bunfig). Bun automatically loads the files/modules specified in `preload` before running a file. ```toml preload = ["./myPlugin.ts"] @@ -45,7 +45,7 @@ plugin( ); ``` -Bun's plugin API is based on [esbuild](https://esbuild.github.io/plugins). Only [a subset](/docs/bundler/vs-esbuild#plugin-api) of the esbuild API is implemented, but some esbuild plugins "just work" in Bun, like the official [MDX loader](https://mdxjs.com/packages/esbuild/): +Bun's plugin API is loosely based on [esbuild](https://esbuild.github.io/plugins). Only [a subset](/docs/bundler/vs-esbuild#plugin-api) 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"; @@ -84,15 +84,20 @@ plugin({ }); ``` -With this plugin, data can be directly imported from `.yaml` files. +Register this file in `preload`: + +```toml#bunfig.toml +preload = ["./yamlPlugin.ts"] +``` + +Once the plugin is registered, `.yaml` and `.yml` files can be directly imported. {% codetabs %} ```ts#index.ts -import "./yamlPlugin.ts" -import {name, releaseYear} from "./data.yml" +import data from "./data.yml" -console.log(name, releaseYear); +console.log(data); ``` ```yaml#data.yml @@ -127,7 +132,7 @@ In this case we're using `"object"`βa built-in loader (intended for use by plu --- - `ts` -- `.ts` `.mts` `cts` +- `.ts` `.mts` `.cts` - Transform TypeScript then transpile --- @@ -212,6 +217,91 @@ import MySvelteComponent from "./component.svelte"; console.log(mySvelteComponent.render()); ``` +## Virtual Modules + +{% note %} + +This feature is currently only available at runtime with `Bun.plugin` and not yet supported in the bundler, but you can mimick the behavior using `onResolve` and `onLoad`. + +{% /note %} + +To create virtual modules at runtime, use `builder.module(specifier, callback)` in the `setup` function of a `Bun.plugin`. + +For example: + +```js +import { plugin } from "bun"; + +plugin({ + name: "my-virtual-module", + + setup(build) { + build.module( + // The specifier, which can be any string + "my-transpiled-virtual-module", + // The callback to run when the module is imported or required for the first time + () => { + return { + contents: "console.log('hello world!')", + loader: "js", + }; + }, + ); + + build.module("my-object-virtual-module", () => { + return { + exports: { + foo: "bar", + }, + loader: "object", + }; + }); + }, +}); + +// Sometime later +// All of these work +import "my-transpiled-virtual-module"; +require("my-transpiled-virtual-module"); +await import("my-transpiled-virtual-module"); +require.resolve("my-transpiled-virtual-module"); + +import { foo } from "my-object-virtual-module"; +const object = require("my-object-virtual-module"); +await import("my-object-virtual-module"); +require.resolve("my-object-virtual-module"); +``` + +### Overriding existing modules + +You can also override existing modules with `build.module`. + +```js +import { plugin } from "bun"; +build.module("my-object-virtual-module", () => { + return { + exports: { + foo: "bar", + }, + loader: "object", + }; +}); + +require("my-object-virtual-module"); // { foo: "bar" } +await import("my-object-virtual-module"); // { foo: "bar" } + +build.module("my-object-virtual-module", () => { + return { + exports: { + baz: "quix", + }, + loader: "object", + }; +}); +require("my-object-virtual-module"); // { baz: "quix" } +await import("my-object-virtual-module"); // { baz: "quix" } +``` + ## Reading the config Plugins can read and write to the [build config](/docs/bundler#api) with `build.config`. diff --git a/docs/runtime/typescript.md b/docs/runtime/typescript.md index eade2f13b..e7c59fb1a 100644 --- a/docs/runtime/typescript.md +++ b/docs/runtime/typescript.md @@ -1,119 +1,35 @@ Bun treats TypeScript as a first-class citizen. -## Running `.ts` files - -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. - -**Note** β Similar to other build tools, Bun does not typecheck the files. Use [`tsc`](https://www.typescriptlang.org/docs/handbook/compiler-options.html) (the official TypeScript CLI) if you're looking to catch static type errors. - {% callout %} -**Is transpiling still necessary?** β Because Bun can directly execute TypeScript, you may not need to transpile your TypeScript to run in production. Bun internally transpiles every file it executes (both `.js` and `.ts`), so the additional overhead of directly executing your `.ts/.tsx` source files is negligible. - -That said, if you are using Bun as a development tool but still targeting Node.js or browsers in production, you'll still need to transpile. +**Note** β To add type declarations for Bun APIs like the `Bun` global, follow the instructions at [Intro > TypeScript](/docs/typescript). This page describes how the Bun runtime runs TypeScript code. {% /callout %} -## Configuring `tsconfig.json` - -Bun supports a number of features that TypeScript doesn't support by default, such as extensioned imports, top-level await, and `exports` conditions. It also implements global APIs like the `Bun`. To enable these features, your `tsconfig.json` must be configured properly. - -{% callout %} -If you initialized your project with `bun init`, everything is already configured properly. -{% /callout %} - -To get started, install the `bun-types` package. - -```sh -$ bun add -d bun-types # dev dependency -``` - -If you're using a canary build of Bun, use the `canary` tag. The canary package is updated on every commit to the `main` branch. +## Running `.ts` files -```sh -$ bun add -d bun-types@canary -``` +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. -<!-- ### Quick setup +**Note** β Similar to other build tools, Bun does not typecheck the files. Use [`tsc`](https://www.typescriptlang.org/docs/handbook/compiler-options.html) (the official TypeScript CLI) if you're looking to catch static type errors. {% callout %} -**Note**Β βΒ This approach requires TypeScript 5.0 or later! - -{% /callout %} - -Add the following to your `tsconfig.json`. +**Is transpiling still necessary?** β Because Bun can directly execute TypeScript, you may not need to transpile your TypeScript to run in production. Bun internally transpiles every file it executes (both `.js` and `.ts`), so the additional overhead of directly executing your `.ts/.tsx` source files is negligible. -```json-diff - { -+ "extends": ["bun-types"] - // other options... - } -``` +That said, if you are using Bun as a development tool but still targeting Node.js or browsers in production, you'll still need to transpile. -{% callout %} -**Note** β The `"extends"` field in your `tsconfig.json` can accept an array of values. If you're already using `"extends"`, just add `"bun-types"` to the array. {% /callout %} -That's it! You should be able to use Bun's full feature set without seeing any TypeScript compiler errors. - -### Manual setup --> - -### Recommended `compilerOptions` - -These are the recommended `compilerOptions` for a Bun project. - -```jsonc -{ - "compilerOptions": { - // add Bun type definitions - "types": ["bun-types"], - - // enable latest features - "lib": ["esnext"], - "module": "esnext", - "target": "esnext", - - // if TS 5.x+ - "moduleResolution": "bundler", - "noEmit": true, - "allowImportingTsExtensions": true, - "moduleDetection": "force", - // if TS 4.x or earlier - "moduleResolution": "nodenext", - - "jsx": "react-jsx", // support JSX - "allowJs": true, // allow importing `.js` from `.ts` - "esModuleInterop": true, // allow default imports for CommonJS modules - - // best practices - "strict": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true - } -} -``` - -### Add DOM types - -Settings `"types": ["bun-types"]` means TypeScript will ignore other global type definitions, including `lib: ["dom"]`. To add DOM types into your project, add the following [triple-slash directives](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html) at the top of any TypeScript file in your project. - -```ts -/// <reference lib="dom" /> -/// <reference lib="dom.iterable" /> -``` - -The same applies to other global type definition _libs_ like `webworker`. - ## Path mapping When resolving modules, Bun's runtime respects path mappings defined in [`compilerOptions.paths`](https://www.typescriptlang.org/tsconfig#paths) in your `tsconfig.json`. No other runtime does this. -Given the following `tsconfig.json`... +Consider the following `tsconfig.json`. ```json { "compilerOptions": { + "baseUrl": "./src", "paths": { "data": ["./data.ts"] } @@ -121,7 +37,14 @@ Given the following `tsconfig.json`... } ``` -...the import from `"data"` will work as expected. +Bun will use `baseUrl` to resolve module paths. + +```ts +// resolves to ./src/components/Button.tsx +import { Button } from "components/Button.tsx"; +``` + +Bun will also correctly resolve imports from `"data"`. {% codetabs %} |