diff options
author | 2023-02-23 17:13:30 -0800 | |
---|---|---|
committer | 2023-02-23 17:13:30 -0800 | |
commit | f54300578b1edc7f67daddbfae29575cbf305264 (patch) | |
tree | 1437f3274122c011f879dca71f59a74d75a33fd0 /docs/cli | |
parent | 5929daeeae1f528abab31979a0a28bc87a03b1f4 (diff) | |
download | bun-f54300578b1edc7f67daddbfae29575cbf305264.tar.gz bun-f54300578b1edc7f67daddbfae29575cbf305264.tar.zst bun-f54300578b1edc7f67daddbfae29575cbf305264.zip |
Add documentation (#2148)bun-v0.5.7
* Add documentation
* Tweaks
* Fixes
* Rearrange
* Update
Diffstat (limited to 'docs/cli')
-rw-r--r-- | docs/cli/bun-completions.md | 3 | ||||
-rw-r--r-- | docs/cli/bun-dev.md | 21 | ||||
-rw-r--r-- | docs/cli/bun-init.md | 20 | ||||
-rw-r--r-- | docs/cli/bun-install.md | 257 | ||||
-rw-r--r-- | docs/cli/bun-upgrade.md | 39 | ||||
-rw-r--r-- | docs/cli/bundler.md | 116 | ||||
-rw-r--r-- | docs/cli/create.md | 232 | ||||
-rw-r--r-- | docs/cli/install.md | 344 | ||||
-rw-r--r-- | docs/cli/run.md | 156 | ||||
-rw-r--r-- | docs/cli/test.md | 224 |
10 files changed, 1412 insertions, 0 deletions
diff --git a/docs/cli/bun-completions.md b/docs/cli/bun-completions.md new file mode 100644 index 000000000..68dcb946d --- /dev/null +++ b/docs/cli/bun-completions.md @@ -0,0 +1,3 @@ +This command installs completions for `zsh` and/or `fish`. It runs automatically on every `bun upgrade` and on install. It reads from `$SHELL` to determine which shell to install for. It tries several common shell completion directories for your shell and OS. + +If you want to copy the completions manually, run `bun completions > path-to-file`. If you know the completions directory to install them to, run `bun completions /path/to/directory`. diff --git a/docs/cli/bun-dev.md b/docs/cli/bun-dev.md new file mode 100644 index 000000000..5d1adec5f --- /dev/null +++ b/docs/cli/bun-dev.md @@ -0,0 +1,21 @@ +In your project folder root (where `package.json` is): + +```bash +$ bun bun ./entry-point-1.js ./entry-point-2.jsx +$ bun dev +``` + +By default, `bun dev` will look for any HTML files in the `public` directory and serve that. For browsers navigating to the page, the `.html` file extension is optional in the URL, and `index.html` will automatically rewrite for the directory. + +Here are examples of routing from `public/` and how they’re matched: +| Dev Server URL | File Path | +|----------------|-----------| +| /dir | public/dir/index.html | +| / | public/index.html | +| /index | public/index.html | +| /hi | public/hi.html | +| /file | public/file.html | +| /font/Inter.woff2 | public/font/Inter.woff2 | +| /hello | public/index.html | + +If `public/index.html` exists, it becomes the default page instead of a 404 page, unless that pathname has a file extension. diff --git a/docs/cli/bun-init.md b/docs/cli/bun-init.md new file mode 100644 index 000000000..3a0e66815 --- /dev/null +++ b/docs/cli/bun-init.md @@ -0,0 +1,20 @@ +`bun init` is a quick way to start a blank project with Bun. It guesses with sane defaults and is non-destructive when run multiple times. + + + +It creates: + +- a `package.json` file with a name that defaults to the current directory name +- a `tsconfig.json` file or a `jsconfig.json` file, depending if the entry point is a TypeScript file or not +- an entry point which defaults to `index.ts` unless any of `index.{tsx, jsx, js, mts, mjs}` exist or the `package.json` specifies a `module` or `main` field +- a `README.md` file + +If you pass `-y` or `--yes`, it will assume you want to continue without asking questions. + +At the end, it runs `bun install` to install `bun-types`. + +Added in Bun v0.1.7. + +#### How is `bun init` different than `bun create`? + +`bun init` is for blank projects. `bun create` applies templates. diff --git a/docs/cli/bun-install.md b/docs/cli/bun-install.md new file mode 100644 index 000000000..11cf3ee81 --- /dev/null +++ b/docs/cli/bun-install.md @@ -0,0 +1,257 @@ +### `bun install` + +bun install is a fast package manager & npm client. + +bun install can be configured via `bunfig.toml`, environment variables, and CLI flags. + +#### Configuring `bun install` with `bunfig.toml` + +`bunfig.toml` is searched for in the following paths on `bun install`, `bun remove`, and `bun add`: + +1. `$XDG_CONFIG_HOME/.bunfig.toml` or `$HOME/.bunfig.toml` +2. `./bunfig.toml` + +If both are found, the results are merged together. + +Configuring with `bunfig.toml` is optional. Bun tries to be zero configuration in general, but that's not always possible. + +```toml +# Using scoped packages with bun install +[install.scopes] + +# Scope name The value can be a URL string or an object +"@mybigcompany" = { token = "123456", url = "https://registry.mybigcompany.com" } +# URL is optional and fallsback to the default registry + +# The "@" in the scope is optional +mybigcompany2 = { token = "123456" } + +# Environment variables can be referenced as a string that starts with $ and it will be replaced +mybigcompany3 = { token = "$npm_config_token" } + +# Setting username and password turns it into a Basic Auth header by taking base64("username:password") +mybigcompany4 = { username = "myusername", password = "$npm_config_password", url = "https://registry.yarnpkg.com/" } +# You can set username and password in the registry URL. This is the same as above. +mybigcompany5 = "https://username:password@registry.yarnpkg.com/" + +# You can set a token for a registry URL: +mybigcompany6 = "https://:$NPM_CONFIG_TOKEN@registry.yarnpkg.com/" + +[install] +# Default registry +# can be a URL string or an object +registry = "https://registry.yarnpkg.com/" +# as an object +#registry = { url = "https://registry.yarnpkg.com/", token = "123456" } + +# Install for production? This is the equivalent to the "--production" CLI argument +production = false + +# Don't actually install +dryRun = true + +# Install optionalDependencies (default: true) +optional = true + +# Install local devDependencies (default: true) +dev = true + +# Install peerDependencies (default: false) +peer = false + +# When using `bun install -g`, install packages here +globalDir = "~/.bun/install/global" + +# When using `bun install -g`, link package bins here +globalBinDir = "~/.bun/bin" + +# cache-related configuration +[install.cache] +# The directory to use for the cache +dir = "~/.bun/install/cache" + +# Don't load from the global cache. +# Note: Bun may still write to node_modules/.cache +disable = false + + +# Always resolve the latest versions from the registry +disableManifest = false + + +# Lockfile-related configuration +[install.lockfile] + +# Print a yarn v1 lockfile +# Note: it does not load the lockfile, it just converts bun.lockb into a yarn.lock +print = "yarn" + +# Path to read bun.lockb from +path = "bun.lockb" + +# Path to save bun.lockb to +savePath = "bun.lockb" + +# Save the lockfile to disk +save = true + +``` + +If it's easier to read as TypeScript types: + +```ts +export interface Root { + install: Install; +} + +export interface Install { + scopes: Scopes; + registry: Registry; + production: boolean; + dryRun: boolean; + optional: boolean; + dev: boolean; + peer: boolean; + globalDir: string; + globalBinDir: string; + cache: Cache; + lockfile: Lockfile; + logLevel: "debug" | "error" | "warn"; +} + +type Registry = + | string + | { + url?: string; + token?: string; + username?: string; + password?: string; + }; + +type Scopes = Record<string, Registry>; + +export interface Cache { + dir: string; + disable: boolean; + disableManifest: boolean; +} + +export interface Lockfile { + print?: "yarn"; + path: string; + savePath: string; + save: boolean; +} +``` + +## Configuring with environment variables + +Environment variables have a higher priority than `bunfig.toml`. + +| Name | Description | +| -------------------------------- | ------------------------------------------------------------- | +| BUN_CONFIG_REGISTRY | Set an npm registry (default: <https://registry.npmjs.org>) | +| BUN_CONFIG_TOKEN | Set an auth token (currently does nothing) | +| BUN_CONFIG_LOCKFILE_SAVE_PATH | File path to save the lockfile to (default: bun.lockb) | +| BUN_CONFIG_YARN_LOCKFILE | Save a Yarn v1-style yarn.lock | +| BUN_CONFIG_LINK_NATIVE_BINS | Point `bin` in package.json to a platform-specific dependency | +| BUN_CONFIG_SKIP_SAVE_LOCKFILE | Don’t save a lockfile | +| BUN_CONFIG_SKIP_LOAD_LOCKFILE | Don’t load a lockfile | +| BUN_CONFIG_SKIP_INSTALL_PACKAGES | Don’t install any packages | + +Bun always tries to use the fastest available installation method for the target platform. On macOS, that’s `clonefile` and on Linux, that’s `hardlink`. You can change which installation method is used with the `--backend` flag. When unavailable or on error, `clonefile` and `hardlink` fallsback to a platform-specific implementation of copying files. + +Bun stores installed packages from npm in `~/.bun/install/cache/${name}@${version}`. Note that if the semver version has a `build` or a `pre` tag, it is replaced with a hash of that value instead. This is to reduce the chances of errors from long file paths, but unfortunately complicates figuring out where a package was installed on disk. + +When the `node_modules` folder exists, before installing, Bun checks if the `"name"` and `"version"` in `package/package.json` in the expected node_modules folder matches the expected `name` and `version`. This is how it determines whether it should install. It uses a custom JSON parser which stops parsing as soon as it finds `"name"` and `"version"`. + +When a `bun.lockb` doesn’t exist or `package.json` has changed dependencies, tarballs are downloaded & extracted eagerly while resolving. + +When a `bun.lockb` exists and `package.json` hasn’t changed, Bun downloads missing dependencies lazily. If the package with a matching `name` & `version` already exists in the expected location within `node_modules`, Bun won’t attempt to download the tarball. + +## Platform-specific dependencies? + +bun stores normalized `cpu` and `os` values from npm in the lockfile, along with the resolved packages. It skips downloading, extracting, and installing packages disabled for the current target at runtime. This means the lockfile won’t change between platforms/architectures even if the packages ultimately installed do change. + +## Peer dependencies? + +Peer dependencies are handled similarly to yarn. `bun install` does not automatically install peer dependencies and will try to choose an existing dependency. + +## Lockfile + +`bun.lockb` is Bun’s binary lockfile format. + +## Why is it binary? + +In a word: Performance. Bun’s lockfile saves & loads incredibly quickly, and saves a lot more data than what is typically inside lockfiles. + +## How do I inspect it? + +For now, the easiest thing is to run `bun install -y`. That prints a Yarn v1-style yarn.lock file. + +## What does the lockfile store? + +Packages, metadata for those packages, the hoisted install order, dependencies for each package, what packages those dependencies resolved to, an integrity hash (if available), what each package was resolved to and which version (or equivalent). + +## Why is it fast? + +It uses linear arrays for all data. [Packages](https://github.com/oven-sh/bun/blob/be03fc273a487ac402f19ad897778d74b6d72963/src/install/install.zig#L1825) are referenced by an auto-incrementing integer ID or a hash of the package name. Strings longer than 8 characters are de-duplicated. Prior to saving on disk, the lockfile is garbage-collected & made deterministic by walking the package tree and cloning the packages in dependency order. + +## Cache + +To delete the cache: + +```bash +$ rm -rf ~/.bun/install/cache +``` + +## Platform-specific backends + +`bun install` uses different system calls to install dependencies depending on the platform. This is a performance optimization. You can force a specific backend with the `--backend` flag. + +**`hardlink`** is the default backend on Linux. Benchmarking showed it to be the fastest on Linux. + +```bash +$ rm -rf node_modules +$ bun install --backend hardlink +``` + +**`clonefile`** is the default backend on macOS. Benchmarking showed it to be the fastest on macOS. It is only available on macOS. + +```bash +$ rm -rf node_modules +$ bun install --backend clonefile +``` + +**`clonefile_each_dir`** is similar to `clonefile`, except it clones each file individually per directory. It is only available on macOS and tends to perform slower than `clonefile`. Unlike `clonefile`, this does not recursively clone subdirectories in one system call. + +```bash +$ rm -rf node_modules +$ bun install --backend clonefile_each_dir +``` + +**`copyfile`** is the fallback used when any of the above fail, and is the slowest. on macOS, it uses `fcopyfile()` and on linux it uses `copy_file_range()`. + +```bash +$ rm -rf node_modules +$ bun install --backend copyfile +``` + +**`symlink`** is typically only used for `file:` dependencies (and eventually `link:`) internally. To prevent infinite loops, it skips symlinking the `node_modules` folder. + +If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own node_modules folder or you pass `--preserve-symlinks` to `node`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks). + +```bash +$ rm -rf node_modules +$ bun install --backend symlink +$ node --preserve-symlinks ./my-file.js # https://nodejs.org/api/cli.html#--preserve-symlinks +``` + +Bun's runtime does not currently expose an equivalent of `--preserve-symlinks`, though the code for it does exist. + +## npm registry metadata + +bun uses a binary format for caching NPM registry responses. This loads much faster than JSON and tends to be smaller on disk. +You will see these files in `~/.bun/install/cache/*.npm`. The filename pattern is `${hash(packageName)}.npm`. It’s a hash so that extra directories don’t need to be created for scoped packages. + +Bun's usage of `Cache-Control` ignores `Age`. This improves performance, but means bun may be about 5 minutes out of date to receive the latest package version metadata from npm. diff --git a/docs/cli/bun-upgrade.md b/docs/cli/bun-upgrade.md new file mode 100644 index 000000000..a9d0759b6 --- /dev/null +++ b/docs/cli/bun-upgrade.md @@ -0,0 +1,39 @@ +To upgrade Bun, run `bun upgrade`. + +It automatically downloads the latest version of Bun and overwrites the currently-running version. + +This works by checking the latest version of Bun in [bun-releases-for-updater](https://github.com/Jarred-Sumner/bun-releases-for-updater/releases) and unzipping it using the system-provided `unzip` library (so that Gatekeeper works on macOS) + +If for any reason you run into issues, you can also use the curl install script: + +```bash +$ curl https://bun.sh/install | bash +``` + +It will still work when Bun is already installed. + +Bun is distributed as a single binary file, so you can also do this manually: + +- Download the latest version of Bun for your platform in [bun-releases-for-updater](https://github.com/Jarred-Sumner/bun-releases-for-updater/releases/latest) (`darwin` == macOS) +- Unzip the folder +- Move the `bun` binary to `~/.bun/bin` (or anywhere) + +## `--canary` + +[Canary](https://github.com/oven-sh/bun/releases/tag/canary) builds are generated on every commit. + +To install a [canary](https://github.com/oven-sh/bun/releases/tag/canary) build of Bun, run: + +```bash +$ bun upgrade --canary +``` + +This flag is not persistent (though that might change in the future). If you want to always run the canary build of Bun, set the `BUN_CANARY` environment variable to `1` in your shell's startup script. + +This will download the release zip from https://github.com/oven-sh/bun/releases/tag/canary. + +To revert to the latest published version of Bun, run: + +```bash +$ bun upgrade +``` diff --git a/docs/cli/bundler.md b/docs/cli/bundler.md new file mode 100644 index 000000000..6900e9292 --- /dev/null +++ b/docs/cli/bundler.md @@ -0,0 +1,116 @@ +Bundling is currently an important mechanism for building complex web apps. + +Modern apps typically consist of a large number of files and package dependencies. Despite the fact that modern browsers support [ES Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) imports, it's still too slow to fetch each file via inidividual HTTP requests. _Bundling_ is the process of concatenating several source files into a single large file that can be loaded in a single request. + +{% callout %} +**On bundling** — Despite recent advances like [`modulepreload`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload) and [HTTP/3](https://en.wikipedia.org/wiki/HTTP/3), bundling is still the most performant approach. +{% /callout %} + +## Bundling your app + +Bun's approach to bundling is a little different from other bundlers. Start by passing your app's entrypoint to `bun bun`. + +```bash +$ bun bun ./app.js +``` + +Your entrypoint can be any `js|jsx|ts|tsx|html` file. With this file as a starting point, Bun will construct a graph of imported files and packages, transpile everything, and generate a file called `node_modules.bun`. + +## What is `.bun`? + +{% callout %} +**Note** — [This format may change soon](https://github.com/oven-sh/bun/issues/121) +{% /callout %} + +A `.bun` file contains the pre-transpiled source code of your application, plus a bunch of binary-encoded metadata about your application's structure. as a contains: + +- all the bundled source code +- all the bundled source code metadata +- project metadata & configuration + +Here are some of the questions `.bun` files answer: + +- when I import `react/index.js`, where in the `.bun` is the code for that? (not resolving, just the code) +- what modules of a package are used? +- what framework is used? (e.g., Next.js) +- where is the routes directory? +- how big is each imported dependency? +- what is the hash of the bundle’s contents? (for etags) +- what is the name & version of every npm package exported in this bundle? +- what modules from which packages are used in this project? ("project" is defined as all the entry points used to generate the .bun) + +All in one file. + +It’s a little like a build cache, but designed for reuse across builds. + +{% details summary="Position-independent code" %} + +From a design perspective, the most important part of the `.bun` format is how code is organized. Each module is exported by a hash like this: + +```js +// preact/dist/preact.module.js +export var $eb6819b = $$m({ + "preact/dist/preact.module.js": (module, exports) => { + let n, l, u, i, t, o, r, f, e = {}, c = [], s = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i; + // ... rest of code +``` + +This makes bundled modules [position-independent](https://en.wikipedia.org/wiki/Position-independent_code). In theory, one could import only the exact modules in-use without reparsing code and without generating a new bundle. One bundle can dynamically become many bundles comprising only the modules in use on the webpage. Thanks to the metadata with the byte offsets, a web server can send each module to browsers [zero-copy](https://en.wikipedia.org/wiki/Zero-copy) using [sendfile](https://man7.org/linux/man-pages/man2/sendfile.2.html). Bun itself is not quite this smart yet, but these optimizations would be useful in production and potentially very useful for React Server Components. + +To see the schema inside, have a look at [`JavascriptBundleContainer`](./src/api/schema.d.ts#:~:text=export%20interface-,JavascriptBundleContainer,-%7B). You can find JavaScript bindings to read the metadata in [src/api/schema.js](./src/api/schema.js). This is not really an API yet. It’s missing the part where it gets the binary data from the bottom of the file. Someday, I want this to be usable by other tools too. +{% /details %} + +## Where is the code? + +`.bun` files are marked as executable. + +To print out the code, run `./node_modules.bun` in your terminal or run `bun ./path-to-node_modules.bun`. + +Here is a copy-pastable example: + +```bash +$ ./node_modules.bun > node_modules.js +``` + +This works because every `.bun` file starts with this: + +``` +#!/usr/bin/env bun +``` + +To deploy to production with Bun, you’ll want to get the code from the `.bun` file and stick that somewhere your web server can find it (or if you’re using Vercel or a Rails app, in a `public` folder). + +Note that `.bun` is a binary file format, so just opening it in VSCode or vim might render strangely. + +## Advanced + +By default, `bun bun` only bundles external dependencies that are `import`ed or `require`d in either app code or another external dependency. An "external dependency" is defined as, "A JavaScript-like file that has `/node_modules/` in the resolved file path and a corresponding `package.json`". + +To force Bun to bundle packages which are not located in a `node_modules` folder (i.e., the final, resolved path following all symlinks), add a `bun` section to the root project’s `package.json` with `alwaysBundle` set to an array of package names to always bundle. Here’s an example: + +```json +{ + "name": "my-package-name-in-here", + "bun": { + "alwaysBundle": ["@mybigcompany/my-workspace-package"] + } +} +``` + +Bundled dependencies are not eligible for Hot Module Reloading. The code is served to browsers & Bun.js verbatim. But, in the future, it may be sectioned off into only parts of the bundle being used. That’s possible in the current version of the `.bun` file (so long as you know which files are necessary), but it’s not implemented yet. Longer-term, it will include all `import` and `export` of each module inside. + +## What is the module ID hash? + +The `$eb6819b` hash used here: + +```js +export var $eb6819b = $$m({ +``` + +Is generated like this: + +1. Murmur3 32-bit hash of `package.name@package.version`. This is the hash uniquely identifying the npm package. +2. Wyhash 64 of the `package.hash` + `package_path`. `package_path` means "relative to the root of the npm package, where is the module imported?". For example, if you imported `react/jsx-dev-runtime.js`, the `package_path` is `jsx-dev-runtime.js`. `react-dom/cjs/react-dom.development.js` would be `cjs/react-dom.development.js` +3. Truncate the hash generated above to a `u32` + +The implementation details of this module ID hash will vary between versions of Bun. The important part is the metadata contains the module IDs, the package paths, and the package hashes, so it shouldn’t really matter in practice if other tooling wants to make use of any of this. diff --git a/docs/cli/create.md b/docs/cli/create.md new file mode 100644 index 000000000..8542db68b --- /dev/null +++ b/docs/cli/create.md @@ -0,0 +1,232 @@ +Template a new Bun project with `bun create`. + +```bash +$ bun create <template> <destination> +``` + +{% callout %} +**Note** — You don’t need `bun create` to use Bun. You don’t need any configuration at all. This command exists to make getting started a bit quicker and easier. +{% /callout %} + +A template can take a number of forms: + +```bash +$ bun create <template> # an official template (remote) +$ bun create <username>/<repo> # a GitHub repo (remote) +$ bun create <local-template> # a custom template (local) +``` + +Running `bun create` performs the following steps: + +- Download the template (remote templates only) +- Copy all template files into the destination folder. By default Bun will _not overwrite_ any existing files. Use the `--force` flag to overwrite existing files. +- Install dependencies with `bun install`. +- Initialize a fresh Git repo. Opt out with the `--no-git` flag. +- Run the template's configured `start` script, if defined. + +## Official templates + +The following official templates are available. + +```bash +bun create next ./myapp +bun create react ./myapp +bun create svelte-kit ./myapp +bun create elysia ./myapp +bun create hono ./myapp +bun create kingworld ./myapp +``` + +Each of these corresponds to a directory in the [bun-community/create-templates](https://github.com/bun-community/create-templates) repo. If you think a major framework is missing, please open a PR there. This list will change over time as additional examples are added. To see an up-to-date list, run `bun create` with no arguments. + +```bash +$ bun create +Welcome to bun! Create a new project by pasting any of the following: + <list of templates> +``` + +{% callout %} +⚡️ **Speed** — At the time of writing, `bun create react app` runs ~11x faster on a M1 Macbook Pro than `yarn create react-app app`. +{% /callout %} + +## GitHub repos + +A template of the form `<username>/<repo>` will be downloaded from GitHub. + +```bash +$ bun create ahfarmer/calculator ./myapp +``` + +Complete GitHub URLs will also work: + +```bash +$ bun create github.com/ahfarmer/calculator ./myapp +$ bun create https://github.com/ahfarmer/calculator ./myapp +``` + +Bun installs the files as they currently exist current default branch (usually `main`). Unlike `git clone` it doesn't download the commit history or configure a remote. + +## Local templates + +{% callout %} +**⚠️ Warning** — Unlike remote templates, running `bun create` with a local template will delete the entire destination folder if it already exists! Be careful. +{% /callout %} +Bun's templater can be extended to support custom templates defined on your local file system. These templates should live in one of the following directories: + +- `$HOME/.bun-create/<name>`: global templates +- `<project root>/.bun-create/<name>`: project-specific templates + +{% callout %} +**Note** — You can customize the global template path by setting the `BUN_CREATE_DIR` environment variable. +{% /callout %} + +To create a local template, navigate to `$HOME/.bun-create` and create a new directory with the desired name of your template. + +```bash +$ cd $HOME/.bun-create +$ mkdir foo +$ cd foo +``` + +Then, create a `package.json` file in that directory with the following contents: + +```json +{ + "name": "foo" +} +``` + +You can run `bun create foo` elsewhere on your file system to verify that Bun is correctly finding your local template. + +{% table %} + +--- + +- `postinstall` +- runs after installing dependencies + +--- + +- `preinstall` +- runs before installing dependencies + +<!-- --- + +- `start` +- a command to auto-start the application --> + +{% /table %} + +Each of these can correspond to a string or array of strings. An array of commands will be executed in order. Here is an example: + +```json +{ + "name": "@bun-examples/simplereact", + "version": "0.0.1", + "main": "index.js", + "dependencies": { + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "bun-create": { + "postinstall": "echo 'Installing...'", // a single command + "postinstall": ["echo 'Done!'"], // an array of commands + "start": "bun run echo 'Hello world!'" + } +} +``` + +When cloning a template, `bun create` will automatically remove the `"bun-create"` section from `package.json` before writing it to the destination folder. + +## Reference + +### CLI flags + +{% table %} + +- Flag +- Description + +--- + +- `--force` +- Overwrite existing files + +--- + +- `--no-install` +- Skip installing `node_modules` & tasks + +--- + +- `--no-git` +- Don’t initialize a git repository + +--- + +- `--open` +- Start & open in-browser after finish + +{% /table %} + +### Environment variables + +{% table %} + +- Name +- Description + +--- + +- `GITHUB_API_DOMAIN` +- If you’re using a GitHub enterprise or a proxy, you can customize the GitHub domain Bun pings for downloads + +--- + +- `GITHUB_API_TOKEN` +- This lets `bun create` work with private repositories or if you get rate-limited + +{% /table %} + +### How `bun create` works + +{% details summary="View details" %} + +When you run `bun create ${template} ${destination}`, here’s what happens: + +IF remote template + +1. GET `registry.npmjs.org/@bun-examples/${template}/latest` and parse it +2. GET `registry.npmjs.org/@bun-examples/${template}/-/${template}-${latestVersion}.tgz` +3. Decompress & extract `${template}-${latestVersion}.tgz` into `${destination}` + + - If there are files that would overwrite, warn and exit unless `--force` is passed + +IF GitHub repo + +1. Download the tarball from GitHub’s API +2. Decompress & extract into `${destination}` + + - If there are files that would overwrite, warn and exit unless `--force` is passed + +ELSE IF local template + +1. Open local template folder +2. Delete destination directory recursively +3. Copy files recursively using the fastest system calls available (on macOS `fcopyfile` and Linux, `copy_file_range`). Do not copy or traverse into `node_modules` folder if exists (this alone makes it faster than `cp`) + +4. Parse the `package.json` (again!), update `name` to be `${basename(destination)}`, remove the `bun-create` section from the `package.json` and save the updated `package.json` to disk. + - IF Next.js is detected, add `bun-framework-next` to the list of dependencies + - IF Create React App is detected, add the entry point in /src/index.{js,jsx,ts,tsx} to `public/index.html` + - IF Relay is detected, add `bun-macro-relay` so that Relay works +5. Auto-detect the npm client, preferring `pnpm`, `yarn` (v1), and lastly `npm` +6. Run any tasks defined in `"bun-create": { "preinstall" }` with the npm client +7. Run `${npmClient} install` unless `--no-install` is passed OR no dependencies are in package.json +8. Run any tasks defined in `"bun-create": { "preinstall" }` with the npm client +9. Run `git init; git add -A .; git commit -am "Initial Commit";` + + - Rename `gitignore` to `.gitignore`. NPM automatically removes `.gitignore` files from appearing in packages. + - If there are dependencies, this runs in a separate thread concurrently while node_modules are being installed + - Using libgit2 if available was tested and performed 3x slower in microbenchmarks + +{% /details %} diff --git a/docs/cli/install.md b/docs/cli/install.md new file mode 100644 index 000000000..777ed2da1 --- /dev/null +++ b/docs/cli/install.md @@ -0,0 +1,344 @@ +The `bun` CLI contains an `npm`-compatible package manager designed to be a faster replacement for existing package management tools like `npm`, `yarn`, and `pnpm`. + +It can be be used as a drop-in replacement for these tools, _regardless of whether you're using Bun's runtime_. + +{% callout %} + +**⚡️ 80x faster** — Switch from `npm install` to `bun install` in any Node.js project to make your installations up to 80x faster. + +{% image src="https://user-images.githubusercontent.com/709451/147004342-571b6123-17a9-49a2-8bfd-dcfc5204047e.png" height="200" /%} + +{% /callout %} + +{% details summary="For Linux users" %} +The minimum Linux Kernel version is 5.1. If you're on Linux kernel 5.1 - 5.5, `bun install` should still work, but HTTP requests will be slow due to a lack of support for io_uring's `connect()` operation. + +If you're using Ubuntu 20.04, here's how to install a [newer kernel](https://wiki.ubuntu.com/Kernel/LTSEnablementStack): + +```bash +# If this returns a version >= 5.6, you don't need to do anything +uname -r + +# Install the official Ubuntu hardware enablement kernel +sudo apt install --install-recommends linux-generic-hwe-20.04 +``` + +{% /details %} + +## Install dependencies + +To install all dependencies of a project: + +```bash +$ bun install +``` + +On Linux, `bun install` tends to install packages 20-100x faster than `npm install`. On macOS, it's more like 4-80x. + + + +Running `bun install` will: + +- **Install** all `dependencies`, `devDependencies`, and `optionalDependencies`. Bun does not install `peerDependencies` by default. +- **Run** your project's `{pre|post}install` scripts at the appropriate time. For security reasons Bun _does not execute_ lifecycle scripts of installed dependencies. +- **Write** a `bun.lockb` lockfile to the project root. + +To install in production mode (i.e. without `devDependencies`): + +```bash +$ bun install --production +``` + +To perform a dry run (i.e. don't actually install anything): + +```bash +$ bun install --dry-run +``` + +To modify logging verbosity: + +```bash +$ bun install --verbose # debug logging +$ bun install --silent # no logging +``` + +{% details summary="Configuring behavior" %} +The default behavior of `bun install` can be configured in `bun.toml`: + +```toml +[install] + +# whether to install optionalDependencies +optional = true + +# whether to install devDependencies +dev = true + +# whether to install devDependencies +peer = false + +# equivalent to `--production` flag +production = false + +# equivalent to `--dry-run` flag +dryRun = false +``` + +{% /details %} + +## Adding packages + +To add or remove a particular package: + +```bash +$ bun add preact +$ bun remove preact +``` + +To specify a version, version range, or tag: + +```bash +$ bun add zod@3.20.0 +$ bun add zod@^3.0.0 +$ bun add zod@latest +``` + +To add a package as a dev dependency (`"devDependencies"`): + +```bash +$ bun add --development @types/react +$ bun add -d @types/react +``` + +To add a package as an optional dependency (`"optionalDependencies"`): + +```bash +$ bun add --optional lodash +``` + +To install a package globally: + +```bash +$ bun add --global cowsay # or `bun add -g cowsay` +$ cowsay "Bun!" + ______ +< Bun! > + ------ + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || +``` + +{% details summary="Configuring global installation behavior" %} + +```toml +[install] +# where `bun install --global` installs packages +globalDir = "~/.bun/install/global" + +# where globally-installed package bins are linked +globalBinDir = "~/.bun/bin" +``` + +{% /details %} +To view a complete list of options for a given command: + +```bash +$ bun add --help +``` + +## Global cache + +All packages downloaded from the registry are stored in a global cache at `~/.bun/install/cache`. They are stored in subdirectories named like `${name}@${version}`, so multiple versions of a package can be cached. + +{% details summary="Configuring cache behavior" %} + +```toml +[install.cache] +# the directory to use for the cache +dir = "~/.bun/install/cache" + +# when true, don't load from the global cache. +# Bun may still write to node_modules/.cache +disable = false + +# when true, always resolve the latest versions from the registry +disableManifest = false +``` + +{% /details %} + +### Minimizing re-downloads + +Bun strives to avoid re-downloading packages mutiple times. When installing a package, if the cache already contains a version in the range specified by `package.json`, Bun will use the cached package instead of downloading it again. + +{% details summary="Installation details" %} +If the semver version has pre-release suffix (`1.0.0-beta.0`) or a build suffix (`1.0.0+20220101`), it is replaced with a hash of that value instead, to reduce the chances of errors associated with long file paths. + +When the `node_modules` folder exists, before installing, Bun checks that `node_modules` contains all expected packages with appropriate versions. If so `bun install` completes. Bun uses a custom JSON parser which stops parsing as soon as it finds `"name"` and `"version"`. + +If a package is missing or has a version incompatible with the `package.json`, Bun checks for a compatible module in the cache. If found, it is installed into `node_modules`. Otherwise, the package will be downloaded from the registry then installed. +{% /details %} + +### Fast copying + +Once a package is downloaded into the cache, Bun still needs to copy those files into `node_modules`. Bun uses the fastest syscalls available to perform this task. On Linux, it uses hardlinks; on macOS, it uses `clonefile`. + +### Saving disk space + +Since Bun uses hardlinks to "copy" a module into a project's `node_modules` directory on Linux, the contents of the package only exist in a single location on disk, greatly reducing the amount of disk space dedicated to `node_modules`. + +This benefit does not extend to macOS, which uses `clonefile` for performance reasons. + +{% details summary="Installation strategies" %} +This behavior is configurable with the `--backend` flag, which is respected by all of Bun's package management commands. + +- **`hardlink`**: Default on Linux. +- **`clonefile`** Default on macOS. +- **`clonefile_each_dir`**: Similar to `clonefile`, except it clones each file individually per directory. It is only available on macOS and tends to perform slower than `clonefile`. +- **`copyfile`**: The fallback used when any of the above fail. It is the slowest option. On macOS, it uses `fcopyfile()`; on Linux it uses `copy_file_range()`. + **`symlink`**: Currently used only `file:` (and eventually `link:`) dependencies. To prevent infinite loops, it skips symlinking the `node_modules` folder. + +If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own `node_modules` folder or you pass `--preserve-symlinks` to `node`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks). + +```bash +$ bun install --backend symlink +$ node --preserve-symlinks ./foo.js +``` + +Bun's runtime does not currently expose an equivalent of `--preserve-symlinks`. +{% /details %} + +## Lockfile + +Running `bun install` will create a binary lockfile called `bun.lockb`. + +#### Why is it binary? + +In a word: Performance. Bun’s lockfile saves & loads incredibly quickly, and saves a lot more data than what is typically inside lockfiles. + +#### How do I inspect it? + +Run `bun install -y` to generate a Yarn-compatible `yarn.lock` (v1) that can be inspected more easily. + +#### Platform-specific dependencies? + +Bun stores normalized `cpu` and `os` values from npm in the lockfile, along with the resolved packages. It skips downloading, extracting, and installing packages disabled for the current target at runtime. This means the lockfile won’t change between platforms/architectures even if the packages ultimately installed do change. + +#### What does the lockfile store? + +Packages, metadata for those packages, the hoisted install order, dependencies for each package, what packages those dependencies resolved to, an integrity hash (if available), what each package was resolved to, and which version (or equivalent). + +#### Why is it fast? + +It uses linear arrays for all data. [Packages](https://github.com/oven-sh/bun/blob/be03fc273a487ac402f19ad897778d74b6d72963/src/install/install.zig#L1825) are referenced by an auto-incrementing integer ID or a hash of the package name. Strings longer than 8 characters are de-duplicated. Prior to saving on disk, the lockfile is garbage-collected & made deterministic by walking the package tree and cloning the packages in dependency order. + +#### Can I opt out? + +To install without creating a lockfile: + +```bash +$ bun install --no-save +``` + +To install a Yarn lockfile _in addition_ to `bun.lockb`. + +{% codetabs %} + +```bash#CLI flag +$ bun install --yarn +``` + +```toml#bunfig.toml +[install.lockfile] +# whether to save a non-Bun lockfile alongside bun.lockb +# only "yarn" is supported +print = "yarn" +``` + +{% /codetabs %} + +{% details summary="Configuring lockfile" %} + +```toml +[install.lockfile] + +# path to read bun.lockb from +path = "bun.lockb" + +# path to save bun.lockb to +savePath = "bun.lockb" + +# whether to save the lockfile to disk +save = true + +# whether to save a non-Bun lockfile alongside bun.lockb +# only "yarn" is supported +print = "yarn" +``` + +{% /details %} + +## Workspaces + +Bun supports [`workspaces`](https://docs.npmjs.com/cli/v9/using-npm/workspaces?v=true#description) in `package.json`. Workspaces make it easy to develop complex software as a _monorepo_ consisting of several independent packages. + +To try it, specify a list of sub-packages in the `workspaces` field of your `package.json`; it's conventional to place these sub-packages in a directory called `packages`. + +```json +{ + "name": "my-project", + "version": "1.0.0", + "workspaces": ["packages/a", "packages/b"] +} +``` + +{% callout %} +**Glob support** — Bun doesn't support globs for workspace names yet, but this is coming soon! +{% /callout %} + +This has a couple major benefits. + +- **Code can be split into logical parts.** If one package relies on another, you can simply add it as a dependency with `bun add`. If package `b` depends on `a`, `bun install` will symlink your local `packages/a` directory into the `node_modules` folder of `b`, instead of trying to download it from the npm registry. +- **Dependencies can be de-duplicated.** If `a` and `b` share a common dependency, it will be _hoisted_ to the root `node_modules` directory. This reduces redundant disk usage and minimizes "dependency hell" issues associated with having multiple versions of a package installed simultaneously. + +{% callout %} +⚡️ **Speed** — Installs are fast, even for big monorepos. Bun installs the [Remix](https://github.com/remix-run/remix) monorepo in about `500ms` on Linux. + +- 28x faster than `npm install` +- 12x faster than `yarn install` (v1) +- 8x faster than `pnpm install` + +{% image src="https://user-images.githubusercontent.com/709451/212829600-77df9544-7c9f-4d8d-a984-b2cd0fd2aa52.png" /%} +{% /callout %} + +## Registries + +The default registry is `registry.npmjs.org`. This can be globally configured in `bunfig.toml`: + +```toml +[install] +# set default registry as a string +registry = "https://registry.npmjs.org" +# set a token +registry = { url = "https://registry.npmjs.org", token = "123456" } +# set a username/password +registry = "https://username:password@registry.npmjs.org" +``` + +To configure organization-scoped registries: + +```toml +[install.scopes] +# registry as string +"@myorg1" = "https://username:password@registry.myorg.com/" + +# registry with username/password +# you can reference environment variables +"@myorg2" = { username = "myusername", password = "$NPM_PASS", url = "https://registry.myorg.com/" } + +# registry with token +"@myorg3" = { token = "$npm_token", url = "https://registry.myorg.com/" } +``` diff --git a/docs/cli/run.md b/docs/cli/run.md new file mode 100644 index 000000000..f180868d2 --- /dev/null +++ b/docs/cli/run.md @@ -0,0 +1,156 @@ +The `bun` CLI can be used to execute JavaScript/TypeScript files, `package.json` scripts, and [executable packages](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#bin). + +## Run a file + +{% callout %} +Compare to `node <file>` +{% /callout %} + +Bun can execute `.js`, `.jsx`, `.ts`, and `.tsx` files. Every file is transpiled to vanilla JavaScript by Bun's fast native transpiler before being executed. For details on Bun's runtime, refer to the [Bun runtime](/docs/runtime) documentation. + +```ts#foo.ts +import { z } from "zod"; + +const schema = z.string() +const result = schema.parse("Billie Eilish"); +console.log(result); +``` + +To run a file in Bun: + +```bash +$ bun foo.ts +Billie Eilish +``` + +If no `node_modules` directory is found in the working directory or above, Bun will abandon Node.js-style module resolution in favor of the `Bun module resolution algorithm`. Under Bun-style module resolution, all packages are _auto-installed_ on the fly into a [global module cache](/docs/cli/install#global-cache). For full details on this algorithm, refer to [Runtime > Modules](/docs/runtime/modules). + +## Run a package script + +{% note %} +Compare to `npm run <script>` or `yarn <script>` +{% /note %} + +Your `package.json` can define a number of named `"scripts"` that correspond to shell commands. + +```jsonc +{ + // ... other fields + "scripts": { + "clean": "rm -rf dist && echo 'Done.'", + "dev": "bun server.ts" + } +} +``` + +Use `bun <script>` to execute these scripts. + +```bash +$ bun clean + $ rm -rf dist && echo 'Done.' + Cleaning... + Done. +``` + +Bun executes the script command in a subshell. It checks for the following shells in order, using the first one it finds: `bash`, `sh`, `zsh`. + +{% callout %} +⚡️ The startup time for `npm run` on Linux is roughly 170ms; with Bun it is `6ms`. +{% /callout %} + +If there is a name conflict between a `package.json` script and a built-in `bun` command (`install`, `dev`, `upgrade`, etc.) Bun's built-in command takes precedence. In this case, use the more explicit `bun run` command to execute your package script. + +```bash +$ bun run dev +``` + +To see a list of available scripts, run `bun run` without any arguments. + +```bash +$ bun run +quickstart scripts: + + bun run clean + rm -rf dist && echo 'Done.' + + bun run dev + bun server.ts + +2 scripts +``` + +Bun respects lifecycle hooks. For instance, `bun run clean` will execute `preclean` and `postclean`, if defined. If the `pre<script>` fails, Bun will not execute the script itself. + +## Run an executable + +{% callout %} +Compare to `npx <command>` +{% /callout %} + +Packages can declare executables in the `"bin"` field of their `package.json`. These are known as _package executables_ or _package binaries_. + +```jsonc#package.json +{ + // ... other fields + "name": "my-cli", + "bin": { + "my-cli": "dist/index.js" + } +} +``` + +These executables are commonly plain JavaScript files marked with a [shebang line](<https://en.wikipedia.org/wiki/Shebang_(Unix)>) to indicate which program should be used to execute them. The following file indicates that it should be executed with `node`. + +```js#dist/index.js +#!/usr/bin/env node + +console.log("Hello world!"); +``` + +These executables can be run with `bunx`, Bun's equivalent of `npx`. + +{% callout %} +⚡️ **Speed** — With Bun's fast startup times, `bunx` is [roughly 100x faster](https://twitter.com/jarredsumner/status/1606163655527059458) than `npx` for locally installed packages. +{% /callout %} + +```bash +$ bunx my-cli +``` + +As with `npx`, `bunx` will check for a locally installed package first, then fall back to auto-installing the package from `npm`. Installed packages will be stored in Bun's global cache for future use. + +### Arguments and flags + +To pass additional command-line flags and arguments through to the executable: + +```bash +$ bunx my-cli --foo bar +``` + +### Shebangs + +By default, Bun respects shebangs. If an executable is marked with `#!/usr/bin/env node`, Bun will spin up a `node` process to execute the file. However, in some cases it may be desirable to run executables using [Bun's runtime](/docs/runtime), even if the executable indicates otherwise. To do so, include the `--bun` flag. + +```bash +$ bunx --bun my-cli +``` + +{% callout %} +**Note** — The `--bun` flag must occur _before_ the executable name. Flags that appear _after_ the name are passed through to the executable. + +```bash +$ bunx --bun my-cli # good +$ bunx my-cli --bun # bad +``` + +{% /callout %} + +## Environment variables + +Bun automatically loads environment variables from `.env` files before running a file, script, or executable. The following files are checked, in order: + +1. `.env.local` (first) +2. `NODE_ENV` === `"production"` ? `.env.production` : `.env.development` +3. `.env` + +To debug environment variables, run `bun run env` to view a list of resolved environment variables. diff --git a/docs/cli/test.md b/docs/cli/test.md new file mode 100644 index 000000000..4471a7204 --- /dev/null +++ b/docs/cli/test.md @@ -0,0 +1,224 @@ +Bun ships with a built-in test runner. + +```bash +$ bun wiptest +``` + +The runner recursively searches the working directory for files that match the following patterns: + +- `*.test.{js|jsx|ts|tsx}` +- `*_test.{js|jsx|ts|tsx}` +- `*.spec.{js|jsx|ts|tsx}` +- `*_spec.{js|jsx|ts|tsx}` + +You can filter the set of tests to run by passing additional positional arguments to `wiptest`. Any file in the directory with an _absolute path_ that contains one of the filters will run. Commonly, these filters will be file or directory names; glob patterns are not yet supported. + +```bash +$ bun wiptest <filter> <filter> ... +``` + +<!-- +Consider the following directory structure: + +``` +. +├── a.test.ts +├── b.test.ts +├── c.test.ts +└── foo + ├── a.test.ts + └── b.test.ts +``` + +To run both `a.test.ts` files: + +``` +$ bun wiptest a +``` + +To run all tests in the `foo` directory: + +``` +$ bun wiptest foo +``` + +Any test file in the directory with an _absolute path_ that contains one of the targets will run. Glob patterns are not yet supported. --> + +## Writing tests + +Define tests with a Jest-like API imported from the built-in `bun:test` module. + +```ts#math.test.ts +import { expect, test } from "bun:test"; + +test("2 + 2", () => { + expect(2 + 2).toBe(4); +}); +``` + +Group tests into suites with `describe`. + +```ts#math.test.ts +import { expect, test, describe } from "bun:test"; + +describe("arithmetic", () => { + test("2 + 2", () => { + expect(2 + 2).toBe(4); + }); + + test("2 * 2", () => { + expect(2 * 2).toBe(4); + }); +}); +``` + +Tests can be `async`. + +```ts +import { expect, test } from "bun:test"; + +test("2 * 2", async () => { + const result = await Promise.resolve(2 * 2); + expect(result).toEqual(4); +}); +``` + +Alternatively, use the `done` callback to signal completion. If you include the `done` callback as a parameter in your test definition, you _must_ call it or the test will hang. + +```ts +import { expect, test } from "bun:test"; + +test("2 * 2", done => { + Promise.resolve(2 * 2).then(done => { + expect(result).toEqual(4); + done(); + }); +}); +``` + +Perform per-test setup and teardown logic with `beforeEach` and `afterEach`. + +```ts +import { expect, test } from "bun:test"; + +beforeEach(() => { + console.log("running test."); +}); + +afterEach(() => { + console.log("done with test."); +}); + +// tests... +``` + +Perform per-scope setup and teardown logic with `beforeAll` and `afterAll`. At the top-level, the `*scope* is the current file; in a `describe` block, the scope is the block itself. + +```ts +import { expect, test, beforeAll, afterAll } from "bun:test"; + +let db: Database; +beforeAll(() => { + // connect to database +}); + +afterAll(() => { + // close connection +}); + +// tests... +``` + +Skip individual tests with `test.skip`. + +```ts +import { expect, test } from "bun:test"; + +test.skip("wat", () => { + // TODO: fix this + expect(0.1 + 0.2).toEqual(0.3); +}); +``` + +## Expect matchers + +Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress [here](https://github.com/oven-sh/bun/issues/1825). + +- [x] [`.not`](https://jestjs.io/docs/expect#not) +- [x] [`.toBe()`](https://jestjs.io/docs/expect#tobevalue) +- [x] [`.toEqual()`](https://jestjs.io/docs/expect#toequalvalue) +- [x] [`.toBeNull()`](https://jestjs.io/docs/expect#tobenull) +- [x] [`.toBeUndefined()`](https://jestjs.io/docs/expect#tobeundefined) +- [x] [`.toBeNaN()`](https://jestjs.io/docs/expect#tobenan) +- [x] [`.toBeDefined()`](https://jestjs.io/docs/expect#tobedefined) +- [x] [`.toBeFalsy()`](https://jestjs.io/docs/expect#tobefalsy) +- [x] [`.toBeTruthy()`](https://jestjs.io/docs/expect#tobetruthy) +- [x] [`.toContain()`](https://jestjs.io/docs/expect#tocontainitem) +- [x] [`.toStrictEqual()`](https://jestjs.io/docs/expect#tostrictequalvalue) +- [x] [`.toThrow()`](https://jestjs.io/docs/expect#tothrowerror) +- [x] [`.toHaveLength()`](https://jestjs.io/docs/expect#tohavelengthnumber) +- [x] [`.toHaveProperty()`](https://jestjs.io/docs/expect#tohavepropertykeypath-value) +- [ ] [`.extend`](https://jestjs.io/docs/expect#expectextendmatchers) +- [ ] [`.anything()`](https://jestjs.io/docs/expect#expectanything) +- [ ] [`.any()`](https://jestjs.io/docs/expect#expectanyconstructor) +- [ ] [`.arrayContaining()`](https://jestjs.io/docs/expect#expectarraycontainingarray) +- [ ] [`.assertions()`](https://jestjs.io/docs/expect#expectassertionsnumber) +- [ ] [`.closeTo()`(number, numDigit](https://jestjs.io/docs/expect#expectclosetonumber-numdigits) +- [ ] [`.hasAssertions()`](https://jestjs.io/docs/expect#expecthasassertions) +- [ ] [`.objectContaining()`](https://jestjs.io/docs/expect#expectobjectcontainingobject) +- [ ] [`.stringContaining()`](https://jestjs.io/docs/expect#expectstringcontainingstring) +- [ ] [`.stringMatching()`](https://jestjs.io/docs/expect#expectstringmatchingstring--regexp) +- [ ] [`.addSnapshotSerializer()`](https://jestjs.io/docs/expect#expectaddsnapshotserializerserializer) +- [ ] [`.resolves()`](https://jestjs.io/docs/expect#resolves) +- [ ] [`.rejects()`](https://jestjs.io/docs/expect#rejects) +- [ ] [`.toHaveBeenCalled()`](https://jestjs.io/docs/expect#tohavebeencalled) +- [ ] [`.toHaveBeenCalledTimes()`](https://jestjs.io/docs/expect#tohavebeencalledtimesnumber) +- [ ] [`.toHaveBeenCalledWith()`](https://jestjs.io/docs/expect#tohavebeencalledwitharg1-arg2-) +- [ ] [`.toHaveBeenLastCalledWith()`](https://jestjs.io/docs/expect#tohavebeenlastcalledwitharg1-arg2-) +- [ ] [`.toHaveBeenNthCalledWith()`](https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-) +- [ ] [`.toHaveReturned()`](https://jestjs.io/docs/expect#tohavereturned) +- [ ] [`.toHaveReturnedTimes()`](https://jestjs.io/docs/expect#tohavereturnedtimesnumber) +- [ ] [`.toHaveReturnedWith()`](https://jestjs.io/docs/expect#tohavereturnedwithvalue) +- [ ] [`.toHaveLastReturnedWith()`](https://jestjs.io/docs/expect#tohavelastreturnedwithvalue) +- [ ] [`.toHaveNthReturnedWith()`](https://jestjs.io/docs/expect#tohaventhreturnedwithnthcall-value) +- [ ] [`.toBeCloseTo()`](https://jestjs.io/docs/expect#tobeclosetonumber-numdigits) +- [ ] [`.toBeGreaterThan()`](https://jestjs.io/docs/expect#tobegreaterthannumber--bigint) +- [ ] [`.toBeGreaterThanOrEqual()`](https://jestjs.io/docs/expect#tobegreaterthanorequalnumber--bigint) +- [ ] [`.toBeLessThan()`](https://jestjs.io/docs/expect#tobelessthannumber--bigint) +- [ ] [`.toBeLessThanOrEqual()`](https://jestjs.io/docs/expect#tobelessthanorequalnumber--bigint) +- [ ] [`.toBeInstanceOf()`](https://jestjs.io/docs/expect#tobeinstanceofclass) +- [ ] [`.toContainEqual()`](https://jestjs.io/docs/expect#tocontainequalitem) +- [ ] [`.toMatch()`](https://jestjs.io/docs/expect#tomatchregexp--string) +- [ ] [`.toMatchObject()`](https://jestjs.io/docs/expect#tomatchobjectobject) +- [ ] [`.toMatchSnapshot()`](https://jestjs.io/docs/expect#tomatchsnapshotpropertymatchers-hint) +- [ ] [`.toMatchInlineSnapshot()`](https://jestjs.io/docs/expect#tomatchinlinesnapshotpropertymatchers-inlinesnapshot) +- [ ] [`.toThrowErrorMatchingSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchingsnapshothint) +- [ ] [`.toThrowErrorMatchingInlineSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchinginlinesnapshotinlinesnapshot) + +<!-- ```ts +test('matchers', ()=>{ + + expect(5).toBe(5); + expect("do re mi").toContain("mi"); + expect("do re mi").toEqual("do re mi"); + expect({}).toStrictEqual({}); // uses Bun.deepEquals() + expect([1,2,3]).toHaveLength(3); + expect({ name: "foo" }).toHaveProperty("name"); + expect({ name: "foo" }).toHaveProperty("name", "foo"); + expect(5).toBeTruthy(); + expect(0).toBeFalsy(); + expect("").toBeDefined(); + expect(undefined).toBeUndefined(); + expect(parseInt('tuna')).toBeNaN(); + expect(null).toBeNull(); + expect(5).toBeGreaterThan(4); + expect(5).toBeGreaterThanOrEqual(5); + expect(5).toBeLessThan(6); + expect(5).toBeLessThanOrEqual(5); + expect(()=>throw new Error()).toThrow(); + + // negation + expect(5).not.toBe(4) + +}) +``` --> |