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:
--watchpara reconstrucciones incrementales - Targets:
--target browser|bun|node - Formatos:
--format esm|cjs|iife(experimental para cjs/iife)
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './build',
});CLI
bun build ./index.tsx --outdir ./buildEs 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_modulespuede 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
getServerSidePropso 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.
import * as ReactDOM from "react-dom/client";
import { Component } from "./Component";
const root = ReactDOM.createRoot(document.getElementById("root")!);
root.render(<Component message="Sup!" />);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:
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
});bun build ./index.tsx --outdir ./outPara 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í:
.
├── index.tsx
├── Component.tsx
└── out
└── index.jsEl contenido de out/index.js se verá algo como esto:
// 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.
bun build ./index.tsx --outdir ./out --watchTipos 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.
| Extensiones | Detalles |
|---|---|
.js .jsx .cjs .mjs .mts .cts .ts .tsx | Usa 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. |
.json | Los 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/> |
.jsonc | JSON 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/> |
.toml | Los 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 .yml | Los 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/> |
.txt | El 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/> |
.html | Los archivos HTML se procesan y cualquier asset referenciado (scripts, hojas de estilo, imágenes) se empaqueta. |
.css | Los archivos CSS se empaquetan juntos en un único archivo .css en el directorio de salida. |
.node .wasm | Estos 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.
// bundle entrypoint
import logo from "./logo.svg";
console.log(logo);// 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
const result = await Bun.build({
entrypoints: ["./index.ts"]
});CLI
bun build ./index.tsoutdir
El directorio donde se escribirán los archivos de salida.
JavaScript
const result = await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out'
});
// => { success: boolean, outputs: `BuildArtifact[]`, logs: `BuildMessage[]` }CLI
bun build ./index.ts --outdir ./outSi 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.
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
await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out',
target: 'browser', // predeterminado
})CLI
bun build ./index.ts --outdir ./out --target browserDependiendo 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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
format: "esm",
})CLI
bun build ./index.tsx --outdir ./out --format esmPara 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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
format: "cjs",
})CLI
bun build ./index.tsx --outdir ./out --format cjsformat: "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):
await Bun.build({
entrypoints: ["./app.tsx"],
outdir: "./out",
jsx: {
factory: "h",
fragment: "Fragment",
runtime: "classic",
},
});# La configuración JSX se maneja vía bunfig.toml o tsconfig.json
bun build ./app.tsx --outdir ./outEjemplo de runtime automático (usa importSource):
await Bun.build({
entrypoints: ["./app.tsx"],
outdir: "./out",
jsx: {
importSource: "preact",
runtime: "automatic",
},
});# La configuración JSX se maneja vía bunfig.toml o tsconfig.json
bun build ./app.tsx --outdir ./outsplitting
Si habilitar o no code splitting.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
splitting: false, // predeterminado
})CLI
bun build ./index.tsx --outdir ./out --splittingCuando 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:
import { shared } from "./shared.ts";import { shared } from "./shared.ts";export const shared = "shared";Para empaquetar entry-a.ts y entry-b.ts con code-splitting habilitado:
JavaScript
await Bun.build({
entrypoints: ['./entry-a.ts', './entry-b.ts'],
outdir: './out',
splitting: true,
})CLI
bun build ./entry-a.ts ./entry-b.ts --outdir ./out --splittingEjecutar esta construcción resultará en los siguientes archivos:
.
├── entry-a.tsx
├── entry-b.tsx
├── shared.tsx
└── out
├── entry-a.js
├── entry-b.js
└── chunk-2fce6291bf86559d.jsEl 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.
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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
env: "inline",
})CLI
bun build ./index.tsx --outdir ./out --env inlinePara la entrada a continuación:
// input.js
console.log(process.env.FOO);
console.log(process.env.BAZ);El bundle generado contendrá el siguiente código:
// 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
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
bun build ./index.tsx --outdir ./out --env ACME_PUBLIC_*Por ejemplo, dadas las siguientes variables de entorno:
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.comY código fuente:
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:
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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
sourcemap: 'linked', // predeterminado 'none'
})CLI
bun build ./index.tsx --outdir ./out --sourcemap linked| Valor | Descripció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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: true, // predeterminado false
})CLI
bun build ./index.tsx --outdir ./out --minifyPara habilitar granularmente ciertas minificaciones:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: {
whitespace: true,
identifiers: true,
syntax: true,
},
})CLI
bun build ./index.tsx --outdir ./out --minify-whitespace --minify-identifiers --minify-syntaxexternal
Una lista de rutas de import a considerar externas. Predeterminado [].
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ["lodash", "react"], // predeterminado: []
})CLI
bun build ./index.tsx --outdir ./out --external lodash --external reactUn 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:
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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['zod'],
})CLI
bun build ./index.tsx --outdir ./out --external zodEl bundle generado se verá algo como esto:
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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['*'],
})CLI
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
await Bun.build({
entrypoints: ['./index.ts'],
packages: 'external',
})CLI
bun build ./index.ts --packages externalnaming
Personaliza los nombres de archivos generados. Predeterminado ./[dir]/[name].[ext].
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: "[dir]/[name].[ext]", // predeterminado
})CLI
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.
.
├── index.tsx
└── out
└── index.jsCon múltiples entrypoints, la jerarquía de archivos generados reflejará la estructura de directorios de los entrypoints.
.
├── index.tsx
└── nested
└── index.tsx
└── out
├── index.js
└── nested
└── index.jsLos 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.tsx | index | js | a1b2c3d4 | "" (cadena vacía) |
./nested/entry.ts | entry | js | c3d4e5f6 | "nested" |
Podemos combinar estos tokens para crear una cadena de plantilla. Por ejemplo, para incluir el hash en los nombres de bundle generados:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: 'files/[dir]/[name]-[hash].[ext]',
})CLI
bun build ./index.tsx --outdir ./out --entry-naming 'files/[dir]/[name]-[hash].[ext]'Esta construcción resultaría en la siguiente estructura de archivos:
.
├── index.tsx
└── out
└── files
└── index-a1b2c3d4.jsCuando 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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: {
// valores predeterminados
entry: '[dir]/[name].[ext]',
chunk: '[name]-[hash].[ext]',
asset: '[name]-[hash].[ext]',
},
})CLI
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
await Bun.build({
entrypoints: ['./pages/a.tsx', './pages/b.tsx'],
outdir: './out',
root: '.',
})CLI
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:
.
└── pages
└── index.tsx
└── settings.tsxPodemos construir ambos entrypoints en el directorio pages:
JavaScript
await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
})CLI
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./outEsto resultaría en una estructura de archivos como esta:
.
└── pages
└── index.tsx
└── settings.tsx
└── out
└── index.js
└── settings.jsDado 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
await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
root: '.',
})CLI
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.jspublicPath
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 enoutdirtal 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
splittingestá 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:
import logo from "./logo.svg";
console.log(logo);var logo = "./logo-a7305bdef.svg";
console.log(logo);Establecer publicPath prefijará todas las rutas de archivo con el valor especificado.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
publicPath: 'https://cdn.example.com/', // predeterminado es undefined
})CLI
bun build ./index.tsx --outdir ./out --public-path 'https://cdn.example.com/'El archivo de salida ahora se vería algo como esto.
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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
define: {
STRING: JSON.stringify("value"),
"nested.boolean": "true",
},
})CLI
bun build ./index.tsx --outdir ./out --define STRING='"value"' --define nested.boolean=trueloader
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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
loader: {
".png": "dataurl",
".txt": "file",
},
})CLI
bun build ./index.tsx --outdir ./out --loader .png:dataurl --loader .txt:filebanner
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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
banner: 'use client;'
})CLI
bun build ./index.tsx --outdir ./out --banner 'use client";'footer
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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
footer: '// built with love in SF'
})CLI
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
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
drop: ["console", "debugger", "anyIdentifier.or.propertyAccess"],
})CLI
bun build ./index.tsx --outdir ./out --drop console --drop debuggerOutputs
La función Bun.build devuelve una Promise<BuildOutput>, definida como:
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.
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:
| Propiedad | Descripción |
|---|---|
kind | Qué 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). |
path | Ruta absoluta al archivo en disco |
loader | El loader usado para interpretar el archivo. Consulta Empaquetador > Loaders para ver cómo Bun mapea extensiones de archivo al loader integrado apropiado. |
hash | El hash del contenido del archivo. Siempre definido para assets. |
sourcemap | El 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().
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.
// build.ts
const build = await Bun.build({
/* */
});
const artifact = build.outputs[0];
console.log(artifact);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
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
bytecode: true,
})CLI
bun build ./index.tsx --outdir ./out --bytecodeEjecutables
Bun soporta "compilar" un entrypoint JavaScript/TypeScript en un ejecutable independiente. Este ejecutable contiene una copia del binario de Bun.
bun build ./cli.tsx --outfile mycli --compile
./mycliConsulta 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.
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.
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.
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
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;
}