Bun

vs esbuild

Bun 的打包器 API 在很大程度上受到了 esbuild 的启发。从 esbuild 迁移到 Bun 的打包器应该相对容易。本指南将简要介绍您可能为何考虑迁移到 Bun 的打包器,并为那些已经熟悉 esbuild API 的用户提供并排的 API 比较参考。

有几点行为差异需要注意。

  • 默认打包。与 esbuild 不同,Bun 默认始终打包。这就是为什么在 Bun 示例中不需要 --bundle 标志。要单独转译每个文件,请使用 Bun.Transpiler
  • 仅是打包器。与 esbuild 不同,Bun 的打包器不包含内置的开发服务器或文件监视器。它只是一个打包器。该打包器旨在与 Bun.serve 和其他运行时 API 结合使用以达到相同的效果。因此,与 HTTP/文件监视相关的所有选项都不适用。

性能

凭借以性能为导向的 API,结合广泛优化的基于 Zig 的 JS/TS 解析器,Bun 的打包器在 esbuild 的 three.js 基准测试上比 esbuild 快 1.75 倍。

从头开始打包 10 个 three.js 副本,包含 sourcemaps 和压缩

CLI API

Bun 和 esbuild 都提供命令行界面。

esbuild <entrypoint> --outdir=out --bundle
bun build <entrypoint> --outdir=out

在 Bun 的 CLI 中,简单的布尔标志(如 --minify)不接受参数。其他标志(如 --outdir <path>)则接受参数;这些标志可以写成 --outdir out--outdir=out。一些标志(如 --define)可以指定多次:--define foo=bar --define bar=baz

esbuildbun build
--bundle不适用Bun 始终打包,使用 --no-bundle 禁用此行为。

--define:K=V

--define K=V

语法上的小差异;没有冒号。

esbuild --define:foo=bar
bun build --define foo=bar

--external:<pkg>

--external <pkg>

语法上的小差异;没有冒号。

esbuild --external:react
bun build --external react
--format--formatBun 目前支持 "esm""cjs",但计划支持更多模块格式。esbuild 默认为 "iife"

--loader:.ext=loader

--loader .ext:loader

Bun 支持一套与 esbuild 不同的内置加载器;有关完整参考,请参阅 Bundler > Loaders。esbuild 加载器 dataurlbinarybase64copyempty 尚未实现。

--loader 的语法略有不同。

esbuild app.ts --bundle --loader:.svg=text
bun build app.ts --loader .svg:text
--minify--minify无差异
--outdir--outdir无差异
--outfile--outfile
--packages--packages无差异
--platform--target为了与 tsconfig 保持一致,已重命名为 --target。不支持 neutral
--serve不适用不适用
--sourcemap--sourcemap无差异
--splitting--splitting无差异
--target不适用不支持。Bun 的打包器目前不执行任何语法降级。
--watch--watch无差异
--allow-overwrite不适用从不允许覆盖
--analyze不适用不支持
--asset-names--asset-naming为了与 JS API 中的 naming 保持一致而重命名
--banner--banner仅适用于 js 包
--footer--footer仅适用于 js 包
--certfile不适用不适用
--charset=utf8不适用不支持
--chunk-names--chunk-naming为了与 JS API 中的 naming 保持一致而重命名
--color不适用始终启用
--drop--drop
--entry-names--entry-naming为了与 JS API 中的 naming 保持一致而重命名
--global-name不适用不适用,Bun 目前不支持 iife 输出
--ignore-annotations--ignore-dce-annotations
--inject不适用不支持
--jsx--jsx-runtime <runtime>支持 "automatic"(使用 jsx 转换)和 "classic"(使用 React.createElement
--jsx-dev不适用Bun 从 tsconfig.json 读取 compilerOptions.jsx 以确定默认值。如果 compilerOptions.jsx"react-jsx",或者 NODE_ENV=production,Bun 将使用 jsx 转换。否则,它将使用 jsxDEV。对于任何 to Bun 都使用 jsxDEV。打包器不支持 preserve
--jsx-factory--jsx-factory
--jsx-fragment--jsx-fragment
--jsx-import-source--jsx-import-source
--jsx-side-effects--jsx-side-effects控制 JSX 表达式是否被标记为 /* @__PURE__ */ 以进行死代码消除。默认为 false(JSX 被标记为 pure)。
--keep-names不适用不支持
--keyfile不适用不适用
--legal-comments不适用不支持
--log-level不适用不支持。这可以在 bunfig.toml 中设置为 logLevel
--log-limit不适用不支持
--log-override:X=Y不适用不支持
--main-fields不适用不支持
--mangle-cache不适用不支持
--mangle-props不适用不支持
--mangle-quoted不适用不支持
--metafile不适用不支持
--minify-whitespace--minify-whitespace
--minify-identifiers--minify-identifiers
--minify-syntax--minify-syntax
--out-extension不适用不支持
--outbase--root
--preserve-symlinks不适用不支持
--public-path--public-path
--pure不适用不支持
--reserve-props不适用不支持
--resolve-extensions不适用不支持
--servedir不适用不适用
--source-root不适用不支持
--sourcefile不适用不支持。Bun 尚不支持 stdin 输入。
--sourcemap--sourcemap无差异
--sources-content不适用不支持
--supported不适用不支持
--tree-shaking不适用始终为 true
--tsconfig--tsconfig-override
--version不适用运行 bun --version 以查看 Bun 的版本。

JavaScript API

esbuild.build()Bun.build()
absWorkingDir不适用始终设置为 process.cwd()
alias不适用不支持
allowOverwrite不适用始终为 false

assetNames

naming.asset

使用与 esbuild 相同的模板语法,但 [ext] 必须明确包含。

Bun.build({
  entrypoints: ["./index.tsx"],
  naming: {
    asset: "[name].[ext]",
  },
});
banner不适用不支持
bundle不适用始终为 true。使用 Bun.Transpiler 进行无打包转译。
charset不适用不支持

chunkNames

naming.chunk

使用与 esbuild 相同的模板语法,但 [ext] 必须明确包含。

Bun.build({
  entrypoints: ["./index.tsx"],
  naming: {
    chunk: "[name].[ext]",
  },
});
color不适用Bun 在构建结果的 logs 属性中返回日志。
conditions不适用不支持。导出条件优先级由 target 确定。
definedefine
drop不适用不支持

entryNames

namingnaming.entry

Bun 支持一个 naming 键,它可以是字符串或对象。使用与 esbuild 相同的模板语法,但 [ext] 必须明确包含。

Bun.build({
  entrypoints: ["./index.tsx"],
  // when string, this is equivalent to entryNames
  naming: "[name].[ext]",

  // granular naming options
  naming: {
    entry: "[name].[ext]",
    asset: "[name].[ext]",
    chunk: "[name].[ext]",
  },
});
entryPointsentrypoints大小写差异
externalexternal无差异
footer不适用不支持
formatformat目前仅支持 "esm"。计划支持 "cjs""iife"
globalName不适用不支持
ignoreAnnotations不适用不支持
inject不适用不支持
jsxjsxJS API 中不支持,在 tsconfig.json 中配置
jsxDevjsxDevJS API 中不支持,在 tsconfig.json 中配置
jsxFactoryjsxFactoryJS API 中不支持,在 tsconfig.json 中配置
jsxFragmentjsxFragmentJS API 中不支持,在 tsconfig.json 中配置
jsxImportSourcejsxImportSourceJS API 中不支持,在 tsconfig.json 中配置
jsxSideEffectsjsxSideEffects控制 JSX 表达式是否被标记为 pure 以进行死代码消除
keepNames不适用不支持
legalComments不适用不支持
loaderloaderBun 支持一套与 esbuild 不同的内置加载器;有关完整参考,请参阅 Bundler > Loaders。esbuild 加载器 dataurlbinarybase64copyempty 尚未实现。
logLevel不适用不支持
logLimit不适用不支持
logOverride不适用不支持
mainFields不适用不支持
mangleCache不适用不支持
mangleProps不适用不支持
mangleQuoted不适用不支持
metafile不适用不支持

minify

minify

在 Bun 中,minify 可以是布尔值或对象。

await Bun.build({
  entrypoints: ['./index.tsx'],
  // enable all minification
  minify: true

  // granular options
  minify: {
    identifiers: true,
    syntax: true,
    whitespace: true
  }
})
minifyIdentifiersminify.identifiers参见 minify
minifySyntaxminify.syntax参见 minify
minifyWhitespaceminify.whitespace参见 minify
nodePaths不适用不支持
outExtension不适用不支持
outbaseroot名称不同
outdiroutdir无差异
outfileoutfile无差异
packages不适用不支持,使用 external
platformtarget支持 "bun""node""browser"(默认)。不支持 "neutral"
pluginspluginsBun 的插件 API 是 esbuild 的一个子集。一些 esbuild 插件可以开箱即用地与 Bun 一起使用。
preserveSymlinks不适用不支持
publicPathpublicPath无差异
pure不适用不支持
reserveProps不适用不支持
resolveExtensions不适用不支持
sourceRoot不适用不支持
sourcemapsourcemap支持 "inline""external""none"
sourcesContent不适用不支持
splittingsplitting无差异
stdin不适用不支持
supported不适用不支持
target不适用不支持语法降级
treeShaking不适用始终为 true
tsconfig不适用不支持
write不适用如果设置了 outdir/outfile,则设置为 true,否则为 false

插件 API

Bun 的插件 API 设计为兼容 esbuild。Bun 不支持 esbuild 的全部插件 API 范围,但核心功能已实现。许多第三方 esbuild 插件可以开箱即用地与 Bun 一起使用。

长远来看,我们的目标是实现与 esbuild API 的功能对等,因此如果有什么不起作用,请提交 issue 以帮助我们确定优先级。

Bun 和 esbuild 中的插件使用 builder 对象定义。

import type { BunPlugin } from "bun";

const myPlugin: BunPlugin = {
  name: "my-plugin",
  setup(builder) {
    // define plugin
  },
};

builder 对象提供了一些方法来钩入打包过程的各个部分。Bun 实现 onResolveonLoad;它尚未实现 esbuild 的钩子 onStartonEndonDispose,以及 resolve 工具。initialOptions 已部分实现,为只读,并且只有 esbuild 选项的子集;请改用 config(与 Bun 的 BuildConfig 格式相同,但具有 Bun 的格式)而不是。

import type { BunPlugin } from "bun";
const myPlugin: BunPlugin = {
  name: "my-plugin",
  setup(builder) {
    builder.onResolve(
      {
        /* onResolve.options */
      },
      args => {
        return {
          /* onResolve.results */
        };
      },
    );
    builder.onLoad(
      {
        /* onLoad.options */
      },
      args => {
        return {
          /* onLoad.results */
        };
      },
    );
  },
};

onResolve

options

🟢filter
🟢namespace

arguments

🟢path
🟢importer
🔴namespace
🔴resolveDir
🔴kind
🔴pluginData

results

🟢namespace
🟢path
🔴errors
🔴external
🔴pluginData
🔴pluginName
🔴sideEffects
🔴suffix
🔴warnings
🔴watchDirs
🔴watchFiles

onLoad

options

🟢filter
🟢namespace

arguments

🟢path
🔴namespace
🔴suffix
🔴pluginData

results

🟢contents
🟢loader
🔴errors
🔴pluginData
🔴pluginName
🔴resolveDir
🔴warnings
🔴watchDirs
🔴watchFiles