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 解析器,在 esbuild 的 three.js 基准测试中,Bun 的打包器比 esbuild 快 1.75 倍。

从头开始打包 10 份 three.js,带有 sourcemap 和压缩

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
--bundlen/aBun 始终打包,使用 --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
--serven/a不适用
--sourcemap--sourcemap无差异
--splitting--splitting无差异
--targetn/a不支持。Bun 的打包器目前不执行任何语法降级。
--watch--watch无差异
--allow-overwriten/a永远不允许覆盖
--analyzen/a不支持
--asset-names--asset-naming为了与 JS API 中的 naming 保持一致而重命名
--banner--banner仅适用于 js 包
--footer--footer仅适用于 js 包
--certfilen/a不适用
--charset=utf8n/a不支持
--chunk-names--chunk-naming为了与 JS API 中的 naming 保持一致而重命名
--colorn/a始终启用
--drop--drop
--entry-names--entry-naming为了与 JS API 中的 naming 保持一致而重命名
--global-namen/a不适用,Bun 目前不支持 iife 输出
--ignore-annotations--ignore-dce-annotations
--injectn/a不支持
--jsx--jsx-runtime <runtime>支持 "automatic"(使用 jsx 转换)和 "classic"(使用 React.createElement
--jsx-devn/aBun 从 tsconfig.json 读取 compilerOptions.jsx 以确定默认值。如果 compilerOptions.jsx"react-jsx",或者如果 NODE_ENV=production,Bun 将使用 jsx 转换。否则,它使用 jsxDEV。对于任何 Bun 都使用 jsxDEV。打包器不支持 preserve
--jsx-factory--jsx-factory
--jsx-fragment--jsx-fragment
--jsx-import-source--jsx-import-source
--jsx-side-effectsn/aJSX 始终被假定为无副作用
--keep-namesn/a不支持
--keyfilen/a不适用
--legal-commentsn/a不支持
--log-leveln/a不支持。这可以在 bunfig.toml 中设置为 logLevel
--log-limitn/a不支持
--log-override:X=Yn/a不支持
--main-fieldsn/a不支持
--mangle-cachen/a不支持
--mangle-propsn/a不支持
--mangle-quotedn/a不支持
--metafilen/a不支持
--minify-whitespace--minify-whitespace
--minify-identifiers--minify-identifiers
--minify-syntax--minify-syntax
--out-extensionn/a不支持
--outbase--root
--preserve-symlinksn/a不支持
--public-path--public-path
--puren/a不支持
--reserve-propsn/a不支持
--resolve-extensionsn/a不支持
--servedirn/a不适用
--source-rootn/a不支持
--sourcefilen/a不支持。Bun 尚不支持 stdin 输入。
--sourcemap--sourcemap无差异
--sources-contentn/a不支持
--supportedn/a不支持
--tree-shakingn/a始终为 true
--tsconfig--tsconfig-override
--versionn/a运行 bun --version 查看 Bun 的版本。

JavaScript API

esbuild.build()Bun.build()
absWorkingDirn/a始终设置为 process.cwd()
aliasn/a不支持
allowOverwriten/a始终为 false

assetNames

naming.asset

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

Bun.build({
  entrypoints: ["./index.tsx"],
  naming: {
    asset: "[name].[ext]",
  },
});
bannern/a不支持
bundlen/a始终为 true。使用 Bun.Transpiler 进行转译而不打包。
charsetn/a不支持

chunkNames

naming.chunk

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

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

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无差异
footern/a不支持
formatformat目前仅支持 "esm"。计划支持 "cjs""iife"
globalNamen/a不支持
ignoreAnnotationsn/a不支持
injectn/a不支持
jsxjsxJS API 中不支持,在 tsconfig.json 中配置
jsxDevjsxDevJS API 中不支持,在 tsconfig.json 中配置
jsxFactoryjsxFactoryJS API 中不支持,在 tsconfig.json 中配置
jsxFragmentjsxFragmentJS API 中不支持,在 tsconfig.json 中配置
jsxImportSourcejsxImportSourceJS API 中不支持,在 tsconfig.json 中配置
jsxSideEffectsjsxSideEffectsJS API 中不支持,在 tsconfig.json 中配置
keepNamesn/a不支持
legalCommentsn/a不支持
loaderloaderBun 支持的内置加载器集与 esbuild 不同;有关完整参考,请参阅 Bundler > Loaders。esbuild 加载器 dataurlbinarybase64copyempty 尚未实现。
logLeveln/a不支持
logLimitn/a不支持
logOverriden/a不支持
mainFieldsn/a不支持
mangleCachen/a不支持
manglePropsn/a不支持
mangleQuotedn/a不支持
metafilen/a不支持

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
nodePathsn/a不支持
outExtensionn/a不支持
outbaseroot不同的名称
outdiroutdir无差异
outfileoutfile无差异
packagesn/a不支持,请使用 external
platformtarget支持 "bun""node""browser"(默认值)。不支持 "neutral"
pluginspluginsBun 的插件 API 是 esbuild 的子集。一些 esbuild 插件可以直接与 Bun 一起使用。
preserveSymlinksn/a不支持
publicPathpublicPath无差异
puren/a不支持
reservePropsn/a不支持
resolveExtensionsn/a不支持
sourceRootn/a不支持
sourcemapsourcemap支持 "inline""external""none"
sourcesContentn/a不支持
splittingsplitting无差异
stdinn/a不支持
supportedn/a不支持
targetn/a不支持语法降级
treeShakingn/a始终为 true
tsconfign/a不支持
writen/a如果设置了 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 格式)。

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