import Build from "/snippets/cli/build.mdx";
O bundler nativo rápido do Bun pode ser usado através do comando CLI bun build ou da API JavaScript Bun.build().
Visão Geral
- API JS:
await Bun.build({ entrypoints, outdir }) - CLI:
bun build <entry> --outdir ./out - Watch:
--watchpara reconstruções incrementais - 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 ./buildÉ rápido. Os números abaixo representam o desempenho no benchmark three.js do esbuild.

Por que fazer bundling?
O bundler é uma peça fundamental de infraestrutura no ecossistema JavaScript. Como uma breve visão geral de por que o bundling é tão importante:
- Reduzindo requisições HTTP. Um único pacote em
node_modulespode consistir em centenas de arquivos e aplicações grandes podem ter dezenas de tais dependências. Carregar cada um desses arquivos com uma requisição HTTP separada torna-se insustentável muito rapidamente então bundlers são usados para converter o código fonte da nossa aplicação em um número menor de "bundles" autocontidos que podem ser carregados com uma única requisição. - Transformações de código. Aplicações modernas são comumente construídas com linguagens ou ferramentas como TypeScript JSX e CSS modules todos os quais devem ser convertidos em JavaScript e CSS puros antes de poderem ser consumidos por um navegador. O bundler é o lugar natural para configurar essas transformações.
- Recursos de frameworks. Frameworks dependem de plugins de bundler e transformações de código para implementar padrões comuns como roteamento baseado em sistema de arquivos co-localização de código cliente-servidor (pense em
getServerSidePropsou loaders do Remix) e server components. - Aplicações Full-stack. O bundler do Bun pode lidar com código de servidor e cliente em um único comando permitindo builds de produção otimizados e executáveis de arquivo único. Com imports HTML em tempo de build você pode empacotar toda a sua aplicação — assets de frontend e servidor backend — em uma única unidade implantável.
Vamos pular para a API do bundler.
NOTE
O bundler do Bun não se destina a substituir o `tsc` para verificação de tipos ou geração de declarações de tipo.Exemplo básico
Vamos criar nosso primeiro bundle. Você tem os seguintes dois arquivos que implementam um aplicativo React renderizado no lado do cliente simples.
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>;
}Aqui index.tsx é o "entrypoint" da nossa aplicação. Comumente este será um script que executa algum efeito colateral como iniciar um servidor ou—neste caso—inicializar uma raiz React. Como estamos usando TypeScript e JSX precisamos empacotar nosso código antes que ele possa ser enviado para o navegador.
Para criar nosso bundle:
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
});bun build ./index.tsx --outdir ./outPara cada arquivo especificado em entrypoints o Bun gerará um novo bundle. Este bundle será gravado no disco no diretório ./out (resolvido a partir do diretório de trabalho atual). Após executar o build o sistema de arquivos se parece com isto:
.
├── index.tsx
├── Component.tsx
└── out
└── index.jsO conteúdo de out/index.js se parecerá com isto:
// out/index.js
// ...
// ~20k linhas de código
// incluindo o conteúdo de `react-dom/client` e todas as suas dependências
// é aqui que as funções $jsxDEV e $createRoot são definidas
// 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 o runtime e o executor de testes o bundler suporta modo watch nativamente.
bun build ./index.tsx --outdir ./out --watchTipos de conteúdo
Como o runtime do Bun o bundler suporta uma série de tipos de arquivo nativamente. A tabela abaixo divide o conjunto de "loaders" padrão do bundler. Consulte Bundler > Tipos de arquivo para documentação completa.
| Extensões | Detalhes |
|---|---|
.js .jsx .cjs .mjs .mts .cts .ts .tsx | Usa o transpiler integrado do Bun para analisar o arquivo e transpilar sintaxe TypeScript/JSX para JavaScript puro. O bundler executa um conjunto de transformações padrão incluindo eliminação de código morto e tree shaking. No momento o Bun não tenta fazer down-conversion de sintaxe; se você usar sintaxe ECMAScript recente isso será refletido no código empacotado. |
.json | Arquivos JSON são analisados e incorporados no bundle como um objeto JavaScript.js<br/>import pkg from "./package.json";<br/>pkg.name; // => "my-package"<br/> |
.jsonc | JSON com comentários. Arquivos são analisados e incorporados no bundle como um objeto JavaScript.js<br/>import config from "./config.jsonc";<br/>config.name; // => "my-config"<br/> |
.toml | Arquivos TOML são analisados e incorporados no bundle como um objeto JavaScript.js<br/>import config from "./bunfig.toml";<br/>config.logLevel; // => "debug"<br/> |
.yaml .yml | Arquivos YAML são analisados e incorporados no bundle como um objeto JavaScript.js<br/>import config from "./config.yaml";<br/>config.name; // => "my-app"<br/> |
.txt | O conteúdo do arquivo de texto é lido e incorporado no bundle como uma string.js<br/>import contents from "./file.txt";<br/>console.log(contents); // => "Hello, world!"<br/> |
.html | Arquivos HTML são processados e quaisquer assets referenciados (scripts stylesheets imagens) são empacotados. |
.css | Arquivos CSS são agrupados em um único arquivo .css no diretório de saída. |
.node .wasm | Estes arquivos são suportados pelo runtime do Bun mas durante o bundling eles são tratados como assets. |
Assets
Se o bundler encontrar uma importação com uma extensão não reconhecida ele trata o arquivo importado como um arquivo externo. O arquivo referenciado é copiado como está para outdir e a importação é resolvida como um caminho para o arquivo.
// bundle entrypoint
import logo from "./logo.svg";
console.log(logo);// bundled output
var logo = "./logo-a7305bdef.svg";
console.log(logo);O comportamento exato do file loader também é impactado por naming e publicPath.
Plugins
O comportamento descrito nesta tabela pode ser substituído ou estendido com plugins. Consulte a página Bundler > Loaders para documentação completa.
API
entrypoints
Um array de caminhos correspondendo aos entrypoints da nossa aplicação. Um bundle será gerado para cada entrypoint.
JavaScript
const result = await Bun.build({
entrypoints: ["./index.ts"]
});CLI
bun build ./index.tsoutdir
O diretório onde os arquivos de saída serão gravados.
JavaScript
const result = await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out'
});
// => { success: boolean, outputs: `BuildArtifact[]`, logs: `BuildMessage[]` }CLI
bun build ./index.ts --outdir ./outSe outdir não for passado para a API JavaScript o código empacotado não será gravado no disco. Arquivos empacotados são retornados em um array de objetos BuildArtifact. Estes objetos são Blobs com propriedades extras; veja Outputs para documentação completa.
const result = await Bun.build({
entrypoints: ["./index.ts"],
});
for (const res of result.outputs) {
// Pode ser consumido como blobs
await res.text();
// Bun definirá os cabeçalhos Content-Type e Etag
new Response(res);
// Pode ser gravado manualmente mas você deve usar `outdir` neste caso.
Bun.write(path.join("out", res.path), res);
}Quando outdir está definido a propriedade path em um BuildArtifact será o caminho absoluto para onde foi gravado.
target
O ambiente de execução pretendido para o bundle.
JavaScript
await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out',
target: 'browser', // padrão
})CLI
bun build ./index.ts --outdir ./out --target browserDependendo do target o Bun aplicará diferentes regras de resolução de módulos e otimizações.
Padrão. Para gerar bundles destinados à execução em um navegador. Prioriza a condição de export "browser" ao resolver imports. Importar qualquer módulo built-in como node:events ou node:path funcionará mas chamar algumas funções como fs.readFile não funcionará.
Para gerar bundles destinados a serem executados pelo runtime do Bun. Em muitos casos não é necessário empacotar código do lado do servidor; você pode executar diretamente o código fonte sem modificação. No entanto empacotar seu código de servidor pode reduzir tempos de inicialização e melhorar o desempenho de execução. Este é o target a ser usado para construir aplicações full-stack com imports HTML em tempo de build onde tanto o código do servidor quanto do cliente são empacotados juntos.
Todos os bundles gerados com target: "bun" são marcados com um pragma especial // @bun que indica ao runtime do Bun que não há necessidade de re-transpilar o arquivo antes da execução.
Se qualquer entrypoint contiver um shebang do Bun (#!/usr/bin/env bun) o bundler usará como padrão target: "bun" em vez de "browser".
Ao usar target: "bun" e format: "cjs" juntos o pragma // @bun @bun-cjs é adicionado e o wrapper CommonJS não é compatível com Node.js.
Para gerar bundles destinados a serem executados pelo Node.js. Prioriza a condição de export "node" ao resolver imports e produz .mjs. No futuro isso fará automaticamente polyfill do global Bun e outros módulos built-in bun:* embora isso ainda não esteja implementado.
format
Especifica o formato de módulo a ser usado nos bundles gerados.
O Bun usa como padrão "esm" e fornece suporte experimental para "cjs" e "iife".
format: "esm" - ES Module
Este é o formato padrão que suporta sintaxe de ES Module incluindo top-level await import.meta e mais.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
format: "esm",
})CLI
bun build ./index.tsx --outdir ./out --format esmPara usar sintaxe de ES Module em navegadores defina format como "esm" e certifique-se de que sua tag <script type="module"> tenha type="module" definido.
format: "cjs" - CommonJS
Para construir um módulo CommonJS defina format como "cjs". Ao escolher "cjs" o target padrão muda de "browser" (esm) para "node" (cjs). Módulos CommonJS transpilados com format: "cjs", target: "node" podem ser executados tanto no Bun quanto no Node.js (assumindo que as APIs em uso são suportadas por 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 quando suportarmos globalNames.
jsx
Configure o comportamento da transformação JSX. Permite controle fino sobre como o JSX é compilado.
Exemplo de runtime clássico (usa factory e fragment):
await Bun.build({
entrypoints: ["./app.tsx"],
outdir: "./out",
jsx: {
factory: "h",
fragment: "Fragment",
runtime: "classic",
},
});# Configuração JSX é tratada via bunfig.toml ou tsconfig.json
bun build ./app.tsx --outdir ./outExemplo de runtime automático (usa importSource):
await Bun.build({
entrypoints: ["./app.tsx"],
outdir: "./out",
jsx: {
importSource: "preact",
runtime: "automatic",
},
});# Configuração JSX é tratada via bunfig.toml ou tsconfig.json
bun build ./app.tsx --outdir ./outsplitting
Se deve habilitar code splitting.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
splitting: false, // padrão
})CLI
bun build ./index.tsx --outdir ./out --splittingQuando true o bundler habilitará code splitting. Quando múltiplos entrypoints importam o mesmo arquivo módulo ou conjunto de arquivos/módulos frequentemente é útil dividir o código compartilhado em um bundle separado. Este bundle compartilhado é conhecido como um chunk. Considere os seguintes arquivos:
import { shared } from "./shared.ts";import { shared } from "./shared.ts";export const shared = "shared";Para empacotar entry-a.ts e entry-b.ts com 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 --splittingExecutar este build resultará nos seguintes arquivos:
.
├── entry-a.tsx
├── entry-b.tsx
├── shared.tsx
└── out
├── entry-a.js
├── entry-b.js
└── chunk-2fce6291bf86559d.jsO arquivo chunk-2fce6291bf86559d.js gerado contém o código compartilhado. Para evitar colisões o nome do arquivo inclui automaticamente um hash de conteúdo por padrão. Isso pode ser personalizado com naming.
plugins
Uma lista de plugins para usar durante o bundling.
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
plugins: [
/* ... */
],
});O Bun implementa um sistema de plugins universal tanto para o runtime quanto para o bundler do Bun. Consulte a documentação de plugins para documentação completa.
env
Controla como variáveis de ambiente são manipuladas durante o bundling. Internamente isso usa define para injetar variáveis de ambiente no bundle mas facilita especificar as variáveis de ambiente a injetar.
env: "inline"
Injeta variáveis de ambiente na saída do bundle convertendo referências process.env.FOO em literais de string contendo os valores reais das variáveis de ambiente.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
env: "inline",
})CLI
bun build ./index.tsx --outdir ./out --env inlinePara a entrada abaixo:
// input.js
console.log(process.env.FOO);
console.log(process.env.BAZ);O bundle gerado conterá o seguinte código:
// output.js
console.log("bar");
console.log("123");env: "PUBLIC_*" (prefixo)
Incorpora variáveis de ambiente correspondendo ao prefixo dado (a parte antes do caractere *) substituindo process.env.FOO pelo valor real da variável de ambiente. Isso é útil para incorporar seletivamente variáveis de ambiente para coisas como URLs públicas ou tokens do lado do cliente sem se preocupar em injetar credenciais privadas nos bundles de saída.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
// Inline todas as env vars que começam com "ACME_PUBLIC_"
env: "ACME_PUBLIC_*",
})CLI
bun build ./index.tsx --outdir ./out --env ACME_PUBLIC_*Por exemplo dadas as seguintes variáveis de ambiente:
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.comE código fonte:
console.log(process.env.FOO);
console.log(process.env.ACME_PUBLIC_URL);
console.log(process.env.BAZ);O bundle gerado conterá o seguinte código:
console.log(process.env.FOO);
console.log("https://acme.com");
console.log(process.env.BAZ);env: "disable"
Desabilita totalmente a injeção de variáveis de ambiente.
sourcemap
Especifica o tipo de sourcemap a ser gerado.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
sourcemap: 'linked', // padrão 'none'
})CLI
bun build ./index.tsx --outdir ./out --sourcemap linked| Valor | Descrição |
|---|---|
"none" | Padrão. Nenhum sourcemap é gerado. |
"linked" | Um arquivo separado *.js.map é criado ao lado de cada bundle *.js usando um comentário //# sourceMappingURL para vincular os dois. Requer que --outdir seja definido. A URL base disso pode ser personalizada com --public-path.js<br/>// <código empacotado aqui><br/><br/>//# sourceMappingURL=bundle.js.map<br/> |
"external" | Um arquivo separado *.js.map é criado ao lado de cada bundle *.js sem inserir um comentário //# sourceMappingURL.Bundles gerados contêm um debug id que pode ser usado para associar um bundle ao seu sourcemap correspondente. Este debugId é adicionado como um comentário na parte inferior do arquivo.js<br/>// <código gerado do bundle><br/><br/>//# debugId=<DEBUG ID><br/> |
"inline" | Um sourcemap é gerado e anexado ao final do bundle gerado como um payload base64.js<br/>// <código empacotado aqui><br/><br/>//# sourceMappingURL=data:application/json;base64,<sourcemap codificado aqui><br/> |
O arquivo sourcemap *.js.map associado será um arquivo JSON contendo uma propriedade debugId equivalente.
minify
Se deve habilitar minificação. Padrão false.
NOTE
Ao target `bun` identificadores serão minificados por padrão.Para habilitar todas as opções de minificação:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: true, // padrão false
})CLI
bun build ./index.tsx --outdir ./out --minifyPara habilitar granularmente certas minificações:
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
Uma lista de caminhos de importação para considerar como externos. Padrão [].
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ["lodash", "react"], // padrão: []
})CLI
bun build ./index.tsx --outdir ./out --external lodash --external reactUma importação externa é uma que não será incluída no bundle final. Em vez disso a declaração de importação será deixada como está para ser resolvida em tempo de execução.
Por exemplo considere o seguinte arquivo de entrypoint:
import _ from "lodash";
import { z } from "zod";
const value = z.string().parse("Hello world!");
console.log(_.upperCase(value));Normalmente empacotar index.tsx geraria um bundle contendo todo o código fonte do pacote "zod". Se em vez disso quisermos deixar a declaração de importação como está podemos marcá-la como externa:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['zod'],
})CLI
bun build ./index.tsx --outdir ./out --external zodO bundle gerado se parecerá com isto:
import { z } from "zod";
// ...
// o conteúdo do pacote "lodash"
// incluindo a função `_.upperCase`
var value = z.string().parse("Hello world!");
console.log(_.upperCase(value));Para marcar todas as importações como externas use o wildcard *:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['*'],
})CLI
bun build ./index.tsx --outdir ./out --external '*'packages
Controla se dependências de pacotes são incluídas no bundle ou não. Valores possíveis: bundle (padrão), external. O Bun trata qualquer importação cujo caminho não começa com ., .. ou / como um pacote.
JavaScript
await Bun.build({
entrypoints: ['./index.ts'],
packages: 'external',
})CLI
bun build ./index.ts --packages externalnaming
Personaliza os nomes de arquivos gerados. Padrão ./[dir]/[name].[ext].
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: "[dir]/[name].[ext]", // padrão
})CLI
bun build ./index.tsx --outdir ./out --entry-naming "[dir]/[name].[ext]"Por padrão os nomes dos bundles gerados são baseados no nome do entrypoint associado.
.
├── index.tsx
└── out
└── index.jsCom múltiplos entrypoints a hierarquia de arquivos gerada refletirá a estrutura de diretórios dos entrypoints.
.
├── index.tsx
└── nested
└── index.tsx
└── out
├── index.js
└── nested
└── index.jsOs nomes e localizações dos arquivos gerados podem ser personalizados com o campo naming. Este campo aceita uma string de template que é usada para gerar os nomes de arquivos para todos os bundles correspondentes aos entrypoints onde os seguintes tokens são substituídos por seus valores correspondentes:
[name]- O nome do arquivo de entrypoint sem a extensão.[ext]- A extensão do bundle gerado.[hash]- Um hash do conteúdo do bundle.[dir]- O caminho relativo da raiz do projeto até o diretório pai do arquivo fonte.
Por exemplo:
| Token | [name] | [ext] | [hash] | [dir] |
|---|---|---|---|---|
./index.tsx | index | js | a1b2c3d4 | "" (string vazia) |
./nested/entry.ts | entry | js | c3d4e5f6 | "nested" |
Podemos combinar estes tokens para criar uma string de template. Por exemplo para incluir o hash nos nomes dos bundles gerados:
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]'Este build resultaria na seguinte estrutura de arquivos:
.
├── index.tsx
└── out
└── files
└── index-a1b2c3d4.jsQuando uma string é fornecida para o campo naming ela é usada apenas para bundles que correspondem aos entrypoints. Os nomes de chunks e assets copiados não são afetados. Usando a API JavaScript strings de template separadas podem ser especificadas para cada tipo de arquivo gerado.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: {
// valores padrão
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
O diretório raiz do projeto.
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 .Se não especificado é calculado para ser o primeiro ancestral comum de todos os arquivos de entrypoint. Considere a seguinte estrutura de arquivos:
.
└── pages
└── index.tsx
└── settings.tsxPodemos construir ambos os entrypoints no diretório pages:
JavaScript
await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
})CLI
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./outIsso resultaria em uma estrutura de arquivos como esta:
.
└── pages
└── index.tsx
└── settings.tsx
└── out
└── index.js
└── settings.jsComo o diretório pages é o primeiro ancestral comum dos arquivos de entrypoint ele é considerado a raiz do projeto. Isso significa que os bundles gerados vivem no nível superior do diretório out; não há diretório out/pages.
Este comportamento pode ser substituído especificando a opção 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 .Ao especificar . como root a estrutura de arquivos gerada se parecerá com isto:
.
└── pages
└── index.tsx
└── settings.tsx
└── out
└── pages
└── index.js
└── settings.jspublicPath
Um prefixo a ser anexado a quaisquer caminhos de importação no código empacotado.
Em muitos casos bundles gerados não conterão declarações de importação. Afinal o objetivo do bundling é combinar todo o código em um único arquivo. No entanto há vários casos em que os bundles gerados conterão declarações de importação.
- Imports de assets — Ao importar um tipo de arquivo não reconhecido como
*.svgo bundler delega ao file loader que copia o arquivo paraoutdircomo está. A importação é convertida em uma variável - Módulos externos — Arquivos e módulos podem ser marcados como externos nesse caso eles não serão incluídos no bundle. Em vez disso a declaração de importação será deixada no bundle final.
- Chunking. Quando
splittingestá habilitado o bundler pode gerar arquivos "chunk" separados que representam código compartilhado entre múltiplos entrypoints.
Em qualquer um desses casos os bundles finais podem conter caminhos para outros arquivos. Por padrão estas importações são relativas. Aqui está um exemplo de um import de asset simples:
import logo from "./logo.svg";
console.log(logo);var logo = "./logo-a7305bdef.svg";
console.log(logo);Definir publicPath prefixará todos os caminhos de arquivo com o valor especificado.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
publicPath: 'https://cdn.example.com/', // padrão é undefined
})CLI
bun build ./index.tsx --outdir ./out --public-path 'https://cdn.example.com/'O arquivo de saída se parecerá com isto:
var logo = "https://cdn.example.com/logo-a7305bdef.svg";define
Um mapa de identificadores globais a serem substituídos em tempo de build. Chaves deste objeto são nomes de identificadores e valores são strings JSON que serão incorporadas.
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
Um mapa de extensões de arquivo para nomes de loaders built-in. Isso pode ser usado para personalizar rapidamente como certos arquivos são carregados.
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
Um banner a ser adicionado ao bundle final isso pode ser uma diretiva como use client para react ou um bloco de comentário como uma licença para o 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
Um footer a ser adicionado ao bundle final isso pode ser algo como um bloco de comentário para uma licença ou apenas um easter egg 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
Remove chamadas de função de um bundle. Por exemplo --drop=console removerá todas as chamadas para console.log. Argumentos para chamadas também serão removidos independentemente de esses argumentos poderem ter efeitos colaterais. Dropar debugger removerá todas as declarações 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
A função Bun.build retorna uma Promise<BuildOutput> definida como:
interface BuildOutput {
outputs: BuildArtifact[];
success: boolean;
logs: Array<object>; // veja docs para detalhes
}
interface BuildArtifact extends Blob {
kind: "entry-point" | "chunk" | "asset" | "sourcemap";
path: string;
loader: Loader;
hash: string | null;
sourcemap: BuildArtifact | null;
}O array outputs contém todos os arquivos que foram gerados pelo build. Cada artefato implementa a interface 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 artefato também contém as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
kind | Que tipo de saída de build este arquivo é. Um build gera entrypoints empacotados chunks de code-split sourcemaps bytecode e assets copiados (como imagens). |
path | Caminho absoluto para o arquivo no disco |
loader | O loader foi usado para interpretar o arquivo. Veja Bundler > Loaders para ver como o Bun mapeia extensões de arquivo para o loader built-in apropriado. |
hash | O hash do conteúdo do arquivo. Sempre definido para assets. |
sourcemap | O arquivo sourcemap correspondente a este arquivo se gerado. Apenas definido para entrypoints e chunks. |
Semelhante ao BunFile objetos BuildArtifact podem ser passados diretamente para new Response().
const build = await Bun.build({
/* */
});
const artifact = build.outputs[0];
// O cabeçalho Content-Type é definido automaticamente
return new Response(artifact);O runtime do Bun implementa impressão especial de objetos BuildArtifact para facilitar a depuração.
// 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
A opção bytecode: boolean pode ser usada para gerar bytecode para qualquer entrypoint JavaScript/TypeScript. Isso pode melhorar muito os tempos de inicialização para aplicações grandes. Suportado apenas para o formato "cjs" suporta apenas "target": "bun" e depende de uma versão correspondente do Bun. Isso adiciona um arquivo .jsc correspondente para cada entrypoint.
JavaScript
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
bytecode: true,
})CLI
bun build ./index.tsx --outdir ./out --bytecodeExecutáveis
O Bun suporta "compilar" um entrypoint JavaScript/TypeScript em um executável autônomo. Este executável contém uma cópia do binário do Bun.
bun build ./cli.tsx --outfile mycli --compile
./mycliConsulte Bundler > Executáveis para documentação completa.
Logs e erros
Em falha Bun.build retorna uma promise rejeitada com um AggregateError. Isso pode ser registrado no console para impressão bonita da lista de erros ou lido programaticamente com um bloco try/catch.
try {
const result = await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
});
} catch (e) {
// TypeScript não permite anotações na cláusula catch
const error = e as AggregateError;
console.error("Build Failed");
// Exemplo: Usando o formatter built-in
console.error(error);
// Exemplo: Serializando a falha como uma string JSON.
console.error(JSON.stringify(error, null, 2));
}Na maioria das vezes um try/catch explícito não é necessário pois o Bun imprimirá neatmente exceções não capturadas. É suficiente apenas usar um await de nível superior na chamada Bun.build.
Cada item em error.errors é uma instância de BuildMessage ou ResolveMessage (subclasses de Error) contendo informações detalhadas para cada erro.
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;
}Em sucesso de build o objeto retornado contém uma propriedade logs que contém avisos do bundler e mensagens de informação.
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á neatmente o objeto de mensagem
console.warn(message);
}
}Referência
interface Bun {
build(options: BuildOptions): Promise<BuildOutput>;
}
interface BuildConfig {
entrypoints: string[]; // lista de caminhos de arquivo
outdir?: string; // diretório de saída
target?: Target; // padrão: "browser"
/**
* Formato de módulo de saída. Top-level await é suportado apenas para `"esm"`.
*
* Pode ser:
* - `"esm"`
* - `"cjs"` (**experimental**)
* - `"iife"` (**experimental**)
*
* @default "esm"
*/
format?: "esm" | "cjs" | "iife";
/**
* Objeto de configuração JSX para controlar o comportamento da transformação 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; // raiz do projeto
splitting?: boolean; // padrão true habilita 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; // padrão: "none", true -> "inline"
/**
* Condições de export `package.json` usadas ao resolver imports
*
* Equivalente a `--conditions` em `bun build` ou `bun run`.
*
* https://nodejs.org/api/packages.html#exports
*/
conditions?: Array<string> | string;
/**
* Controla como variáveis de ambiente são manipuladas durante o bundling.
*
* Pode ser um de:
* - `"inline"`: Injeta variáveis de ambiente na saída do bundle convertendo referências `process.env.FOO`
* em literais de string contendo os valores reais das variáveis de ambiente
* - `"disable"`: Desabilita totalmente a injeção de variáveis de ambiente
* - Uma string terminando em `*`: Incorpora variáveis de ambiente que correspondem ao prefixo dado.
* Por exemplo `"MY_PUBLIC_*"` incluirá apenas env vars começando com "MY_PUBLIC_"
*/
env?: "inline" | "disable" | `${string}*`;
minify?:
| boolean
| {
whitespace?: boolean;
syntax?: boolean;
identifiers?: boolean;
};
/**
* Ignora anotações de eliminação de código morto/tree-shaking como @__PURE__ e campos
* "sideEffects" do package.json. Isso deve ser usado apenas como uma solução temporária para
* anotações incorretas em bibliotecas.
*/
ignoreDCEAnnotations?: boolean;
/**
* Força a emissão de anotações @__PURE__ mesmo se minify.whitespace for true.
*/
emitDCEAnnotations?: boolean;
/**
* Gera bytecode para a saída. Isso pode melhorar dramaticamente os tempos de
* inicialização a frio mas tornará a saída final maior e aumentará ligeiramente
* o uso de memória.
*
* Bytecode é atualmente suportado apenas para CommonJS (`format: "cjs"`).
*
* Deve ser `target: "bun"`
* @default false
*/
bytecode?: boolean;
/**
* Adiciona um banner ao código empacotado como "use client";
*/
banner?: string;
/**
* Adiciona um footer ao código empacotado como um bloco de comentário como
*
* `// made with bun!`
*/
footer?: string;
/**
* Remove chamadas de função para acessos de propriedade correspondentes.
*/
drop?: string[];
/**
* - Quando definido como `true` a promise retornada rejeita com um AggregateError quando um erro de build acontece.
* - Quando definido como `false` retorna um {@link BuildOutput} com `{success: false}`
*
* @default true
*/
throw?: boolean;
/**
* Caminho do arquivo tsconfig.json personalizado para usar para resolução de caminho.
* Equivalente a `--tsconfig-override` na 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;
}