Skip to content

O bundler do Bun implementa a flag --compile para gerar um binário autônomo a partir de um arquivo TypeScript ou JavaScript.

bash
bun build ./cli.ts --compile --outfile mycli
ts
console.log("Hello world!");

Isso empacota cli.ts em um executável que pode ser executado diretamente:

bash
./mycli
txt
Hello world!

Todos os arquivos e pacotes importados são empacotados no executável, junto com uma cópia do runtime do Bun. Todas as APIs built-in do Bun e Node.js são suportadas.


Cross-compilação para outras plataformas

A flag --target permite que você compile seu executável autônomo para um sistema operacional, arquitetura ou versão do Bun diferente da máquina onde você está executando bun build.

Para build para Linux x64 (maioria dos servidores):

bash
bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp

# Para suportar CPUs anteriores a 2013, use a versão baseline (nehalem)
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp

# Para suportar explicitamente apenas CPUs de 2013 em diante, use a versão moderna (haswell)
# moderna é mais rápida, mas baseline é mais compatível.
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp

Para build para Linux ARM64 (ex: Graviton ou Raspberry Pi):

bash
# Nota: a arquitetura padrão é x64 se nenhuma arquitetura for especificada.
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp

Para build para Windows x64:

bash
bun build --compile --target=bun-windows-x64 ./path/to/my/app.ts --outfile myapp

# Para suportar CPUs anteriores a 2013, use a versão baseline (nehalem)
bun build --compile --target=bun-windows-x64-baseline ./path/to/my/app.ts --outfile myapp

# Para suportar explicitamente apenas CPUs de 2013 em diante, use a versão moderna (haswell)
bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfile myapp

# nota: se nenhuma extensão .exe for fornecida, Bun adicionará automaticamente para executáveis Windows

Para build para macOS arm64:

bash
bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myapp

Para build para macOS x64:

bash
bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myapp

Targets suportados

A ordem da flag --target não importa, desde que sejam delimitadas por -.

--targetSistema OperacionalArquiteturaModernoBaselineLibc
bun-linux-x64Linuxx64glibc
bun-linux-arm64Linuxarm64N/Aglibc
bun-windows-x64Windowsx64-
bun-windows-arm64Windowsarm64-
bun-darwin-x64macOSx64-
bun-darwin-arm64macOSarm64N/A-
bun-linux-x64-muslLinuxx64musl
bun-linux-arm64-muslLinuxarm64N/Amusl

Constantes em tempo de build

Use a flag --define para injetar constantes em tempo de build no seu executável, como números de versão, timestamps de build ou valores de configuração:

bash
bun build --compile --define BUILD_VERSION='"1.2.3"' --define BUILD_TIME='"2024-01-15T10:30:00Z"' src/cli.ts --outfile mycli

Estas constantes são incorporadas diretamente no seu binário compilado em tempo de build, fornecendo zero overhead em runtime e habilitando otimizações de eliminação de código morto.

NOTE

Para exemplos abrangentes e padrões avançados, veja o [guia de constantes em tempo de build](/pt/guides/runtime/build-time-constants).

Deploy em produção

Executáveis compilados reduzem uso de memória e melhoram o tempo de inicialização do Bun.

Normalmente, Bun lê e transpila arquivos JavaScript e TypeScript em import e require. Isso é parte do que faz tanto do Bun "funcionar", mas não é gratuito. Custa tempo e memória ler arquivos do disco, resolver caminhos de arquivo, analisar, transpilar e imprimir código fonte.

Com executáveis compilados, você pode mover este custo de runtime para tempo de build.

Ao fazer deploy em produção, recomendamos o seguinte:

bash
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp

Compilação de bytecode

Para melhorar o tempo de inicialização, habilite compilação de bytecode:

bash
bun build --compile --minify --sourcemap --bytecode ./path/to/my/app.ts --outfile myapp

Usando compilação de bytecode, tsc inicia 2x mais rápido:

Compilação de bytecode move overhead de parsing para arquivos de entrada grandes de runtime para tempo de bundle. Seu app inicia mais rápido, em troca de tornar o comando bun build um pouco mais lento. Não ofusca o código fonte.

O que estas flags fazem?

O argumento --minify otimiza o tamanho do código transpilado. Se você tem uma aplicação grande, isso pode economizar megabytes de espaço. Para aplicações menores, ainda pode melhorar um pouco o tempo de inicialização.

O argumento --sourcemap incorpora um sourcemap comprimido com zstd, para que erros e stacktraces apontem para suas localizações originais em vez da localização transpilada. Bun automaticamente descomprime e resolve o sourcemap quando um erro ocorre.

O argumento --bytecode habilita compilação de bytecode. Toda vez que você executa código JavaScript no Bun, JavaScriptCore (o engine) compila seu código fonte em bytecode. Podemos mover este trabalho de parsing de runtime para tempo de bundle, economizando tempo de inicialização.


Incorporação de argumentos de runtime

--compile-exec-argv="args" - Incorpora argumentos de runtime disponíveis via process.execArgv:

bash
bun build --compile --compile-exec-argv="--smol --user-agent=MyBot" ./app.ts --outfile myapp
ts
// No app compilado
console.log(process.execArgv); // ["--smol", "--user-agent=MyBot"]

Desabilitar carregamento automático de config

Por padrão, executáveis autônomos procuram por arquivos .env e bunfig.toml no diretório onde o executável é executado. Você pode desabilitar este comportamento em tempo de build para execução determinística independentemente do diretório de trabalho do usuário.

bash
# Desabilita carregamento de .env
bun build --compile --no-compile-autoload-dotenv ./app.ts --outfile myapp

# Desabilita carregamento de bunfig.toml
bun build --compile --no-compile-autoload-bunfig ./app.ts --outfile myapp

# Desabilita ambos
bun build --compile --no-compile-autoload-dotenv --no-compile-autoload-bunfig ./app.ts --outfile myapp

Você também pode configurar isso via API JavaScript:

ts
await Bun.build({
  entrypoints: ["./app.ts"],
  compile: {
    autoloadDotenv: false, // Desabilita carregamento de .env
    autoloadBunfig: false, // Desabilita carregamento de bunfig.toml
  },
});

Agir como a CLI do Bun

NOTE

Novo no Bun v1.2.16

Você pode executar um executável autônomo como se fosse a CLI bun definindo a variável de ambiente BUN_BE_BUN=1. Quando esta variável está definida, o executável ignora seu entrypoint incorporado e expõe todos os recursos da CLI do Bun.

Por exemplo, considere um executável compilado a partir de um script simples:

bash
echo "console.log(\"you shouldn't see this\");" > such-bun.js
bun build --compile ./such-bun.js
txt
[3ms] bundle 1 modules
[89ms] compile such-bun

Normalmente, executar ./such-bun com argumentos executaria o script.

bash
# Executável executa seu próprio entrypoint por padrão
./such-bun install
txt
you shouldn't see this

No entanto, com a variável de ambiente BUN_BE_BUN=1, age exatamente como o binário bun:

bash
# Com a variável de ambiente, o executável age como a CLI `bun`
BUN_BE_BUN=1 ./such-bun install
txt
bun install v1.2.16-canary.1 (1d1db811)
Checked 63 installs across 64 packages (no changes) [5.00ms]

Isso é útil para construir ferramentas CLI em cima do Bun que podem precisar instalar pacotes, empacotar dependências, executar arquivos diferentes ou locais e mais sem precisar baixar um binário separado ou instalar bun.


Executáveis full-stack

NOTE

Novo no Bun v1.2.17

A flag --compile do Bun pode criar executáveis autônomos que contêm tanto código de servidor quanto de cliente, tornando-o ideal para aplicações full-stack. Quando você importa um arquivo HTML no seu código de servidor, Bun automaticamente empacota todos os assets de frontend (JavaScript, CSS, etc.) e os incorpora no executável. Quando Bun vê o import HTML no servidor, ele inicia um processo de build de frontend para empacotar JavaScript, CSS e outros assets.

ts
import { serve } from "bun";
import index from "./index.html";

const server = serve({
  routes: {
    "/": index,
    "/api/hello": { GET: () => Response.json({ message: "Hello from API" }) },
  },
});

console.log(`Server running at http://localhost:${server.port}`);
html
<!DOCTYPE html>
<html>
  <head>
    <title>My App</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <h1>Hello World</h1>
    <script src="./app.ts"></script>
  </body>
</html>
ts
console.log("Hello from the client!");
css
body {
  background-color: #f0f0f0;
}

Para build disto em um único executável:

bash
bun build --compile ./server.ts --outfile myapp

Isso cria um binário autocontido que inclui:

  • Seu código de servidor
  • O runtime do Bun
  • Todos os assets de frontend (HTML, CSS, JavaScript)
  • Quaisquer pacotes npm usados pelo seu servidor

O resultado é um único arquivo que pode ser implantado em qualquer lugar sem precisar de Node.js, Bun ou quaisquer dependências instaladas. Basta executar:

bash
./myapp

Bun automaticamente lida com servir os assets de frontend com tipos MIME e cabeçalhos de cache apropriados. O import HTML é substituído por um objeto manifest que Bun.serve usa para servir eficientemente assets pré-empacotados.

Para mais detalhes sobre construir aplicações full-stack com Bun, veja o guia full-stack.


Worker

Para usar workers em um executável autônomo, adicione o entrypoint do worker aos argumentos da CLI:

bash
bun build --compile ./index.ts ./my-worker.ts --outfile myapp

Então, referencie o worker no seu código:

ts
console.log("Hello from Bun!");

// Qualquer um destes funcionará:
new Worker("./my-worker.ts");
new Worker(new URL("./my-worker.ts", import.meta.url));
new Worker(new URL("./my-worker.ts", import.meta.url).href);

Quando você adiciona múltiplos entrypoints a um executável autônomo, eles serão empacotados separadamente no executável.

No futuro, podemos detectar automaticamente usos de caminhos estaticamente conhecidos em new Worker(path) e então empacotá-los no executável, mas por enquanto, você precisará adicioná-lo ao comando shell manualmente como no exemplo acima.

Se você usar um caminho relativo para um arquivo não incluído no executável autônomo, ele tentará carregar aquele caminho do disco relativo ao diretório de trabalho atual do processo (e então errará se não existir).


SQLite

Você pode usar imports bun:sqlite com bun build --compile.

Por padrão, o banco de dados é resolvido relativo ao diretório de trabalho atual do processo.

ts
import db from "./my.db" with { type: "sqlite" };

console.log(db.query("select * from users LIMIT 1").get());

Isso significa que se o executável está localizado em /usr/bin/hello, o terminal do usuário está em /home/me/Desktop, ele procurará por /home/me/Desktop/my.db.

bash
cd /home/me/Desktop
./hello

Incorporar assets e arquivos

Executáveis autônomos suportam incorporação de arquivos.

Para incorporar arquivos em um executável com bun build --compile, importe o arquivo no seu código.

ts
// isto se torna um caminho de arquivo interno
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

export default {
  fetch(req) {
    // Arquivos incorporados podem ser streamados de objetos Response
    return new Response(file(icon));
  },
};

Arquivos incorporados podem ser lidos usando as funções de Bun.file ou a função fs.readFile do Node.js (em "node:fs").

Por exemplo, para ler o conteúdo do arquivo incorporado:

ts
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

const bytes = await file(icon).arrayBuffer();
// await fs.promises.readFile(icon)
// fs.readFileSync(icon)

Incorporar bancos de dados SQLite

Se sua aplicação quer incorporar um banco de dados SQLite, defina type: "sqlite" no atributo de import e o atributo embed para "true".

ts
import myEmbeddedDb from "./my.db" with { type: "sqlite", embed: "true" };

console.log(myEmbeddedDb.query("select * from users LIMIT 1").get());

Este banco de dados é read-write, mas todas as alterações são perdidas quando o executável sai (já que é armazenado em memória).

Incorporar Addons N-API

Você pode incorporar arquivos .node em executáveis.

ts
const addon = require("./addon.node");

console.log(addon.hello());

Infelizmente, se você está usando @mapbox/node-pre-gyp ou outras ferramentas similares, precisará garantir que o arquivo .node seja diretamente requerido ou não será empacotado corretamente.

Incorporar diretórios

Para incorporar um diretório com bun build --compile, use um shell glob no seu comando bun build:

bash
bun build --compile ./index.ts ./public/**/*.png

Então, você pode referenciar os arquivos no seu código:

ts
import icon from "./public/assets/icon.png" with { type: "file" };
import { file } from "bun";

export default {
  fetch(req) {
    // Arquivos incorporados podem ser streamados de objetos Response
    return new Response(file(icon));
  },
};

Isto é honestamente um workaround, e esperamos melhorar isso no futuro com uma API mais direta.

Listar arquivos incorporados

Para obter uma lista de todos os arquivos incorporados, use Bun.embeddedFiles:

ts
import "./icon.png" with { type: "file" };
import { embeddedFiles } from "bun";

console.log(embeddedFiles[0].name); // `icon-${hash}.png`

Bun.embeddedFiles retorna um array de objetos Blob que você pode usar para obter o tamanho, conteúdo e outras propriedades dos arquivos.

ts
embeddedFiles: Blob[]

A lista de arquivos incorporados exclui código fonte empacotado como arquivos .ts e .js.

Hash de conteúdo

Por padrão, arquivos incorporados têm um hash de conteúdo anexado ao seu nome. Isso é útil para situações onde você quer servir o arquivo de uma URL ou CDN e ter menos problemas de invalidação de cache. Mas às vezes, isso é inesperado e você pode querer o nome original:

Para desabilitar o hash de conteúdo, passe --asset-naming para bun build --compile assim:

bash
bun build --compile --asset-naming="[name].[ext]" ./index.ts

Minificação

Para reduzir o tamanho do executável um pouco, passe --minify para bun build --compile. Isso usa o minificador do Bun para reduzir o tamanho do código. No geral, porém, o binário do Bun ainda é grande demais e precisamos torná-lo menor.


Flags específicas do Windows

Ao compilar um executável autônomo no Windows, há duas opções específicas de plataforma que podem ser usadas para personalizar metadados no arquivo .exe gerado:

  • --windows-icon=path/to/icon.ico para personalizar o ícone do arquivo executável.
  • --windows-hide-console para desabilitar o terminal de fundo, que pode ser usado para aplicações que não precisam de TTY.

Code signing no macOS

Para codesignar um executável autônomo no macOS (o que corrige avisos do Gatekeeper), use o comando codesign.

bash
codesign --deep --force -vvvv --sign "XXXXXXXXXX" ./myapp

Recomendamos incluir um arquivo entitlements.plist com permissões JIT.

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.disable-executable-page-protection</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
</dict>
</plist>

Para codesignar com suporte JIT, passe a flag --entitlements para codesign.

bash
codesign --deep --force -vvvv --sign "XXXXXXXXXX" --entitlements entitlements.plist ./myapp

Após codesignar, verifique o executável:

bash
codesign -vvv --verify ./myapp
./myapp: valid on disk
./myapp: satisfies its Designated Requirement

Code splitting

Executáveis autônomos suportam code splitting. Use --compile com --splitting para criar um executável que carrega chunks de code-split em runtime.

bash
bun build --compile --splitting ./src/entry.ts --outdir ./build
ts
console.log("Entrypoint loaded");
const lazy = await import("./lazy.ts");
lazy.hello();
ts
export function hello() {
  console.log("Lazy module loaded");
}
bash
./build/entry
txt
Entrypoint loaded
Lazy module loaded

Argumentos de CLI não suportados

Atualmente, a flag --compile pode aceitar apenas um único entrypoint por vez e não suporta as seguintes flags:

  • --outdir — use outfile em vez disso (exceto ao usar com --splitting).
  • --public-path
  • --target=node ou --target=browser
  • --no-bundle - sempre empacotamos tudo no executável.

Bun by www.bunjs.com.cn edit