O bundler do Bun implementa a flag --compile para gerar um binário autônomo a partir de um arquivo TypeScript ou JavaScript.
bun build ./cli.ts --compile --outfile mycliconsole.log("Hello world!");Isso empacota cli.ts em um executável que pode ser executado diretamente:
./mycliHello 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):
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 myappPara build para Linux ARM64 (ex: Graviton ou Raspberry Pi):
# Nota: a arquitetura padrão é x64 se nenhuma arquitetura for especificada.
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myappPara build para Windows x64:
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 WindowsPara build para macOS arm64:
bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myappPara build para macOS x64:
bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myappTargets suportados
A ordem da flag --target não importa, desde que sejam delimitadas por -.
| --target | Sistema Operacional | Arquitetura | Moderno | Baseline | Libc |
|---|---|---|---|---|---|
| bun-linux-x64 | Linux | x64 | ✅ | ✅ | glibc |
| bun-linux-arm64 | Linux | arm64 | ✅ | N/A | glibc |
| bun-windows-x64 | Windows | x64 | ✅ | ✅ | - |
| ❌ | ❌ | - | |||
| bun-darwin-x64 | macOS | x64 | ✅ | ✅ | - |
| bun-darwin-arm64 | macOS | arm64 | ✅ | N/A | - |
| bun-linux-x64-musl | Linux | x64 | ✅ | ✅ | musl |
| bun-linux-arm64-musl | Linux | arm64 | ✅ | N/A | musl |
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:
bun build --compile --define BUILD_VERSION='"1.2.3"' --define BUILD_TIME='"2024-01-15T10:30:00Z"' src/cli.ts --outfile mycliEstas 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:
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myappCompilação de bytecode
Para melhorar o tempo de inicialização, habilite compilação de bytecode:
bun build --compile --minify --sourcemap --bytecode ./path/to/my/app.ts --outfile myappUsando 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:
bun build --compile --compile-exec-argv="--smol --user-agent=MyBot" ./app.ts --outfile myapp// 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.
# 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 myappVocê também pode configurar isso via API JavaScript:
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.16Você 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:
echo "console.log(\"you shouldn't see this\");" > such-bun.js
bun build --compile ./such-bun.js[3ms] bundle 1 modules
[89ms] compile such-bunNormalmente, executar ./such-bun com argumentos executaria o script.
# Executável executa seu próprio entrypoint por padrão
./such-bun installyou shouldn't see thisNo entanto, com a variável de ambiente BUN_BE_BUN=1, age exatamente como o binário bun:
# Com a variável de ambiente, o executável age como a CLI `bun`
BUN_BE_BUN=1 ./such-bun installbun 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.17A 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.
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}`);<!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>console.log("Hello from the client!");body {
background-color: #f0f0f0;
}Para build disto em um único executável:
bun build --compile ./server.ts --outfile myappIsso 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:
./myappBun 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:
bun build --compile ./index.ts ./my-worker.ts --outfile myappEntão, referencie o worker no seu código:
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.
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.
cd /home/me/Desktop
./helloIncorporar 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.
// 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:
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".
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.
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:
bun build --compile ./index.ts ./public/**/*.pngEntão, você pode referenciar os arquivos no seu código:
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:
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.
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:
bun build --compile --asset-naming="[name].[ext]" ./index.tsMinificaçã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.icopara personalizar o ícone do arquivo executável.--windows-hide-consolepara 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.
codesign --deep --force -vvvv --sign "XXXXXXXXXX" ./myappRecomendamos incluir um arquivo entitlements.plist com permissões JIT.
<?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.
codesign --deep --force -vvvv --sign "XXXXXXXXXX" --entitlements entitlements.plist ./myappApós codesignar, verifique o executável:
codesign -vvv --verify ./myapp
./myapp: valid on disk
./myapp: satisfies its Designated RequirementCode 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.
bun build --compile --splitting ./src/entry.ts --outdir ./buildconsole.log("Entrypoint loaded");
const lazy = await import("./lazy.ts");
lazy.hello();export function hello() {
console.log("Lazy module loaded");
}./build/entryEntrypoint loaded
Lazy module loadedArgumentos 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— useoutfileem vez disso (exceto ao usar com--splitting).--public-path--target=nodeou--target=browser--no-bundle- sempre empacotamos tudo no executável.