Il bundler di Bun implementa un flag --compile per generare un binario standalone da un file TypeScript o JavaScript.
bun build ./cli.ts --compile --outfile mycliconsole.log("Hello world!");Questo crea un bundle di cli.ts in un eseguibile che può essere eseguito direttamente:
./mycliHello world!Tutti i file e pacchetti importati sono bundled nell'eseguibile, insieme a una copia del runtime Bun. Tutte le API built-in di Bun e Node.js sono supportate.
Cross-compilazione per altre piattaforme
Il flag --target ti permette di compilare il tuo eseguibile standalone per un sistema operativo, architettura o versione di Bun diversa dalla macchina su cui stai eseguendo bun build.
Per build per Linux x64 (la maggior parte dei server):
bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp
# Per supportare CPU precedenti al 2013, usa la versione baseline (nehalem)
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp
# Per supportare esplicitamente solo CPU dal 2013 in poi, usa la versione modern (haswell)
# modern è più veloce, ma baseline è più compatibile.
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myappPer build per Linux ARM64 (es. Graviton o Raspberry Pi):
# Nota: l'architettura predefinita è x64 se nessuna architettura è specificata.
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myappPer build per Windows x64:
bun build --compile --target=bun-windows-x64 ./path/to/my/app.ts --outfile myapp
# Per supportare CPU precedenti al 2013, usa la versione baseline (nehalem)
bun build --compile --target=bun-windows-x64-baseline ./path/to/my/app.ts --outfile myapp
# Per supportare esplicitamente solo CPU dal 2013 in poi, usa la versione modern (haswell)
bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfile myapp
# nota: se nessuna estensione .exe è fornita, Bun la aggiungerà automaticamente per eseguibili WindowsPer build per macOS arm64:
bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myappPer build per macOS x64:
bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myappTarget supportati
L'ordine del flag --target non importa, purché siano delimitati da -.
| --target | Sistema Operativo | Architettura | Modern | 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 |
Costanti a build-time
Usa il flag --define per iniettare costanti a build-time nel tuo eseguibile, come numeri di versione, timestamp di build o valori di configurazione:
bun build --compile --define BUILD_VERSION='"1.2.3"' --define BUILD_TIME='"2024-01-15T10:30:00Z"' src/cli.ts --outfile mycliQueste costanti sono incorporate direttamente nel tuo binario compilato a build-time, fornendo zero overhead runtime e abilitando ottimizzazioni di dead code elimination.
NOTE
Per esempi completi e pattern avanzati, vedi la [guida Costanti a build-time](/it/guides/runtime/build-time-constants).Deployment in produzione
Gli eseguibili compilati riducono l'uso di memoria e migliorano il tempo di avvio di Bun.
Normalmente, Bun legge e transpila file JavaScript e TypeScript su import e require. Questo è parte di ciò che rende molto di Bun "just work", ma non è gratuito. Costa tempo e memoria leggere file da disco, risolvere percorsi file, parsare, transpilare e stampare codice sorgente.
Con eseguibili compilati, puoi spostare quel costo da runtime a build-time.
Quando deployi in produzione, raccomandiamo quanto segue:
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myappCompilazione bytecode
Per migliorare il tempo di avvio, abilita la compilazione bytecode:
bun build --compile --minify --sourcemap --bytecode ./path/to/my/app.ts --outfile myappUsando la compilazione bytecode, tsc avvia 2x più veloce:
La compilazione bytecode sposta l'overhead di parsing per file di input grandi da runtime a bundle time. La tua app avvia più veloce, in cambio di rendere il comando bun build un po' più lento. Non offusca il codice sorgente.
Cosa fanno questi flag?
L'argomento --minify ottimizza la dimensione del codice di output transpilato. Se hai un'applicazione grande, questo può risparmiare megabyte di spazio. Per applicazioni più piccole, potrebbe comunque migliorare il tempo di avvio un po'.
L'argomento --sourcemap incorpora una sourcemap compressa con zstd, così che errori e stacktrace puntano alle loro posizioni originali invece della posizione transpilata. Bun decomprimerà e risolverà automaticamente la sourcemap quando si verifica un errore.
L'argomento --bytecode abilita la compilazione bytecode. Ogni volta che esegui codice JavaScript in Bun, JavaScriptCore (il motore) compilerà il tuo codice sorgente in bytecode. Possiamo spostare questo lavoro di parsing da runtime a bundle time, risparmiandoti tempo di avvio.
Incorporare argomenti runtime
--compile-exec-argv="args" - Incorpora argomenti runtime disponibili tramite process.execArgv:
bun build --compile --compile-exec-argv="--smol --user-agent=MyBot" ./app.ts --outfile myapp// Nell'app compilata
console.log(process.execArgv); // ["--smol", "--user-agent=MyBot"]Disabilitare caricamento automatico config
Di default, gli eseguibili standalone cercano file .env e bunfig.toml nella directory dove l'eseguibile è eseguito. Puoi disabilitare questo comportamento a build time per esecuzione deterministica indipendentemente dalla directory di lavoro dell'utente.
# Disabilita caricamento .env
bun build --compile --no-compile-autoload-dotenv ./app.ts --outfile myapp
# Disabilita caricamento bunfig.toml
bun build --compile --no-compile-autoload-bunfig ./app.ts --outfile myapp
# Disabilita entrambi
bun build --compile --no-compile-autoload-dotenv --no-compile-autoload-bunfig ./app.ts --outfile myappPuoi anche configurare questo tramite l'API JavaScript:
await Bun.build({
entrypoints: ["./app.ts"],
compile: {
autoloadDotenv: false, // Disabilita caricamento .env
autoloadBunfig: false, // Disabilita caricamento bunfig.toml
},
});Agire come la CLI Bun
NOTE
Nuovo in Bun v1.2.16Puoi eseguire un eseguibile standalone come se fosse la CLI bun stessa impostando la variabile d'ambiente BUN_BE_BUN=1. Quando questa variabile è impostata, l'eseguibile ignorerà il suo entrypoint bundled e invece esporrà tutte le funzionalità della CLI di Bun.
Per esempio, considera un eseguibile compilato da uno script semplice:
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, eseguire ./such-bun con argomenti eseguirebbe lo script.
# L'eseguibile esegue il proprio entrypoint di default
./such-bun installyou shouldn't see thisTuttavia, con la variabile d'ambiente BUN_BE_BUN=1, agisce proprio come il binario bun:
# Con la variabile d'ambiente, l'eseguibile agisce come la 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]Questo è utile per costruire strumenti CLI su Bun che potrebbero aver bisogno di installare pacchetti, bundlare dipendenze, eseguire file diversi o locali e altro senza dover scaricare un binario separato o installare bun.
Eseguibili full-stack
NOTE
Nuovo in Bun v1.2.17Il flag --compile di Bun può creare eseguibili standalone che contengono sia codice server che client, rendendolo ideale per applicazioni full-stack. Quando importi un file HTML nel tuo codice server, Bun bundla automaticamente tutte le risorse frontend (JavaScript, CSS, ecc.) e le incorpora nell'eseguibile. Quando Bun vede l'import HTML sul server, avvia un processo di build frontend per bundlare JavaScript, CSS e altre risorse.
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 in esecuzione su 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;
}Per buildare questo in un singolo eseguibile:
bun build --compile ./server.ts --outfile myappQuesto crea un binario self-contained che include:
- Il tuo codice server
- Il runtime Bun
- Tutte le risorse frontend (HTML, CSS, JavaScript)
- Qualsiasi pacchetto npm usato dal tuo server
Il risultato è un singolo file che può essere deployato ovunque senza bisogno di Node.js, Bun o dipendenze installate. Basta eseguire:
./myappBun gestisce automaticamente il serving delle risorse frontend con i corretti header MIME type e cache. L'import HTML è rimpiazzato con un oggetto manifest che Bun.serve usa per servire efficientemente risorse pre-bundlate.
Per maggiori dettagli sulla costruzione di applicazioni full-stack con Bun, vedi la guida full-stack.
Worker
Per usare worker in un eseguibile standalone, aggiungi l'entrypoint del worker agli argomenti CLI:
bun build --compile ./index.ts ./my-worker.ts --outfile myappPoi, referenzia il worker nel tuo codice:
console.log("Hello from Bun!");
// Ognuno di questi funzionerà:
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 aggiungi più entrypoint a un eseguibile standalone, saranno bundlati separatamente nell'eseguibile.
In futuro, potremmo rilevare automaticamente usi di percorsi staticamente noti in new Worker(path) e poi bundlarli nell'eseguibile, ma per ora, dovrai aggiungerlo manualmente al comando shell come nell'esempio sopra.
Se usi un percorso relativo a un file non incluso nell'eseguibile standalone, proverà a caricare quel percorso da disco relativo alla directory di lavoro corrente del processo (e poi darà errore se non esiste).
SQLite
Puoi usare import bun:sqlite con bun build --compile.
Di default, il database è risolto relativo alla directory di lavoro corrente del processo.
import db from "./my.db" with { type: "sqlite" };
console.log(db.query("select * from users LIMIT 1").get());Questo significa che se l'eseguibile si trova a /usr/bin/hello, il terminale dell'utente si trova a /home/me/Desktop, cercherà /home/me/Desktop/my.db.
cd /home/me/Desktop
./helloIncorporare risorse e file
Gli eseguibili standalone supportano l'incorporamento di file.
Per incorporare file in un eseguibile con bun build --compile, importa il file nel tuo codice.
// questo diventa un percorso file interno
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";
export default {
fetch(req) {
// I file incorporati possono essere streammati da oggetti Response
return new Response(file(icon));
},
};I file incorporati possono essere letti usando le funzioni di Bun.file o la funzione fs.readFile di Node.js (in "node:fs").
Per esempio, per leggere i contenuti del file incorporato:
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)Incorporare database SQLite
Se la tua applicazione vuole incorporare un database SQLite, imposta type: "sqlite" nell'attributo di import e l'attributo embed a "true".
import myEmbeddedDb from "./my.db" with { type: "sqlite", embed: "true" };
console.log(myEmbeddedDb.query("select * from users LIMIT 1").get());Questo database è read-write, ma tutte le modifiche sono perse quando l'eseguibile esce (poiché è memorizzato in memoria).
Incorporare Addon N-API
Puoi incorporare file .node negli eseguibili.
const addon = require("./addon.node");
console.log(addon.hello());Sfortunatamente, se stai usando @mapbox/node-pre-gyp o altri strumenti simili, dovrai assicurarti che il file .node sia richiesto direttamente o non si bundlerà correttamente.
Incorporare directory
Per incorporare una directory con bun build --compile, usa un glob shell nel tuo comando bun build:
bun build --compile ./index.ts ./public/**/*.pngPoi, puoi referenziare i file nel tuo codice:
import icon from "./public/assets/icon.png" with { type: "file" };
import { file } from "bun";
export default {
fetch(req) {
// I file incorporati possono essere streammati da oggetti Response
return new Response(file(icon));
},
};Questo è onestamente un workaround, e ci aspettiamo di migliorare questo in futuro con un'API più diretta.
Elencare file incorporati
Per ottenere una lista di tutti i file incorporati, usa Bun.embeddedFiles:
import "./icon.png" with { type: "file" };
import { embeddedFiles } from "bun";
console.log(embeddedFiles[0].name); // `icon-${hash}.png`Bun.embeddedFiles restituisce un array di oggetti Blob che puoi usare per ottenere dimensione, contenuti e altre proprietà dei file.
embeddedFiles: Blob[]La lista dei file incorporati esclude codice sorgente bundled come file .ts e .js.
Hash contenuto
Di default, i file incorporati hanno un hash di contenuto aggiunto al loro nome. Questo è utile per situazioni dove vuoi servire il file da un URL o CDN e avere meno problemi di invalidazione cache. Ma a volte, questo è inaspettato e potresti volere il nome originale invece:
Per disabilitare l'hash di contenuto, passa --asset-naming a bun build --compile così:
bun build --compile --asset-naming="[name].[ext]" ./index.tsMinificazione
Per ridurre un po' la dimensione dell'eseguibile, passa --minify a bun build --compile. Questo usa il minifier di Bun per ridurre la dimensione del codice. Complessivamente però, il binario di Bun è ancora troppo grande e dobbiamo renderlo più piccolo.
Flag specifici per Windows
Quando compili un eseguibile standalone su Windows, ci sono due opzioni specifiche per piattaforma che possono essere usate per personalizzare i metadati sul file .exe generato:
--windows-icon=path/to/icon.icoper personalizzare l'icona del file eseguibile.--windows-hide-consoleper disabilitare il terminale di sfondo, che può essere usato per applicazioni che non hanno bisogno di un TTY.
Code signing su macOS
Per codesignare un eseguibile standalone su macOS (che risolve gli avvisi Gatekeeper), usa il comando codesign.
codesign --deep --force -vvvv --sign "XXXXXXXXXX" ./myappRaccomandiamo di includere un file entitlements.plist con permessi 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>Per codesignare con supporto JIT, passa il flag --entitlements a codesign.
codesign --deep --force -vvvv --sign "XXXXXXXXXX" --entitlements entitlements.plist ./myappDopo codesigning, verifica l'eseguibile:
codesign -vvv --verify ./myapp
./myapp: valid on disk
./myapp: satisfies its Designated RequirementCode splitting
Gli eseguibili standalone supportano code splitting. Usa --compile con --splitting per creare un eseguibile che carica chunk code-split a 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 loadedArgomenti CLI non supportati
Attualmente, il flag --compile può accettare solo un singolo entrypoint alla volta e non supporta i seguenti flag:
--outdir— usaoutfileinvece (eccetto quando usato con--splitting).--public-path--target=nodeo--target=browser--no-bundle- bundliamo sempre tutto nell'eseguibile.