Skip to content

import Build from "/snippets/cli/build.mdx";

El empaquetador nativo rápido de Bun puede usarse vía el comando CLI bun build o la API de JavaScript Bun.build().

De un Vistazo

  • API JS: await Bun.build({ entrypoints, outdir })
  • CLI: bun build <entry> --outdir ./out
  • Watch: --watch para reconstrucciones incrementales
  • Targets: --target browser|bun|node
  • Formatos: --format esm|cjs|iife (experimental para cjs/iife)

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './build',
});

CLI

bash
bun build ./index.tsx --outdir ./build

Es rápido. Los números a continuación representan el rendimiento en el benchmark three.js de esbuild.

¿Por qué empaquetar?

El empaquetador es una pieza clave de infraestructura en el ecosistema JavaScript. Como una breve visión general de por qué el empaquetado es tan importante:

  • Reducir peticiones HTTP. Un único paquete en node_modules puede consistir en cientos de archivos, y aplicaciones grandes pueden tener docenas de tales dependencias. Cargar cada uno de estos archivos con una petición HTTP separada se vuelve insostenible muy rápidamente, por lo que se usan empaquetadores para convertir nuestro código fuente de la aplicación en un número menor de "bundles" autocontenidos que pueden cargarse con una única petición.
  • Transformaciones de código. Las aplicaciones modernas comúnmente se construyen con lenguajes o herramientas como TypeScript, JSX y módulos CSS, todos los cuales deben convertirse en JavaScript y CSS planos antes de que puedan ser consumidos por un navegador. El empaquetador es el lugar natural para configurar estas transformaciones.
  • Características de frameworks. Los frameworks dependen de plugins del empaquetador y transformaciones de código para implementar patrones comunes como enrutamiento basado en sistema de archivos, co-ubicación de código cliente-servidor (piensa en getServerSideProps o loaders de Remix), y componentes de servidor.
  • Aplicaciones Full-stack. El empaquetador de Bun puede manejar tanto código de servidor como de cliente en un único comando, permitiendo construcciones de producción optimizadas y ejecutables de un solo archivo. Con imports HTML en tiempo de construcción, puedes empaquetar toda tu aplicación — assets frontend y servidor backend — en una única unidad desplegable.

Saltemos a la API del empaquetador.

NOTE

El empaquetador de Bun no está destinado a reemplazar `tsc` para verificación de tipos o generar declaraciones de tipo.

Ejemplo básico

Construyamos nuestro primer bundle. Tienes los siguientes dos archivos, que implementan una aplicación React renderizada del lado del cliente simple.

tsx
import * as ReactDOM from "react-dom/client";
import { Component } from "./Component";

const root = ReactDOM.createRoot(document.getElementById("root")!);
root.render(<Component message="Sup!" />);
tsx
export function Component(props: { message: string }) {
  return <h1>{props.message}</h1>;
}

Aquí, index.tsx es el "entrypoint" de nuestra aplicación. Comúnmente, este será un script que realiza algún efecto secundario, como iniciar un servidor o, en este caso, inicializar un root de React. Debido a que estamos usando TypeScript y JSX, necesitamos empaquetar nuestro código antes de que pueda enviarse al navegador.

Para crear nuestro bundle:

ts
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
});
bash
bun build ./index.tsx --outdir ./out

Para cada archivo especificado en entrypoints, Bun generará un nuevo bundle. Este bundle se escribirá en disco en el directorio ./out (resuelto desde el directorio de trabajo actual). Después de ejecutar la construcción, el sistema de archivos se ve así:

file system
text
.
├── index.tsx
├── Component.tsx
└── out
    └── index.js

El contenido de out/index.js se verá algo como esto:

out/index.js
js
// out/index.js
// ...
// ~20k líneas de código
// incluyendo el contenido de `react-dom/client` y todas sus dependencias
// aquí es donde se definen las funciones $jsxDEV y $createRoot

// Component.tsx
function Component(props) {
  return $jsxDEV(
    "p",
    {
      children: props.message,
    },
    undefined,
    false,
    undefined,
    this,
  );
}

// index.tsx
var rootNode = document.getElementById("root");
var root = $createRoot(rootNode);
root.render(
  $jsxDEV(
    Component,
    {
      message: "Sup!",
    },
    undefined,
    false,
    undefined,
    this,
  ),
);

Modo watch

Como el runtime y el ejecutor de tests, el empaquetador soporta modo watch nativamente.

bash
bun build ./index.tsx --outdir ./out --watch

Tipos de contenido

Como el runtime de Bun, el empaquetador soporta un array de tipos de archivos integrados. La siguiente tabla desglosa el conjunto de "loaders" estándar del empaquetador. Consulta Empaquetador > Tipos de archivos para documentación completa.

ExtensionesDetalles
.js .jsx .cjs .mjs .mts .cts .ts .tsxUsa el transpilador integrado de Bun para analizar el archivo y transpilar sintaxis TypeScript/JSX a JavaScript vanilla. El empaquetador ejecuta un conjunto de transformaciones predeterminadas incluyendo eliminación de código muerto y tree shaking. Por el momento Bun no intenta convertir sintaxis hacia abajo; si usas sintaxis ECMAScript reciente, eso se reflejará en el código empaquetado.
.jsonLos archivos JSON se analizan e incluyen en línea en el bundle como un objeto JavaScript.

js<br/>import pkg from "./package.json";<br/>pkg.name; // => "my-package"<br/>
.jsoncJSON con comentarios. Los archivos se analizan e incluyen en línea en el bundle como un objeto JavaScript.

js<br/>import config from "./config.jsonc";<br/>config.name; // => "my-config"<br/>
.tomlLos archivos TOML se analizan e incluyen en línea en el bundle como un objeto JavaScript.

js<br/>import config from "./bunfig.toml";<br/>config.logLevel; // => "debug"<br/>
.yaml .ymlLos archivos YAML se analizan e incluyen en línea en el bundle como un objeto JavaScript.

js<br/>import config from "./config.yaml";<br/>config.name; // => "my-app"<br/>
.txtEl contenido del archivo de texto se lee e incluye en línea en el bundle como una cadena.

js<br/>import contents from "./file.txt";<br/>console.log(contents); // => "Hello, world!"<br/>
.htmlLos archivos HTML se procesan y cualquier asset referenciado (scripts, hojas de estilo, imágenes) se empaqueta.
.cssLos archivos CSS se empaquetan juntos en un único archivo .css en el directorio de salida.
.node .wasmEstos archivos son compatibles con el runtime de Bun, pero durante el empaquetado se tratan como assets.

Assets

Si el empaquetador encuentra un import con una extensión no reconocida, trata el archivo importado como un archivo externo. El archivo referenciado se copia tal cual en outdir, y el import se resuelve como una ruta al archivo.

ts
// bundle entrypoint
import logo from "./logo.svg";
console.log(logo);
ts
// bundled output
var logo = "./logo-a7305bdef.svg";
console.log(logo);

El comportamiento exacto del file loader también se ve afectado por naming y publicPath.

Plugins

El comportamiento descrito en esta tabla puede anularse o extenderse con plugins. Consulta la página Empaquetador > Loaders para documentación completa.

API

entrypoints

Un array de rutas correspondientes a los entrypoints de nuestra aplicación. Se generará un bundle para cada entrypoint.

JavaScript

ts
const result = await Bun.build({
  entrypoints: ["./index.ts"]
});

CLI

bash
bun build ./index.ts

outdir

El directorio donde se escribirán los archivos de salida.

JavaScript

ts
const result = await Bun.build({
  entrypoints: ['./index.ts'],
  outdir: './out'
});
// => { success: boolean, outputs: `BuildArtifact[]`, logs: `BuildMessage[]` }

CLI

bash
bun build ./index.ts --outdir ./out

Si no se pasa outdir a la API de JavaScript, el código empaquetado no se escribirá en disco. Los archivos empaquetados se devuelven en un array de objetos BuildArtifact. Estos objetos son Blobs con propiedades adicionales; consulta Outputs para documentación completa.

ts
const result = await Bun.build({
  entrypoints: ["./index.ts"],
});

for (const res of result.outputs) {
  // Pueden consumirse como blobs
  await res.text();

  // Bun establecerá las cabeceras Content-Type y Etag
  new Response(res);

  // Pueden escribirse manualmente, pero deberías usar `outdir` en este caso.
  Bun.write(path.join("out", res.path), res);
}

Cuando outdir está establecido, la propiedad path en un BuildArtifact será la ruta absoluta a donde se escribió.

target

El entorno de ejecución previsto para el bundle.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.ts'],
  outdir: './out',
  target: 'browser', // predeterminado
})

CLI

bash
bun build ./index.ts --outdir ./out --target browser

Dependiendo del target, Bun aplicará diferentes reglas de resolución de módulos y optimizaciones.

Predeterminado. Para generar bundles destinados a ejecución por un navegador. Prioriza la condición de export "browser" al resolver imports. Importar cualquier módulo integrado, como node:events o node:path funcionará, pero llamar a algunas funciones, como fs.readFile no funcionará.

Para generar bundles destinados a ser ejecutados por el runtime de Bun. En muchos casos, no es necesario empaquetar código del lado del servidor; puedes ejecutar directamente el código fuente sin modificación. Sin embargo, empaquetar tu código de servidor puede reducir tiempos de inicio y mejorar el rendimiento de ejecución. Este es el target a usar para construir aplicaciones full-stack con imports HTML en tiempo de construcción, donde tanto el código de servidor como de cliente se empaquetan juntos.

Todos los bundles generados con target: "bun" están marcados con un pragma especial // @bun, que indica al runtime de Bun que no es necesario volver a transpilar el archivo antes de la ejecución.

Si algún entrypoint contiene un shebang de Bun (#!/usr/bin/env bun) el empaquetador usará por defecto target: "bun" en lugar de "browser".

Al usar target: "bun" y format: "cjs" juntos, se agrega el pragma // @bun @bun-cjs y la función wrapper CommonJS no es compatible con Node.js.

Para generar bundles destinados a ser ejecutados por Node.js. Prioriza la condición de export "node" al resolver imports, y genera .mjs. En el futuro, esto rellenará automáticamente el global Bun y otros módulos integrados bun:*, aunque esto aún no está implementado.

format

Especifica el formato de módulo a usar en los bundles generados.

Bun usa por defecto "esm", y proporciona soporte experimental para "cjs" e "iife".

format: "esm" - ES Module

Este es el formato predeterminado, que soporta sintaxis de ES Module incluyendo await de nivel superior, import.meta, y más.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  format: "esm",
})

CLI

bash
bun build ./index.tsx --outdir ./out --format esm

Para usar sintaxis de ES Module en navegadores, establece format en "esm" y asegúrate de que tu etiqueta <script type="module"> tenga type="module" establecido.

format: "cjs" - CommonJS

Para construir un módulo CommonJS, establece format en "cjs". Al elegir "cjs", el target predeterminado cambia de "browser" (esm) a "node" (cjs). Los módulos CommonJS transpilados con format: "cjs", target: "node" pueden ejecutarse tanto en Bun como en Node.js (asumiendo que las APIs en uso son compatibles con ambos).

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  format: "cjs",
})

CLI

bash
bun build ./index.tsx --outdir ./out --format cjs

format: "iife" - IIFE

TODO: documentar IIFE una vez que soportemos globalNames.

jsx

Configura el comportamiento de la transformación JSX. Permite control fino sobre cómo se compila JSX.

Ejemplo de runtime clásico (usa factory y fragment):

ts
await Bun.build({
  entrypoints: ["./app.tsx"],
  outdir: "./out",
  jsx: {
    factory: "h",
    fragment: "Fragment",
    runtime: "classic",
  },
});
bash
# La configuración JSX se maneja vía bunfig.toml o tsconfig.json
bun build ./app.tsx --outdir ./out

Ejemplo de runtime automático (usa importSource):

ts
await Bun.build({
  entrypoints: ["./app.tsx"],
  outdir: "./out",
  jsx: {
    importSource: "preact",
    runtime: "automatic",
  },
});
bash
# La configuración JSX se maneja vía bunfig.toml o tsconfig.json
bun build ./app.tsx --outdir ./out

splitting

Si habilitar o no code splitting.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  splitting: false, // predeterminado
})

CLI

bash
bun build ./index.tsx --outdir ./out --splitting

Cuando es true, el empaquetador habilitará code splitting. Cuando múltiples entrypoints importan el mismo archivo, módulo, o conjunto de archivos/módulos, a menudo es útil dividir el código compartido en un bundle separado. Este bundle compartido se conoce como un chunk. Considera los siguientes archivos:

ts
import { shared } from "./shared.ts";
ts
import { shared } from "./shared.ts";
ts
export const shared = "shared";

Para empaquetar entry-a.ts y entry-b.ts con code-splitting habilitado:

JavaScript

ts
await Bun.build({
  entrypoints: ['./entry-a.ts', './entry-b.ts'],
  outdir: './out',
  splitting: true,
})

CLI

bash
bun build ./entry-a.ts ./entry-b.ts --outdir ./out --splitting

Ejecutar esta construcción resultará en los siguientes archivos:

file system
text
.
├── entry-a.tsx
├── entry-b.tsx
├── shared.tsx
└── out
    ├── entry-a.js
    ├── entry-b.js
    └── chunk-2fce6291bf86559d.js

El archivo generado chunk-2fce6291bf86559d.js contiene el código compartido. Para evitar colisiones, el nombre del archivo incluye automáticamente un hash de contenido por defecto. Esto puede personalizarse con naming.

plugins

Una lista de plugins a usar durante el empaquetado.

ts
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
  plugins: [
    /* ... */
  ],
});

Bun implementa un sistema de plugins universal tanto para el runtime como para el empaquetador de Bun. Consulta la documentación de plugins para documentación completa.

env

Controla cómo se manejan las variables de entorno durante el empaquetado. Internamente, esto usa define para inyectar variables de entorno en el bundle, pero hace más fácil especificar las variables de entorno a inyectar.

env: "inline"

Inyecta variables de entorno en la salida empaquetada convirtiendo referencias process.env.FOO a literales de cadena que contienen los valores reales de las variables de entorno.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  env: "inline",
})

CLI

bash
bun build ./index.tsx --outdir ./out --env inline

Para la entrada a continuación:

input.js
js
// input.js
console.log(process.env.FOO);
console.log(process.env.BAZ);

El bundle generado contendrá el siguiente código:

output.js
js
// output.js
console.log("bar");
console.log("123");

env: "PUBLIC_*" (prefijo)

Incluye en línea variables de entorno que coincidan con el prefijo dado (la parte antes del carácter *), reemplazando process.env.FOO con el valor real de la variable de entorno. Esto es útil para incluir selectivamente variables de entorno para cosas como URLs públicas o tokens del lado del cliente, sin preocuparse por inyectar credenciales privadas en bundles de salida.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  
  // Incluir en línea todas las variables de entorno que comienzan con "ACME_PUBLIC_"
  env: "ACME_PUBLIC_*",
})

CLI

bash
bun build ./index.tsx --outdir ./out --env ACME_PUBLIC_*

Por ejemplo, dadas las siguientes variables de entorno:

bash
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.com

Y código fuente:

tsx
console.log(process.env.FOO);
console.log(process.env.ACME_PUBLIC_URL);
console.log(process.env.BAZ);

El bundle generado contendrá el siguiente código:

output.js
js
console.log(process.env.FOO);
console.log("https://acme.com");
console.log(process.env.BAZ);

env: "disable"

Deshabilita la inyección de variables de entorno por completo.

sourcemap

Especifica el tipo de sourcemap a generar.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  sourcemap: 'linked', // predeterminado 'none'
})

CLI

bash
bun build ./index.tsx --outdir ./out --sourcemap linked
ValorDescripción
"none"Predeterminado. No se genera sourcemap.
"linked"Se crea un archivo *.js.map separado junto a cada bundle *.js usando un comentario //# sourceMappingURL para vincular los dos. Requiere que --outdir esté establecido. La URL base de esto puede personalizarse con --public-path.

js<br/>// <código empaquetado aquí><br/><br/>//# sourceMappingURL=bundle.js.map<br/>
"external"Se crea un archivo *.js.map separado junto a cada bundle *.js sin insertar un comentario //# sourceMappingURL.

Los bundles generados contienen un debug id que puede usarse para asociar un bundle con su sourcemap correspondiente. Este debugId se agrega como un comentario en la parte inferior del archivo.

js<br/>// <código de bundle generado><br/><br/>//# debugId=<DEBUG ID><br/>
"inline"Se genera un sourcemap y se anexa al final del bundle generado como una carga útil base64.

js<br/>// <código empaquetado aquí><br/><br/>//# sourceMappingURL=data:application/json;base64,<sourcemap codificado aquí><br/>

El sourcemap *.js.map asociado será un archivo JSON que contiene una propiedad debugId equivalente.

minify

Si habilitar o no la minificación. Predeterminado false.

NOTE

Cuando el target es `bun`, los identificadores se minificarán por defecto.

Para habilitar todas las opciones de minificación:

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  minify: true, // predeterminado false
})

CLI

bash
bun build ./index.tsx --outdir ./out --minify

Para habilitar granularmente ciertas minificaciones:

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  minify: {
    whitespace: true,
    identifiers: true,
    syntax: true,
  },
})

CLI

bash
bun build ./index.tsx --outdir ./out --minify-whitespace --minify-identifiers --minify-syntax

external

Una lista de rutas de import a considerar externas. Predeterminado [].

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ["lodash", "react"], // predeterminado: []
})

CLI

bash
bun build ./index.tsx --outdir ./out --external lodash --external react

Un import externo es uno que no se incluirá en el bundle final. En su lugar, la declaración de import se dejará tal cual, para resolverse en runtime.

Por ejemplo, considera el siguiente archivo entrypoint:

tsx
import _ from "lodash";
import { z } from "zod";

const value = z.string().parse("Hello world!");
console.log(_.upperCase(value));

Normalmente, empaquetar index.tsx generaría un bundle que contiene todo el código fuente del paquete "zod". Si en cambio, queremos dejar la declaración de import tal cual, podemos marcarla como externa:

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ['zod'],
})

CLI

bash
bun build ./index.tsx --outdir ./out --external zod

El bundle generado se verá algo como esto:

out/index.js
js
import { z } from "zod";

// ...
// el contenido del paquete "lodash"
// incluyendo la función `_.upperCase`

var value = z.string().parse("Hello world!");
console.log(_.upperCase(value));

Para marcar todos los imports como externos, usa el comodín *:

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ['*'],
})

CLI

bash
bun build ./index.tsx --outdir ./out --external '*'

packages

Controla si las dependencias de paquetes se incluyen en el bundle o no. Valores posibles: bundle (predeterminado), external. Bun trata cualquier import cuya ruta no comience con ., .. o / como paquete.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.ts'],
  packages: 'external',
})

CLI

bash
bun build ./index.ts --packages external

naming

Personaliza los nombres de archivos generados. Predeterminado ./[dir]/[name].[ext].

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: "[dir]/[name].[ext]", // predeterminado
})

CLI

bash
bun build ./index.tsx --outdir ./out --entry-naming "[dir]/[name].[ext]"

Por defecto, los nombres de los bundles generados se basan en el nombre del entrypoint asociado.

file system
text
.
├── index.tsx
└── out
    └── index.js

Con múltiples entrypoints, la jerarquía de archivos generados reflejará la estructura de directorios de los entrypoints.

file system
text
.
├── index.tsx
└── nested
    └── index.tsx
└── out
    ├── index.js
    └── nested
        └── index.js

Los nombres y ubicaciones de los archivos generados pueden personalizarse con el campo naming. Este campo acepta una cadena de plantilla que se usa para generar los nombres de archivo para todos los bundles correspondientes a entrypoints. donde los siguientes tokens se reemplazan con sus valores correspondientes:

  • [name] - El nombre del archivo entrypoint, sin la extensión.
  • [ext] - La extensión del bundle generado.
  • [hash] - Un hash del contenido del bundle.
  • [dir] - La ruta relativa desde la raíz del proyecto al directorio padre del archivo fuente.

Por ejemplo:

Token[name][ext][hash][dir]
./index.tsxindexjsa1b2c3d4"" (cadena vacía)
./nested/entry.tsentryjsc3d4e5f6"nested"

Podemos combinar estos tokens para crear una cadena de plantilla. Por ejemplo, para incluir el hash en los nombres de bundle generados:

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: 'files/[dir]/[name]-[hash].[ext]',
})

CLI

bash
bun build ./index.tsx --outdir ./out --entry-naming 'files/[dir]/[name]-[hash].[ext]'

Esta construcción resultaría en la siguiente estructura de archivos:

file system
text
.
├── index.tsx
└── out
    └── files
        └── index-a1b2c3d4.js

Cuando se proporciona una cadena para el campo naming, se usa solo para bundles que corresponden a entrypoints. Los nombres de chunks y assets copiados no se ven afectados. Usando la API de JavaScript, pueden especificarse cadenas de plantilla separadas para cada tipo de archivo generado.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: {
    // valores predeterminados
    entry: '[dir]/[name].[ext]',
    chunk: '[name]-[hash].[ext]',
    asset: '[name]-[hash].[ext]',
  },
})

CLI

bash
bun build ./index.tsx --outdir ./out \
  --entry-naming '[dir]/[name].[ext]' \
  --chunk-naming '[name]-[hash].[ext]' \
  --asset-naming '[name]-[hash].[ext]'

root

El directorio raíz del proyecto.

JavaScript

ts
await Bun.build({
  entrypoints: ['./pages/a.tsx', './pages/b.tsx'],
  outdir: './out',
  root: '.',
})

CLI

bash
bun build ./pages/a.tsx ./pages/b.tsx --outdir ./out --root .

Si no se especifica, se calcula como el primer ancestro común de todos los archivos entrypoint. Considera la siguiente estructura de archivos:

file system
text
.
└── pages
  └── index.tsx
  └── settings.tsx

Podemos construir ambos entrypoints en el directorio pages:

JavaScript

js
await Bun.build({
  entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
  outdir: './out',
})

CLI

bash
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out

Esto resultaría en una estructura de archivos como esta:

file system
text
.
└── pages
  └── index.tsx
  └── settings.tsx
└── out
  └── index.js
  └── settings.js

Dado que el directorio pages es el primer ancestro común de los archivos entrypoint, se considera la raíz del proyecto. Esto significa que los bundles generados viven en el nivel superior del directorio out; no hay un directorio out/pages.

Este comportamiento puede anularse especificando la opción root:

JavaScript

js
await Bun.build({
  entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
  outdir: './out',
  root: '.',
})

CLI

bash
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out --root .

Al especificar . como root, la estructura de archivos generada se verá así:

.
└── pages
  └── index.tsx
  └── settings.tsx
└── out
  └── pages
    └── index.js
    └── settings.js

publicPath

Un prefijo a agregar a cualquier ruta de import en el código empaquetado.

En muchos casos, los bundles generados no contendrán declaraciones de import. Después de todo, el objetivo del empaquetado es combinar todo el código en un único archivo. Sin embargo, hay varios casos en los que los bundles generados contendrán declaraciones de import.

  • Imports de assets — Al importar un tipo de archivo no reconocido como *.svg, el empaquetador delega al file loader, que copia el archivo en outdir tal cual. El import se convierte en una variable
  • Módulos externos — Los archivos y módulos pueden marcarse como externos, en cuyo caso no se incluirán en el bundle. En su lugar, la declaración de import se dejará en el bundle final.
  • Chunking. Cuando splitting está habilitado, el empaquetador puede generar archivos "chunk" separados que representan código compartido entre múltiples entrypoints.

En cualquiera de estos casos, los bundles finales pueden contener rutas a otros archivos. Por defecto estos imports son relativos. Aquí hay un ejemplo de un import de asset simple:

ts
import logo from "./logo.svg";
console.log(logo);
ts
var logo = "./logo-a7305bdef.svg";
console.log(logo);

Establecer publicPath prefijará todas las rutas de archivo con el valor especificado.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  publicPath: 'https://cdn.example.com/', // predeterminado es undefined
})

CLI

bash
bun build ./index.tsx --outdir ./out --public-path 'https://cdn.example.com/'

El archivo de salida ahora se vería algo como esto.

out/index.js
js
var logo = "https://cdn.example.com/logo-a7305bdef.svg";

define

Un mapa de identificadores globales a reemplazar en tiempo de construcción. Las claves de este objeto son nombres de identificadores, y los valores son cadenas JSON que se incluirán en línea.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  define: {
    STRING: JSON.stringify("value"),
    "nested.boolean": "true",
  },
})

CLI

bash
bun build ./index.tsx --outdir ./out --define STRING='"value"' --define nested.boolean=true

loader

Un mapa de extensiones de archivo a nombres de loader integrados. Esto puede usarse para personalizar rápidamente cómo se cargan ciertos archivos.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  loader: {
    ".png": "dataurl",
    ".txt": "file",
  },
})

CLI

bash
bun build ./index.tsx --outdir ./out --loader .png:dataurl --loader .txt:file

Un banner a agregar al bundle final, esto puede ser una directiva como use client para react o un bloque de comentarios como una licencia para el código.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  banner: 'use client;'
})

CLI

bash
bun build ./index.tsx --outdir ./out --banner 'use client";'

Un footer a agregar al bundle final, esto puede ser algo como un bloque de comentarios para una licencia o solo un huevo de pascua divertido.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  footer: '// built with love in SF'
})

CLI

bash
bun build ./index.tsx --outdir ./out --footer '// built with love in SF'

drop

Eliminar llamadas a funciones de un bundle. Por ejemplo, --drop=console eliminará todas las llamadas a console.log. Los argumentos a las llamadas también se eliminarán, independientemente de si esos argumentos pueden tener efectos secundarios. Eliminar debugger eliminará todas las declaraciones debugger.

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  drop: ["console", "debugger", "anyIdentifier.or.propertyAccess"],
})

CLI

bash
bun build ./index.tsx --outdir ./out --drop console --drop debugger

Outputs

La función Bun.build devuelve una Promise<BuildOutput>, definida como:

ts
interface BuildOutput {
  outputs: BuildArtifact[];
  success: boolean;
  logs: Array<object>; // consulta docs para detalles
}

interface BuildArtifact extends Blob {
  kind: "entry-point" | "chunk" | "asset" | "sourcemap";
  path: string;
  loader: Loader;
  hash: string | null;
  sourcemap: BuildArtifact | null;
}

El array outputs contiene todos los archivos que fueron generados por la construcción. Cada artifact implementa la interfaz Blob.

ts
const build = await Bun.build({
  /* */
});

for (const output of build.outputs) {
  await output.arrayBuffer(); // => ArrayBuffer
  await output.bytes(); // => Uint8Array
  await output.text(); // string
}

Cada artifact también contiene las siguientes propiedades:

PropiedadDescripción
kindQué tipo de salida de construcción es este archivo. Una construcción genera entrypoints empaquetados, "chunks" de code-split, sourcemaps, bytecode y assets copiados (como imágenes).
pathRuta absoluta al archivo en disco
loaderEl loader usado para interpretar el archivo. Consulta Empaquetador > Loaders para ver cómo Bun mapea extensiones de archivo al loader integrado apropiado.
hashEl hash del contenido del archivo. Siempre definido para assets.
sourcemapEl archivo sourcemap correspondiente a este archivo, si se genera. Solo definido para entrypoints y chunks.

Similar a BunFile, los objetos BuildArtifact pueden pasarse directamente a new Response().

ts
const build = await Bun.build({
  /* */
});

const artifact = build.outputs[0];

// La cabecera Content-Type se establece automáticamente
return new Response(artifact);

El runtime de Bun implementa impresión especial de objetos BuildArtifact para facilitar la depuración.

ts
// build.ts
const build = await Bun.build({
  /* */
});

const artifact = build.outputs[0];
console.log(artifact);
bash
bun run build.ts

BuildArtifact (entry-point) {
  path: "./index.js",
  loader: "tsx",
  kind: "entry-point",
  hash: "824a039620219640",
  Blob (74756 bytes) {
    type: "text/javascript;charset=utf-8"
  },
  sourcemap: BuildArtifact (sourcemap) {
    path: "./index.js.map",
    loader: "file",
    kind: "sourcemap",
    hash: "e7178cda3e72e301",
    Blob (24765 bytes) {
      type: "application/json;charset=utf-8"
    },
    sourcemap: null
  }
}

Bytecode

La opción bytecode: boolean puede usarse para generar bytecode para cualquier entrypoint JavaScript/TypeScript. Esto puede mejorar enormemente los tiempos de inicio para aplicaciones grandes. Solo compatible con formato "cjs", solo soporta "target": "bun" y depende de una versión coincidente de Bun. Esto agrega un archivo .jsc correspondiente para cada entrypoint.

JavaScript

ts
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
  bytecode: true,
})

CLI

bash
bun build ./index.tsx --outdir ./out --bytecode

Ejecutables

Bun soporta "compilar" un entrypoint JavaScript/TypeScript en un ejecutable independiente. Este ejecutable contiene una copia del binario de Bun.

bash
bun build ./cli.tsx --outfile mycli --compile
./mycli

Consulta Empaquetador > Ejecutables para documentación completa.

Logs y errores

En fallo, Bun.build devuelve una promesa rechazada con un AggregateError. Esto puede registrarse en la consola para impresión bonita de la lista de errores, o leerse programáticamente con un bloque try/catch.

ts
try {
  const result = await Bun.build({
    entrypoints: ["./index.tsx"],
    outdir: "./out",
  });
} catch (e) {
  // TypeScript no permite anotaciones en la cláusula catch
  const error = e as AggregateError;
  console.error("Build Failed");

  // Ejemplo: Usando el formateador integrado
  console.error(error);

  // Ejemplo: Serializando el fallo como una cadena JSON.
  console.error(JSON.stringify(error, null, 2));
}

La mayoría de las veces, un try/catch explícito no es necesario, ya que Bun imprimirá ordenadamente las excepciones no capturadas. Es suficiente con solo usar un await de nivel superior en la llamada Bun.build.

Cada elemento en error.errors es una instancia de BuildMessage o ResolveMessage (subclases de Error), que contiene información detallada para cada error.

ts
class BuildMessage {
  name: string;
  position?: Position;
  message: string;
  level: "error" | "warning" | "info" | "debug" | "verbose";
}

class ResolveMessage extends BuildMessage {
  code: string;
  referrer: string;
  specifier: string;
  importKind: ImportKind;
}

En éxito de construcción, el objeto devuelto contiene una propiedad logs, que contiene advertencias y mensajes de información del empaquetador.

ts
const result = await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
});

if (result.logs.length > 0) {
  console.warn("Build succeeded with warnings:");
  for (const message of result.logs) {
    // Bun imprimirá bonito el objeto message
    console.warn(message);
  }
}

Referencia

ts
interface Bun {
  build(options: BuildOptions): Promise<BuildOutput>;
}

interface BuildConfig {
  entrypoints: string[]; // lista de rutas de archivo
  outdir?: string; // directorio de salida
  target?: Target; // predeterminado: "browser"
  /**
   * Formato de módulo de salida. Await de nivel superior solo se soporta para `"esm"`.
   *
   * Puede ser:
   * - `"esm"`
   * - `"cjs"` (**experimental**)
   * - `"iife"` (**experimental**)
   *
   * @default "esm"
   */
  format?: "esm" | "cjs" | "iife";
  /**
   * Objeto de configuración JSX para controlar el comportamiento de la transformación JSX
   */
  jsx?: {
    runtime?: "automatic" | "classic";
    importSource?: string;
    factory?: string;
    fragment?: string;
    sideEffects?: boolean;
    development?: boolean;
  };
  naming?:
    | string
    | {
        chunk?: string;
        entry?: string;
        asset?: string;
      };
  root?: string; // raíz del proyecto
  splitting?: boolean; // predeterminado true, habilitar code splitting
  plugins?: BunPlugin[];
  external?: string[];
  packages?: "bundle" | "external";
  publicPath?: string;
  define?: Record<string, string>;
  loader?: { [k in string]: Loader };
  sourcemap?: "none" | "linked" | "inline" | "external" | boolean; // predeterminado: "none", true -> "inline"
  /**
   * Condiciones `exports` de package.json usadas al resolver imports
   *
   * Equivalente a `--conditions` en `bun build` o `bun run`.
   *
   * https://nodejs.org/api/packages.html#exports
   */
  conditions?: Array<string> | string;

  /**
   * Controla cómo se manejan las variables de entorno durante el empaquetado.
   *
   * Puede ser uno de:
   * - `"inline"`: Inyecta variables de entorno en la salida empaquetada convirtiendo `process.env.FOO`
   *   referencias a literales de cadena que contienen los valores reales de las variables de entorno
   * - `"disable"`: Deshabilita la inyección de variables de entorno por completo
   * - Una cadena que termina en `*`: Incluye en línea variables de entorno que coinciden con el prefijo dado.
   *   Por ejemplo, `"MY_PUBLIC_*"` solo incluirá variables de entorno que comiencen con "MY_PUBLIC_"
   */
  env?: "inline" | "disable" | `${string}*`;
  minify?:
    | boolean
    | {
        whitespace?: boolean;
        syntax?: boolean;
        identifiers?: boolean;
      };
  /**
   * Ignorar anotaciones de eliminación de código muerto/tree-shaking como @__PURE__ y campos
   * "sideEffects" de package.json. Esto solo debe usarse como una solución temporal para
   * anotaciones incorrectas en librerías.
   */
  ignoreDCEAnnotations?: boolean;
  /**
   * Forzar emisión de anotaciones @__PURE__ incluso si minify.whitespace es true.
   */
  emitDCEAnnotations?: boolean;

  /**
   * Generar bytecode para la salida. Esto puede mejorar dramáticamente los tiempos de inicio
   * en frío, pero hará que la salida final sea más grande y aumente ligeramente
   * el uso de memoria.
   *
   * Bytecode actualmente solo se soporta para CommonJS (`format: "cjs"`).
   *
   * Debe ser `target: "bun"`
   * @default false
   */
  bytecode?: boolean;
  /**
   * Agregar un banner al código empaquetado como "use client";
   */
  banner?: string;
  /**
   * Agregar un footer al código empaquetado como un bloque de comentarios como
   *
   * `// made with bun!`
   */
  footer?: string;

  /**
   * Eliminar llamadas a funciones a accesos de propiedad coincidentes.
   */
  drop?: string[];

  /**
   * - Cuando se establece en `true`, la promesa devuelta rechaza con un AggregateError cuando ocurre un fallo de construcción.
   * - Cuando se establece en `false`, devuelve un {@link BuildOutput} con `{success: false}`
   *
   * @default true
   */
  throw?: boolean;

  /**
   * Ruta de archivo tsconfig.json personalizada a usar para resolución de rutas.
   * Equivalente a `--tsconfig-override` en el CLI.
   */
  tsconfig?: string;

  outdir?: string;
}

interface BuildOutput {
  outputs: BuildArtifact[];
  success: boolean;
  logs: Array<BuildMessage | ResolveMessage>;
}

interface BuildArtifact extends Blob {
  path: string;
  loader: Loader;
  hash: string | null;
  kind: "entry-point" | "chunk" | "asset" | "sourcemap" | "bytecode";
  sourcemap: BuildArtifact | null;
}

type Loader =
  | "js"
  | "jsx"
  | "ts"
  | "tsx"
  | "css"
  | "json"
  | "jsonc"
  | "toml"
  | "yaml"
  | "text"
  | "file"
  | "napi"
  | "wasm"
  | "html";

interface BuildOutput {
  outputs: BuildArtifact[];
  success: boolean;
  logs: Array<BuildMessage | ResolveMessage>;
}

declare class ResolveMessage {
  readonly name: "ResolveMessage";
  readonly position: Position | null;
  readonly code: string;
  readonly message: string;
  readonly referrer: string;
  readonly specifier: string;
  readonly importKind:
    | "entry_point"
    | "stmt"
    | "require"
    | "import"
    | "dynamic"
    | "require_resolve"
    | "at"
    | "at_conditional"
    | "url"
    | "internal";
  readonly level: "error" | "warning" | "info" | "debug" | "verbose";

  toString(): string;
}

Bun por www.bunjs.com.cn editar