Movatterモバイル変換


[0]ホーム

URL:


DocsGuidesBlog
Discord logoDiscord logo
Discord
GitHub logoGitHub logo

Intro

What is Bun?

Installation

Quickstart

TypeScript

Templating

bun init

bun create

Runtime

bun run

File types

TypeScript

JSX

Environment variables

Bun APIs

Web APIs

Node.js compatibility

Single-file executable

Plugins

Watch mode

Module resolution

Auto-install

bunfig.toml

Debugger

Framework APISOON

Package manager

bun install

bun add

bun remove

bun update

bun publish

bun outdated

bun link

bun pm

Global cache

Workspaces

Lifecycle scripts

Filter

Lockfile

Scopes and registries

Overrides and resolutions

Patch dependencies

.npmrc support

Bundler

Bun.build

HTML & static sites

CSS

Fullstack Dev Server

Hot reloading

Loaders

Plugins

Macros

vs esbuild

Test runner

bun test

Writing tests

Watch mode

Lifecycle hooks

Mocks

Snapshots

Dates and times

DOM testing

Code coverage

Package runner

bunx

API

HTTP server

HTTP client

WebSockets

Workers

Binary data

Streams

SQL

S3 Object Storage

File I/O

import.meta

SQLite

FileSystemRouter

TCP sockets

UDP sockets

Globals

$ Shell

Child processes

HTMLRewriter

Hashing

Console

Cookie

FFI

C Compiler

Testing

Utils

Node-API

Glob

DNS

Semver

Color

Transpiler

Project

Roadmap

Benchmarking

Contributing

Building Windows

Bindgen

License

Bun logoBunBun

Search the docs...

/

Intro

What is Bun?

Installation

Quickstart

TypeScript

Templating

bun init

bun create

Runtime

bun run

File types

TypeScript

JSX

Environment variables

Bun APIs

Web APIs

Node.js compatibility

Single-file executable

Plugins

Usage
Third-party plugins
Loaders
Virtual Modules
Overriding existing modules
Reading or modifying the config
Lifecycle hooks
Reference
Namespaces
onStart
onResolve
onLoad

Watch mode

Module resolution

Auto-install

bunfig.toml

Debugger

Framework APISOON

Package manager

bun install

bun add

bun remove

bun update

bun publish

bun outdated

bun link

bun pm

Global cache

Workspaces

Lifecycle scripts

Filter

Lockfile

Scopes and registries

Overrides and resolutions

Patch dependencies

.npmrc support

Bundler

Bun.build

HTML & static sites

CSS

Fullstack Dev Server

Hot reloading

Loaders

Plugins

Macros

vs esbuild

Test runner

bun test

Writing tests

Watch mode

Lifecycle hooks

Mocks

Snapshots

Dates and times

DOM testing

Code coverage

Package runner

bunx

API

HTTP server

HTTP client

WebSockets

Workers

Binary data

Streams

SQL

S3 Object Storage

File I/O

import.meta

SQLite

FileSystemRouter

TCP sockets

UDP sockets

Globals

$ Shell

Child processes

HTMLRewriter

Hashing

Console

Cookie

FFI

C Compiler

Testing

Utils

Node-API

Glob

DNS

Semver

Color

Transpiler

Project

Roadmap

Benchmarking

Contributing

Building Windows

Bindgen

License

Plugins

GitHub logoGitHub logo

Edit on GitHub

Bun provides a universal plugin API that can be used to extend both theruntime andbundler.

Plugins intercept imports and perform custom loading logic: reading files, transpiling code, etc. They can be used to add support for additional file types, like.scss or.yaml. In the context of Bun's bundler, plugins can be used to implement framework-level features like CSS extraction, macros, and client-server code co-location.

Usage

A plugin is defined as simple JavaScript object containing aname property and asetup function. Register a plugin with Bun using theplugin function.

myPlugin.ts
import { plugin,type BunPlugin }from"bun";const myPlugin:BunPlugin= {  name:"Custom loader",setup(build) {// implementation  },};plugin(myPlugin);

Plugins have to be loaded before any other code runs! To achieve this, use thepreload option in yourbunfig.toml. Bun automatically loads the files/modules specified inpreload before running a file.

preload= ["./myPlugin.ts"]

To preload files beforebun test:

[test]preload= ["./myPlugin.ts"]

Third-party plugins

By convention, third-party plugins intended for consumption should export a factory function that accepts some configuration and returns a plugin object.

import { plugin }from"bun";import fooPluginfrom"bun-plugin-foo";plugin(fooPlugin({// configuration  }),);

Bun's plugin API is loosely based onesbuild. Onlya subset of the esbuild API is implemented, but some esbuild plugins "just work" in Bun, like the officialMDX loader:

import { plugin }from"bun";import mdxfrom"@mdx-js/esbuild";plugin(mdx());

Loaders

Plugins are primarily used to extend Bun with loaders for additional file types. Let's look at a simple plugin that implements a loader for.yaml files.

yamlPlugin.ts
import { plugin }from"bun";awaitplugin({  name:"YAML",asyncsetup(build) {const { load }=awaitimport("js-yaml");// when a .yaml file is imported...    build.onLoad({ filter:/\.(yaml|yml)$/ },async (args)=> {// read and parse the fileconst text=await Bun.file(args.path).text();const exports=load(text)asRecord<string,any>;// and returns it as a modulereturn {        exports,        loader:"object",// special loader for JS objects      };    });  },});

Register this file inpreload:

bunfig.toml
preload= ["./yamlPlugin.ts"]

Once the plugin is registered,.yaml and.yml files can be directly imported.

index.ts
data.yml
index.ts
import datafrom"./data.yml"console.log(data);
data.yml
name:Fast XreleaseYear:2023

Note that the returned object has aloader property. This tells Bun which of its internal loaders should be used to handle the result. Even though we're implementing a loader for.yaml, the result must still be understandable by one of Bun's built-in loaders. It's loaders all the way down.

In this case we're using"object"—a built-in loader (intended for use by plugins) that converts a plain JavaScript object to an equivalent ES module. Any of Bun's built-in loaders are supported; these same loaders are used by Bun internally for handling files of various kinds. The table below is a quick reference; refer toBundler > Loaders for complete documentation.

LoaderExtensionsOutput
js.mjs.cjsTranspile to JavaScript files
jsx.js.jsxTransform JSX then transpile
ts.ts.mts.ctsTransform TypeScript then transpile
tsx.tsxTransform TypeScript, JSX, then transpile
toml.tomlParse using Bun's built-in TOML parser
json.jsonParse using Bun's built-in JSON parser
napi.nodeImport a native Node.js addon
wasm.wasmImport a native Node.js addon
objectnoneA special loader intended for plugins that converts a plain JavaScript object to an equivalent ES module. Each key in the object corresponds to a named export.

Loading a YAML file is useful, but plugins support more than just data loading. Let's look at a plugin that lets Bun import*.svelte files.

sveltePlugin.ts
import { plugin }from"bun";awaitplugin({  name:"svelte loader",asyncsetup(build) {const { compile }=awaitimport("svelte/compiler");// when a .svelte file is imported...    build.onLoad({ filter:/\.svelte$/ },async ({path })=> {// read and compile it with the Svelte compilerconst file=await Bun.file(path).text();const contents=compile(file, {        filename: path,        generate:"ssr",      }).js.code;// and return the compiled source code as "js"return {        contents,        loader:"js",      };    });  },});

Note: in a production implementation, you'd want to cache the compiled output and include additional error handling.

The object returned frombuild.onLoad contains the compiled source code incontents and specifies"js" as its loader. That tells Bun to consider the returnedcontents to be a JavaScript module and transpile it using Bun's built-injs loader.

With this plugin, Svelte components can now be directly imported and consumed.

import"./sveltePlugin.ts";import MySvelteComponentfrom"./component.svelte";console.log(MySvelteComponent.render());

Virtual Modules

This feature is currently only available at runtime withBun.plugin and not yet supported in the bundler, but you can mimic the behavior usingonResolve andonLoad.

To create virtual modules at runtime, usebuilder.module(specifier, callback) in thesetup function of aBun.plugin.

For example:

import { plugin }from"bun";plugin({  name:"my-virtual-module",setup(build) {    build.module(// The specifier, which can be any string - except a built-in, such as "buffer""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 workimport"my-transpiled-virtual-module";require("my-transpiled-virtual-module");awaitimport("my-transpiled-virtual-module");require.resolve("my-transpiled-virtual-module");import { foo }from"my-object-virtual-module";const object=require("my-object-virtual-module");awaitimport("my-object-virtual-module");require.resolve("my-object-virtual-module");

Overriding existing modules

You can also override existing modules withbuild.module.

import { plugin }from"bun";build.module("my-object-virtual-module", ()=> {return {    exports: {      foo:"bar",    },    loader:"object",  };});require("my-object-virtual-module");// { foo: "bar" }awaitimport("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" }awaitimport("my-object-virtual-module");// { baz: "quix" }

Reading or modifying the config

Plugins can read and write to thebuild config withbuild.config.

await Bun.build({  entrypoints: ["./app.ts"],  outdir:"./dist",  sourcemap:"external",  plugins: [    {      name:"demo",setup(build) {        console.log(build.config.sourcemap);// "external"        build.config.minify=true;// enable minification// `plugins` is readonly        console.log(`Number of plugins:${build.config.plugins.length}`);      },    },  ],});

NOTE: Plugin lifecycle callbacks (onStart(),onResolve(), etc.) do not have the ability to modify thebuild.config object in thesetup() function. If you want to mutatebuild.config, you must do so directly in thesetup() function:

await Bun.build({  entrypoints: ["./app.ts"],  outdir:"./dist",  sourcemap:"external",  plugins: [    {      name:"demo",setup(build) {// ✅ good! modifying it directly in the setup() function        build.config.minify=true;        build.onStart(()=> {// 🚫 uh-oh! this won't work!          build.config.minify=false;        });      },    },  ],});

Lifecycle hooks

Plugins can register callbacks to be run at various points in the lifecycle of a bundle:

Reference

A rough overview of the types (please refer to Bun'sbun.d.ts for the full type definitions):

namespaceBun {functionplugin(plugin: {    name:string;setup: (build:PluginBuilder)=>void;  }):void;}typePluginBuilder= {onStart(callback: ()=>void):void;onResolve: (args: { filter:RegExp; namespace?:string },callback: (args: { path:string; importer:string })=> {      path:string;      namespace?:string;    }|void,  )=>void;onLoad: (args: { filter:RegExp; namespace?:string },callback: (args: { path:string })=> {      loader?:Loader;      contents?:string;      exports?:Record<string,any>;    },  )=>void;  config:BuildConfig;};typeLoader="js"|"jsx"|"ts"|"tsx"|"css"|"json"|"toml"|"object";

Namespaces

onLoad andonResolve accept an optionalnamespace string. What is a namespace?

Every module has a namespace. Namespaces are used to prefix the import in transpiled code; for instance, a loader with afilter: /\.yaml$/ andnamespace: "yaml:" will transform an import from./myfile.yaml intoyaml:./myfile.yaml.

The default namespace is"file" and it is not necessary to specify it, for instance:import myModule from "./my-module.ts" is the same asimport myModule from "file:./my-module.ts".

Other common namespaces are:

  • "bun": for Bun-specific modules (e.g."bun:test","bun:sqlite")
  • "node": for Node.js modules (e.g."node:fs","node:path")

onStart

onStart(callback: ()=>void):Promise<void>|void;

Registers a callback to be run when the bundler starts a new bundle.

import { plugin }from"bun";plugin({  name:"onStart example",setup(build) {    build.onStart(()=> {      console.log("Bundle started!");    });  },});

The callback can return aPromise. After the bundle process has initialized, the bundler waits until allonStart() callbacks have completed before continuing.

For example:

const result=await Bun.build({  entrypoints: ["./app.ts"],  outdir:"./dist",  sourcemap:"external",  plugins: [    {      name:"Sleep for 10 seconds",setup(build) {        build.onStart(async ()=> {await Bunlog.sleep(10_000);        });      },    },    {      name:"Log bundle time to a file",setup(build) {        build.onStart(async ()=> {const now=Date.now();awaitBun.$`echo${now} > bundle-time.txt`;        });      },    },  ],});

In the above example, Bun will wait until the firstonStart() (sleeping for 10 seconds) has completed,as well as the secondonStart() (writing the bundle time to a file).

Note thatonStart() callbacks (like every other lifecycle callback) do not have the ability to modify thebuild.config object. If you want to mutatebuild.config, you must do so directly in thesetup() function.

onResolve

onResolve(  args: { filter:RegExp; namespace?: string },  callback: (args: { path:string; importer:string })=> {    path: string;    namespace?: string;  }|void,):void;

To bundle your project, Bun walks down the dependency tree of all modules in your project. For each imported module, Bun actually has to find and read that module. The "finding" part is known as "resolving" a module.

TheonResolve() plugin lifecycle callback allows you to configure how a module is resolved.

The first argument toonResolve() is an object with afilter andnamespace property. The filter is a regular expression which is run on the import string. Effectively, these allow you to filter which modules your custom resolution logic will apply to.

The second argument toonResolve() is a callback which is run for each module import Bun finds that matches thefilter andnamespace defined in the first argument.

The callback receives as input thepath to the matching module. The callback can return anew path for the module. Bun will read the contents of thenew path and parse it as a module.

For example, redirecting all imports toimages/ to./public/images/:

import { plugin }from"bun";plugin({  name:"onResolve example",setup(build) {    build.onResolve({ filter:/.*/, namespace:"file" },args=> {if (args.path.startsWith("images/")) {return {          path: args.path.replace("images/","./public/images/"),        };      }    });  },});

onLoad

onLoad(  args: { filter:RegExp; namespace?: string },  callback: (args: { path:string, importer:string, namespace:string, kind:ImportKind  })=> {    loader?: Loader;    contents?: string;exports?: Record<string, any>;  },):void;

After Bun's bundler has resolved a module, it needs to read the contents of the module and parse it.

TheonLoad() plugin lifecycle callback allows you to modify thecontents of a module before it is read and parsed by Bun.

LikeonResolve(), the first argument toonLoad() allows you to filter which modules this invocation ofonLoad() will apply to.

The second argument toonLoad() is a callback which is run for each matching modulebefore Bun loads the contents of the module into memory.

This callback receives as input thepath to the matching module, theimporter of the module (the module that imported the module), thenamespace of the module, and thekind of the module.

The callback can return a newcontents string for the module as well as a newloader.

For example:

import { plugin }from"bun";plugin({  name:"env plugin",setup(build) {    build.onLoad({ filter:/env/, namespace:"file" },args=> {return {        contents:`export default${JSON.stringify(process.env)}`,        loader:"js",      };    });  },});

This plugin will transform all imports of the formimport env from "env" into a JavaScript module that exports the current environment variables.

Previous

Single-file executable

Next

Watch mode

GitHub logoGitHub logo

Edit on GitHub


[8]ページ先頭

©2009-2025 Movatter.jp