301 lines
63 KiB
Plaintext
301 lines
63 KiB
Plaintext
---
|
|
title: esbuild
|
|
description: Migration guide from esbuild to Bun's bundler
|
|
---
|
|
|
|
Bun's bundler API is heavily inspired by esbuild. This page is a side-by-side comparison of the two APIs.
|
|
|
|
A few behaviors differ:
|
|
|
|
<Note>
|
|
**Bundling by default.** Unlike esbuild, Bun bundles by default; no `--bundle` flag is needed. To transpile each file
|
|
individually, use `Bun.Transpiler`.
|
|
</Note>
|
|
|
|
<Note>
|
|
**Bundler only.** Unlike esbuild, Bun's bundler has no built-in development server. Use it with `Bun.serve` and other
|
|
runtime APIs to get the same effect. esbuild's HTTP options don't apply.
|
|
</Note>
|
|
|
|
## Performance
|
|
|
|
Bun's bundler is 1.75x faster than esbuild on esbuild's three.js benchmark.
|
|
|
|
<Info>Bundling 10 copies of three.js from scratch, with sourcemaps and minification</Info>
|
|
|
|
## CLI API
|
|
|
|
```bash terminal icon="terminal"
|
|
# esbuild
|
|
esbuild <entrypoint> --outdir=out --bundle
|
|
|
|
# bun
|
|
bun build <entrypoint> --outdir=out
|
|
```
|
|
|
|
In Bun's CLI, boolean flags like `--minify` take no argument. Flags that take one, like `--outdir <path>`, can be written as `--outdir out` or `--outdir=out`. Some flags, like `--define`, can be repeated: `--define foo=bar --define bar=baz`.
|
|
|
|
| esbuild | bun build | Notes |
|
|
| ---------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `--bundle` | n/a | Bun always bundles; use `--no-bundle` to disable it. |
|
|
| `--define:K=V` | `--define K=V` | Small syntax difference; no colon.<br/>`esbuild --define:foo=bar`<br/>`bun build --define foo=bar` |
|
|
| `--external:<pkg>` | `--external <pkg>` | Small syntax difference; no colon.<br/>`esbuild --external:react`<br/>`bun build --external react` |
|
|
| `--format` | `--format` | Bun supports `"esm"`, `"cjs"`, and `"iife"`. esbuild defaults to `"iife"`. |
|
|
| `--loader:.ext=loader` | `--loader .ext:loader` | Bun supports a different set of built-in loaders than esbuild; see [loaders](/bundler/loaders). The esbuild loaders `dataurl`, `binary`, `base64`, `copy`, and `empty` are not implemented.<br/><br/>The syntax for `--loader` differs.<br/>`esbuild app.ts --bundle --loader:.svg=text`<br/>`bun build app.ts --loader .svg:text` |
|
|
| `--minify` | `--minify` | No differences |
|
|
| `--outdir` | `--outdir` | No differences |
|
|
| `--outfile` | `--outfile` | No differences |
|
|
| `--packages` | `--packages` | No differences |
|
|
| `--platform` | `--target` | Renamed to `--target` for consistency with tsconfig. Does not support `neutral`. |
|
|
| `--serve` | n/a | Not applicable |
|
|
| `--sourcemap` | `--sourcemap` | Supports `linked` (the default when no value is given), `external`, `inline`, and `none`. Does not support esbuild's `both`. |
|
|
| `--splitting` | `--splitting` | No differences |
|
|
| `--target` | n/a | Not supported. Bun's bundler performs no syntactic down-leveling. |
|
|
| `--watch` | `--watch` | No differences |
|
|
| `--allow-overwrite` | n/a | Bun never allows overwriting |
|
|
| `--analyze` | n/a | Not supported |
|
|
| `--asset-names` | `--asset-naming` | Renamed for consistency with naming in JS API |
|
|
| `--banner` | `--banner` | Only applies to js bundles |
|
|
| `--footer` | `--footer` | Only applies to js bundles |
|
|
| `--certfile` | n/a | Not applicable |
|
|
| `--charset=utf8` | n/a | Not supported |
|
|
| `--chunk-names` | `--chunk-naming` | Renamed for consistency with naming in JS API |
|
|
| `--color` | n/a | Always enabled |
|
|
| `--drop` | `--drop` | |
|
|
| n/a | `--feature` | Bun-specific. Enables feature flags for compile-time dead-code elimination through `import { feature } from "bun:bundle"` |
|
|
| `--entry-names` | `--entry-naming` | Renamed for consistency with naming in JS API |
|
|
| `--global-name` | n/a | Not supported |
|
|
| `--ignore-annotations` | `--ignore-dce-annotations` | |
|
|
| `--inject` | n/a | Not supported |
|
|
| `--jsx` | `--jsx-runtime <runtime>` | Supports `"automatic"` (uses jsx transform) and `"classic"` (uses `React.createElement`) |
|
|
| `--jsx-dev` | n/a | Bun reads `compilerOptions.jsx` from `tsconfig.json` to determine a default. If `compilerOptions.jsx` is `"react-jsx"`, or if `NODE_ENV=production`, Bun uses the jsx transform. Otherwise, it uses `jsxDEV`. The bundler does not support `preserve`. |
|
|
| `--jsx-factory` | `--jsx-factory` | |
|
|
| `--jsx-fragment` | `--jsx-fragment` | |
|
|
| `--jsx-import-source` | `--jsx-import-source` | |
|
|
| `--jsx-side-effects` | `--jsx-side-effects` | |
|
|
| `--keep-names` | `--keep-names` | |
|
|
| `--keyfile` | n/a | Not applicable |
|
|
| `--legal-comments` | n/a | Not supported |
|
|
| `--log-level` | n/a | Not supported. You can set the log level in `bunfig.toml` as `logLevel`. |
|
|
| `--log-limit` | n/a | Not supported |
|
|
| `--log-override:X=Y` | n/a | Not supported |
|
|
| `--main-fields` | n/a | Not supported |
|
|
| `--mangle-cache` | n/a | Not supported |
|
|
| `--mangle-props` | n/a | Not supported |
|
|
| `--mangle-quoted` | n/a | Not supported |
|
|
| `--metafile` | `--metafile` | |
|
|
| `--minify-whitespace` | `--minify-whitespace` | |
|
|
| `--minify-identifiers` | `--minify-identifiers` | |
|
|
| `--minify-syntax` | `--minify-syntax` | |
|
|
| `--out-extension` | n/a | Not supported |
|
|
| `--outbase` | `--root` | |
|
|
| `--preserve-symlinks` | n/a | Not supported |
|
|
| `--public-path` | `--public-path` | |
|
|
| `--pure` | n/a | Not supported |
|
|
| `--reserve-props` | n/a | Not supported |
|
|
| `--resolve-extensions` | n/a | Not supported |
|
|
| `--servedir` | n/a | Not applicable |
|
|
| `--source-root` | n/a | Not supported |
|
|
| `--sourcefile` | n/a | Not supported. Bun does not support stdin input. |
|
|
| `--sources-content` | n/a | Not supported |
|
|
| `--supported` | n/a | Not supported |
|
|
| `--tree-shaking` | n/a | Always true |
|
|
| `--tsconfig` | `--tsconfig-override` | |
|
|
| `--version` | n/a | Run `bun --version` to see the version of Bun. |
|
|
|
|
## JavaScript API
|
|
|
|
| esbuild.build() | Bun.build() | Notes |
|
|
| ------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
| `absWorkingDir` | n/a | Always set to `process.cwd()` |
|
|
| `alias` | n/a | Not supported |
|
|
| `allowOverwrite` | n/a | Always false |
|
|
| `assetNames` | `naming.asset` | Uses the same templating syntax as esbuild, but you must include `[ext]` explicitly.<br/><br/>`ts<br/>Bun.build({<br/> entrypoints: ["./index.tsx"],<br/> naming: {<br/> asset: "[name].[ext]",<br/> },<br/>});<br/>` |
|
|
| `banner` | `banner` | Only applies to js bundles |
|
|
| `bundle` | n/a | Always true. Use `Bun.Transpiler` to transpile without bundling. |
|
|
| `charset` | n/a | Not supported |
|
|
| `chunkNames` | `naming.chunk` | Uses the same templating syntax as esbuild, but you must include `[ext]` explicitly.<br/><br/>`ts<br/>Bun.build({<br/> entrypoints: ["./index.tsx"],<br/> naming: {<br/> chunk: "[name].[ext]",<br/> },<br/>});<br/>` |
|
|
| `color` | n/a | Bun returns logs in the `logs` property of the build result. |
|
|
| `conditions` | `conditions` | No differences |
|
|
| `define` | `define` | |
|
|
| `drop` | `drop` | |
|
|
| `entryNames` | `naming` or `naming.entry` | Bun supports a `naming` key that can either be a string or an object. Uses the same templating syntax as esbuild, but you must include `[ext]` explicitly.<br/><br/>`ts<br/>Bun.build({<br/> entrypoints: ["./index.tsx"],<br/> // when string, this is equivalent to entryNames<br/> naming: "[name].[ext]",<br/><br/> // granular naming options<br/> naming: {<br/> entry: "[name].[ext]",<br/> asset: "[name].[ext]",<br/> chunk: "[name].[ext]",<br/> },<br/>});<br/>` |
|
|
| `entryPoints` | `entrypoints` | Capitalization difference |
|
|
| `external` | `external` | No differences |
|
|
| `footer` | `footer` | Only applies to js bundles |
|
|
| `format` | `format` | Supports `"esm"`, `"cjs"`, and `"iife"`. |
|
|
| `globalName` | n/a | Not supported |
|
|
| `ignoreAnnotations` | `ignoreDCEAnnotations` | |
|
|
| `inject` | n/a | Not supported |
|
|
| `jsx` | `jsx.runtime` | Supports `"automatic"` and `"classic"` |
|
|
| `jsxDev` | `jsx.development` | |
|
|
| `jsxFactory` | `jsx.factory` | |
|
|
| `jsxFragment` | `jsx.fragment` | |
|
|
| `jsxImportSource` | `jsx.importSource` | |
|
|
| `jsxSideEffects` | `jsx.sideEffects` | |
|
|
| `keepNames` | `minify.keepNames` | |
|
|
| `legalComments` | n/a | Not supported |
|
|
| `loader` | `loader` | Bun supports a different set of built-in loaders than esbuild; see [loaders](/bundler/loaders). Bun does not implement the esbuild loaders `dataurl`, `binary`, `base64`, `copy`, and `empty`. |
|
|
| `logLevel` | n/a | Not supported |
|
|
| `logLimit` | n/a | Not supported |
|
|
| `logOverride` | n/a | Not supported |
|
|
| `mainFields` | n/a | Not supported |
|
|
| `mangleCache` | n/a | Not supported |
|
|
| `mangleProps` | n/a | Not supported |
|
|
| `mangleQuoted` | n/a | Not supported |
|
|
| `metafile` | `metafile` | |
|
|
| `minify` | `minify` | In Bun, `minify` can be a boolean or an object.<br/><br/>`ts<br/>await Bun.build({<br/> entrypoints: ['./index.tsx'],<br/> // enable all minification<br/> minify: true<br/><br/> // granular options<br/> minify: {<br/> identifiers: true,<br/> syntax: true,<br/> whitespace: true<br/> }<br/>})<br/>` |
|
|
| `minifyIdentifiers` | `minify.identifiers` | See `minify` |
|
|
| `minifySyntax` | `minify.syntax` | See `minify` |
|
|
| `minifyWhitespace` | `minify.whitespace` | See `minify` |
|
|
| `nodePaths` | n/a | Not supported |
|
|
| `outExtension` | n/a | Not supported |
|
|
| `outbase` | `root` | Different name |
|
|
| `outdir` | `outdir` | No differences |
|
|
| `outfile` | `outfile` | No differences |
|
|
| `packages` | `packages` | No differences |
|
|
| `platform` | `target` | Supports `"bun"`, `"node"` and `"browser"` (the default). Does not support `"neutral"`. |
|
|
| `plugins` | `plugins` | Bun's plugin API is a subset of esbuild's. Some esbuild plugins work with Bun without modification. |
|
|
| `preserveSymlinks` | n/a | Not supported |
|
|
| `publicPath` | `publicPath` | No differences |
|
|
| `pure` | n/a | Not supported |
|
|
| `reserveProps` | n/a | Not supported |
|
|
| `resolveExtensions` | n/a | Not supported |
|
|
| `sourceRoot` | n/a | Not supported |
|
|
| `sourcemap` | `sourcemap` | Supports `"none"`, `"linked"`, `"inline"`, and `"external"` |
|
|
| `sourcesContent` | n/a | Not supported |
|
|
| `splitting` | `splitting` | No differences |
|
|
| `stdin` | n/a | Not supported |
|
|
| `supported` | n/a | Not supported |
|
|
| `target` | n/a | No support for syntax downleveling |
|
|
| `treeShaking` | `treeShaking` | Defaults to `true` |
|
|
| `tsconfig` | `tsconfig` | |
|
|
| `write` | n/a | Set to true if `outdir`/`outfile` is set, otherwise false |
|
|
|
|
## Plugin API
|
|
|
|
Bun's plugin API is designed to be esbuild-compatible. Bun doesn't support esbuild's entire plugin API surface, but it implements the core functionality. Many third-party esbuild plugins work with Bun without modification.
|
|
|
|
<Note>
|
|
Long term, we aim for feature parity with esbuild's API. If something doesn't work, file an issue to help us
|
|
prioritize.
|
|
</Note>
|
|
|
|
In both Bun and esbuild, you define plugins with a builder object.
|
|
|
|
```ts title="myPlugin.ts" icon="/icons/typescript.svg"
|
|
import type { BunPlugin } from "bun";
|
|
|
|
const myPlugin: BunPlugin = {
|
|
name: "my-plugin",
|
|
setup(builder) {
|
|
// define plugin
|
|
},
|
|
};
|
|
```
|
|
|
|
The builder object's methods hook into parts of the bundling process. Bun implements `onStart`, `onEnd`, `onResolve`, and `onLoad`; it does not implement the esbuild hooks `onDispose` and `resolve`. Bun partially implements `initialOptions`: the object is read-only and exposes only a subset of esbuild's options. Use `config` (the same thing in Bun's `BuildConfig` format) instead.
|
|
|
|
```ts title="myPlugin.ts" icon="/icons/typescript.svg"
|
|
import type { BunPlugin } from "bun";
|
|
const myPlugin: BunPlugin = {
|
|
name: "my-plugin",
|
|
setup(builder) {
|
|
builder.onStart(() => {
|
|
/* called when the bundle starts */
|
|
});
|
|
builder.onResolve(
|
|
{
|
|
/* onResolve.options */
|
|
},
|
|
args => {
|
|
return {
|
|
/* onResolve.results */
|
|
};
|
|
},
|
|
);
|
|
builder.onLoad(
|
|
{
|
|
/* onLoad.options */
|
|
},
|
|
args => {
|
|
return {
|
|
/* onLoad.results */
|
|
};
|
|
},
|
|
);
|
|
builder.onEnd(result => {
|
|
/* called when the bundle is complete */
|
|
});
|
|
},
|
|
};
|
|
```
|
|
|
|
### onResolve
|
|
|
|
<Tabs>
|
|
<Tab title="options">
|
|
|
|
- 🟢 `filter`
|
|
- 🟢 `namespace`
|
|
|
|
</Tab>
|
|
<Tab title="arguments">
|
|
|
|
- 🟢 `path`
|
|
- 🟢 `importer`
|
|
- 🟢 `namespace`
|
|
- 🟢 `resolveDir`
|
|
- 🟢 `kind`
|
|
- 🔴 `pluginData`
|
|
|
|
</Tab>
|
|
<Tab title="results">
|
|
|
|
- 🟢 `namespace`
|
|
- 🟢 `path`
|
|
- 🔴 `errors`
|
|
- 🟢 `external`
|
|
- 🔴 `pluginData`
|
|
- 🔴 `pluginName`
|
|
- 🔴 `sideEffects`
|
|
- 🔴 `suffix`
|
|
- 🔴 `warnings`
|
|
- 🔴 `watchDirs`
|
|
- 🔴 `watchFiles`
|
|
|
|
</Tab>
|
|
</Tabs>
|
|
|
|
### onLoad
|
|
|
|
<Tabs>
|
|
<Tab title="options">
|
|
|
|
- 🟢 `filter`
|
|
- 🟢 `namespace`
|
|
|
|
</Tab>
|
|
<Tab title="arguments">
|
|
|
|
- 🟢 `path`
|
|
- 🟢 `namespace`
|
|
- 🔴 `suffix`
|
|
- 🔴 `pluginData`
|
|
|
|
</Tab>
|
|
<Tab title="results">
|
|
|
|
- 🟢 `contents`
|
|
- 🟢 `loader`
|
|
- 🔴 `errors`
|
|
- 🔴 `pluginData`
|
|
- 🔴 `pluginName`
|
|
- 🔴 `resolveDir`
|
|
- 🔴 `warnings`
|
|
- 🔴 `watchDirs`
|
|
- 🔴 `watchFiles`
|
|
|
|
</Tab>
|
|
</Tabs>
|