【Bun中文文档-Bundler】vs esbuild

277 阅读7分钟

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 在 esbuild 的three.js 基准上快 1.75 倍。

{% image src="/images/bundler-speed.png" caption="从头开始捆绑10份three.js副本,带有sourcemaps和缩小" /%}

CLI API

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

$ esbuild <入口点> --outdir=out --bundle
$ bun build <入口点> --outdir=out

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

esbuildbun build
--bundlen/aBun 始终捆绑,使用--no-bundle 来禁用此行为。
--define:K=V--define K=V语法差异小,没有冒号。
bash $ esbuild --define:foo=bar $ bun build --define foo=bar
--external:--external 语法差异小,没有冒号。
bash $ esbuild --external:react $ bun build --external react
--format--formatBun 目前仅支持"esm",但计划支持其他模块格式。esbuild 默认为"iife"。
--loader:.ext=loader--loader .ext:loaderBun 支持一组不同的内置加载器,与 esbuild 不同;有关完整参考,请参阅 Bundler > Loaders。尚未实现 esbuild 加载器 dataurl、binary、base64、copy 和 empty。 --loader 的语法略有不同。
bash $ esbuild app.ts --bundle --loader:.svg=text $ bun build app.ts --loader .svg:text
--minify--minify没有差异
--outdir--outdir没有差异
--outfile--outfile没有差异
--packagesn/a不支持
--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 一致,改名
--bannern/a不支持
--certfilen/a不适用
--charset=utf8n/a不支持
--chunk-names--chunk-naming为了与 JS API 中的 naming 一致,改名
--colorn/a始终启用
--dropn/a不支持
--entry-names--entry-naming为了与 JS API 中的 naming 一致,改名
--footern/a不支持
--global-namen/a不适用,Bun 目前不支持 iife 输出
--ignore-annotationsn/a不支持
--injectn/a不支持
--jsx--jsx-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/a假定 JSX 始终是无副作用的
--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
assetNamesnaming.asset使用与 esbuild 相同的模板语法,但必须显式包含[ext]。
bannern/a不支持
bundlen/a始终为 true。要进行捆绑之外的转译,请使用 Bun.Transpiler。
charsetn/a不支持
chunkNamesnaming.chunk使用与 esbuild 相同的模板语法,但必须显式包含[ext]。
colorn/aBun 将日志返回到构建结果的 logs 属性中。
conditionsn/a不支持。导出条件优先级由 target 确定。
definedefine
dropn/a不支持
entryNamesnaming 或 naming.entryBun 支持一个 naming 键,可以是字符串或对象。使用与 esbuild 相同的模板语法,但必须显式包含[ext]。
entryPointsentrypoints大写差异
externalexternal没有差异
footern/a不支持
formatformat目前仅支持"esm"。计划支持"cjs"和"iife"。
globalNamen/a不支持
ignoreAnnotationsn/a不支持
injectn/a不支持
jsxjsx在 JS API 中不支持,在 tsconfig.json 中配置
jsxDevjsxDev在 JS API 中不支持,在 tsconfig.json 中配置
jsxFactoryjsxFactory在 JS API 中不支持,在 tsconfig.json 中配置
jsxFragmentjsxFragment在 JS API 中不支持,在 tsconfig.json 中配置
jsxImportSourcejsxImportSource在 JS API 中不支持,在 tsconfig.json 中配置
jsxSideEffectsjsxSideEffects在 JS API 中不支持,在 tsconfig.json 中配置
keepNamesn/a不支持
legalCommentsn/a不支持
loaderloaderBun 支持一组不同于 esbuild 的内置加载器;有关完整参考,请参阅 Bundler > Loaders。尚未实现 esbuild 加载器 dataurl、binary、base64、copy 和 empty。
logLeveln/a不支持
logLimitn/a不支持
logOverriden/a不支持
mainFieldsn/a不支持
mangleCachen/a不支持
manglePropsn/a不支持
mangleQuotedn/a不支持
metafilen/a不支持
minifyminify在 Bun 中,minify 可以是布尔值或对象。
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 功能相等,因此如果某些功能无法正常工作,请提交问题以帮助我们设置优先级。

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

import type { BunPlugin } from "bun";

const myPlugin: BunPlugin = {
  name: "my-plugin",
  setup(builder) {
    // 定义插件
  },
};

builder对象提供了一些方法,用于钩入捆绑过程的各个部分。Bun 实现了onResolveonLoad;它尚未实现 esbuild 的onStartonEndonDisposeresolve钩子,以及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