Skip to content

Le bundler de Bun implémente une option --compile pour générer un binaire autonome à partir d'un fichier TypeScript ou JavaScript.

bash
bun build ./cli.ts --compile --outfile mycli
ts
console.log("Bonjour le monde !");

Cela bundle cli.ts dans un exécutable qui peut être exécuté directement :

bash
./mycli
txt
Bonjour le monde !

Tous les fichiers et packages importés sont bundle dans l'exécutable, ainsi qu'une copie du runtime Bun. Toutes les API intégrées de Bun et Node.js sont prises en charge.


Cross-compilation vers d'autres plateformes

L'option --target vous permet de compiler votre exécutable autonome pour un système d'exploitation, une architecture ou une version de Bun différente de la machine sur laquelle vous exécutez bun build.

Pour construire pour Linux x64 (la plupart des serveurs) :

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

# Pour prendre en charge les CPU d'avant 2013, utilisez la version baseline (nehalem)
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp

# Pour prendre explicitement en charge uniquement les CPU de 2013 et plus récents, utilisez la version modern (haswell)
# modern est plus rapide, mais baseline est plus compatible.
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp

Pour construire pour Linux ARM64 (par exemple Graviton ou Raspberry Pi) :

bash
# Note : l'architecture par défaut est x64 si aucune architecture n'est spécifiée.
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp

Pour construire pour Windows x64 :

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

# Pour prendre en charge les CPU d'avant 2013, utilisez la version baseline (nehalem)
bun build --compile --target=bun-windows-x64-baseline ./path/to/my/app.ts --outfile myapp

# Pour prendre explicitement en charge uniquement les CPU de 2013 et plus récents, utilisez la version modern (haswell)
bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfile myapp

# note : si aucune extension .exe n'est fournie, Bun l'ajoutera automatiquement pour les exécutables Windows

Pour construire pour macOS arm64 :

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

Pour construire pour macOS x64 :

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

Cibles prises en charge

L'ordre des options --target n'a pas d'importance, tant qu'elles sont délimitées par un -.

--targetSystème d'exploitationArchitectureModernBaselineLibc
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 au moment de la construction

Utilisez l'option --define pour injecter des constantes au moment de la construction dans votre exécutable, telles que des numéros de version, des horodatages de construction ou des valeurs de configuration :

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

Ces constantes sont intégrées directement dans votre binaire compilé au moment de la construction, offrant un surcoût d'exécution nul et permettant des optimisations d'élimination de code mort.

NOTE

Pour des exemples complets et des modèles avancés, consultez le [guide des constantes au moment de la construction](/fr/guides/runtime/build-time-constants).

Déploiement en production

Les exécutables compilés réduisent l'utilisation de la mémoire et améliorent le temps de démarrage de Bun.

Normalement, Bun lit et transpile les fichiers JavaScript et TypeScript lors de import et require. C'est ce qui fait qu'une grande partie de Bun "fonctionne simplement", mais ce n'est pas gratuit. Cela coûte du temps et de la mémoire de lire les fichiers depuis le disque, de résoudre les chemins de fichiers, d'analyser, de transpiler et d'imprimer le code source.

Avec les exécutables compilés, vous pouvez déplacer ce coût du temps d'exécution au temps de construction.

Lors du déploiement en production, nous recommandons ce qui suit :

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

Compilation du bytecode

Pour améliorer le temps de démarrage, activez la compilation du bytecode :

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

En utilisant la compilation du bytecode, tsc démarre 2x plus vite :

La compilation du bytecode déplace la surcharge d'analyse pour les grands fichiers d'entrée du temps d'exécution au temps de bundle. Votre application démarre plus vite, en échange de rendre la commande bun build un peu plus lente. Elle n'obscurcit pas le code source.

Que font ces options ?

L'argument --minify optimise la taille du code transpilé. Si vous avez une grande application, cela peut économiser des mégaoctets d'espace. Pour les applications plus petites, cela peut encore améliorer un peu le temps de démarrage.

L'argument --sourcemap intègre une sourcemap compressée avec zstd, afin que les erreurs et les stacktraces pointent vers leurs emplacements d'origine au lieu de l'emplacement transpilé. Bun décompressera et résoudra automatiquement la sourcemap lorsqu'une erreur se produit.

L'argument --bytecode active la compilation du bytecode. Chaque fois que vous exécutez du code JavaScript dans Bun, JavaScriptCore (le moteur) compile votre code source en bytecode. Nous pouvons déplacer ce travail d'analyse du temps d'exécution au temps de bundle, vous faisant gagner du temps de démarrage.


Intégration des arguments d'exécution

--compile-exec-argv="args" - Intègre des arguments d'exécution disponibles via process.execArgv :

bash
bun build --compile --compile-exec-argv="--smol --user-agent=MyBot" ./app.ts --outfile myapp
ts
// Dans l'application compilée
console.log(process.execArgv); // ["--smol", "--user-agent=MyBot"]

Désactivation du chargement automatique de la configuration

Par défaut, les exécutables autonomes recherchent des fichiers .env et bunfig.toml dans le répertoire où l'exécutable est exécuté. Vous pouvez désactiver ce comportement au moment de la construction pour une exécution déterministe quel que soit le répertoire de travail de l'utilisateur.

bash
# Désactiver le chargement .env
bun build --compile --no-compile-autoload-dotenv ./app.ts --outfile myapp

# Désactiver le chargement bunfig.toml
bun build --compile --no-compile-autoload-bunfig ./app.ts --outfile myapp

# Désactiver les deux
bun build --compile --no-compile-autoload-dotenv --no-compile-autoload-bunfig ./app.ts --outfile myapp

Vous pouvez également configurer cela via l'API JavaScript :

ts
await Bun.build({
  entrypoints: ["./app.ts"],
  compile: {
    autoloadDotenv: false, // Désactiver le chargement .env
    autoloadBunfig: false, // Désactiver le chargement bunfig.toml
  },
});

Agir comme la CLI Bun

NOTE

Nouveau dans Bun v1.2.16

Vous pouvez exécuter un exécutable autonome comme s'il s'agissait de la CLI bun elle-même en définissant la variable d'environnement BUN_BE_BUN=1. Lorsque cette variable est définie, l'exécutable ignorera son point d'entrée bundle et exposera toutes les fonctionnalités de la CLI de Bun.

Par exemple, considérez un exécutable compilé à partir d'un script simple :

bash
echo "console.log(\"vous ne devriez pas voir ceci\");" > such-bun.js
bun build --compile ./such-bun.js
txt
[3ms] bundle 1 modules
[89ms] compile such-bun

Normalement, exécuter ./such-bun avec des arguments exécuterait le script.

bash
# L'exécutable exécute son propre point d'entrée par défaut
./such-bun install
txt
vous ne devriez pas voir ceci

Cependant, avec la variable d'environnement BUN_BE_BUN=1, il agit comme le binaire bun :

bash
# Avec la variable d'environnement, l'exécutable agit comme la 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]

Ceci est utile pour construire des outils CLI sur Bun qui peuvent avoir besoin d'installer des packages, de bundler des dépendances, d'exécuter différents fichiers ou des fichiers locaux et plus encore sans avoir besoin de télécharger un binaire séparé ou d'installer bun.


Exécutables full-stack

NOTE

Nouveau dans Bun v1.2.17

L'option --compile de Bun peut créer des exécutables autonomes qui contiennent à la fois du code serveur et client, ce qui le rend idéal pour les applications full-stack. Lorsque vous importez un fichier HTML dans votre code serveur, Bun bundle automatiquement tous les assets frontend (JavaScript, CSS, etc.) et les intègre dans l'exécutable. Lorsque Bun voit l'importation HTML sur le serveur, il lance un processus de construction frontend pour bundler le JavaScript, le CSS et d'autres assets.

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

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

console.log(`Serveur en cours d'exécution sur http://localhost:${server.port}`);
html
<!DOCTYPE html>
<html>
  <head>
    <title>Mon Application</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <h1>Bonjour le monde</h1>
    <script src="./app.ts"></script>
  </body>
</html>
ts
console.log("Bonjour depuis le client !");
css
body {
  background-color: #f0f0f0;
}

Pour construire cela en un seul exécutable :

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

Cela crée un binaire autonome qui inclut :

  • Votre code serveur
  • Le runtime Bun
  • Tous les assets frontend (HTML, CSS, JavaScript)
  • Tous les packages npm utilisés par votre serveur

Le résultat est un seul fichier qui peut être déployé n'importe où sans avoir besoin de Node.js, Bun ou de dépendances installées. Il suffit d'exécuter :

bash
./myapp

Bun gère automatiquement le service des assets frontend avec les types MIME et les en-têtes de cache appropriés. L'importation HTML est remplacée par un objet manifeste que Bun.serve utilise pour servir efficacement des assets pré-bundle.

Pour plus de détails sur la construction d'applications full-stack avec Bun, consultez le guide full-stack.


Worker

Pour utiliser des workers dans un exécutable autonome, ajoutez le point d'entrée du worker aux arguments CLI :

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

Ensuite, référencez le worker dans votre code :

ts
console.log("Bonjour depuis Bun !");

// N'importe laquelle de ces options fonctionnera :
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);

Lorsque vous ajoutez plusieurs points d'entrée à un exécutable autonome, ils seront bundle séparément dans l'exécutable.

À l'avenir, nous pourrions détecter automatiquement les utilisations de chemins statiquement connus dans new Worker(path) puis les bundler dans l'exécutable, mais pour l'instant, vous devrez les ajouter manuellement à la commande shell comme dans l'exemple ci-dessus.

Si vous utilisez un chemin relatif vers un fichier non inclus dans l'exécutable autonome, il tentera de charger ce chemin depuis le disque par rapport au répertoire de travail actuel du processus (puis affichera une erreur s'il n'existe pas).


SQLite

Vous pouvez utiliser les importations bun:sqlite avec bun build --compile.

Par défaut, la base de données est résolue par rapport au répertoire de travail actuel du processus.

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

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

Cela signifie que si l'exécutable est situé à /usr/bin/hello, le terminal de l'utilisateur est situé à /home/me/Desktop, il recherchera /home/me/Desktop/my.db.

bash
cd /home/me/Desktop
./hello

Intégration de fichiers et d'assets

Les exécutables autonomes prennent en charge l'intégration de fichiers.

Pour intégrer des fichiers dans un exécutable avec bun build --compile, importez le fichier dans votre code.

ts
// ceci devient un chemin de fichier interne
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

export default {
  fetch(req) {
    // Les fichiers intégrés peuvent être streamés depuis des objets Response
    return new Response(file(icon));
  },
};

Les fichiers intégrés peuvent être lus en utilisant les fonctions de Bun.file ou la fonction fs.readFile de Node.js (dans "node:fs").

Par exemple, pour lire le contenu du fichier intégré :

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)

Intégrer des bases de données SQLite

Si votre application souhaite intégrer une base de données SQLite, définissez type: "sqlite" dans l'attribut d'importation et l'attribut embed à "true".

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

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

Cette base de données est en lecture-écriture, mais toutes les modifications sont perdues lorsque l'exécutable se termine (puisqu'elle est stockée en mémoire).

Intégrer des addons N-API

Vous pouvez intégrer des fichiers .node dans des exécutables.

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

console.log(addon.hello());

Malheureusement, si vous utilisez @mapbox/node-pre-gyp ou d'autres outils similaires, vous devrez vous assurer que le fichier .node est directement requis sinon il ne sera pas bundle correctement.

Intégrer des répertoires

Pour intégrer un répertoire avec bun build --compile, utilisez un glob shell dans votre commande bun build :

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

Ensuite, vous pouvez référencer les fichiers dans votre code :

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

export default {
  fetch(req) {
    // Les fichiers intégrés peuvent être streamés depuis des objets Response
    return new Response(file(icon));
  },
};

C'est honnêtement une solution de contournement, et nous espérons améliorer cela à l'avenir avec une API plus directe.

Lister les fichiers intégrés

Pour obtenir une liste de tous les fichiers intégrés, utilisez Bun.embeddedFiles :

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

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

Bun.embeddedFiles retourne un tableau d'objets Blob que vous pouvez utiliser pour obtenir la taille, le contenu et d'autres propriétés des fichiers.

ts
embeddedFiles: Blob[]

La liste des fichiers intégrés exclut le code source bundle comme les fichiers .ts et .js.

Hachage de contenu

Par défaut, les fichiers intégrés ont un hachage de contenu ajouté à leur nom. Ceci est utile pour les situations où vous voulez servir le fichier depuis une URL ou un CDN et avoir moins de problèmes d'invalidation de cache. Mais parfois, cela est inattendu et vous pourriez vouloir le nom d'origine à la place :

Pour désactiver le hachage de contenu, passez --asset-naming à bun build --compile comme ceci :

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

Minification

Pour réduire un peu la taille de l'exécutable, passez --minify à bun build --compile. Cela utilise le minifieur de Bun pour réduire la taille du code. Dans l'ensemble, le binaire de Bun est toujours beaucoup trop grand et nous devons le rendre plus petit.


Options spécifiques à Windows

Lors de la compilation d'un exécutable autonome sur Windows, il y a deux options spécifiques à la plateforme qui peuvent être utilisées pour personnaliser les métadonnées sur le fichier .exe généré :

  • --windows-icon=path/to/icon.ico pour personnaliser l'icône du fichier exécutable.
  • --windows-hide-console pour désactiver le terminal d'arrière-plan, qui peut être utilisé pour les applications qui n'ont pas besoin d'un TTY.

Signature de code sur macOS

Pour signer un exécutable autonome sur macOS (ce qui corrige les avertissements Gatekeeper), utilisez la commande codesign.

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

Nous recommandons d'inclure un fichier entitlements.plist avec les permissions 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>

Pour signer avec le support JIT, passez l'option --entitlements à codesign.

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

Après la signature de code, vérifiez l'exécutable :

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

Code splitting

Les exécutables autonomes prennent en charge le code splitting. Utilisez --compile avec --splitting pour créer un exécutable qui charge des chunks de code split au moment de l'exécution.

bash
bun build --compile --splitting ./src/entry.ts --outdir ./build
ts
console.log("Point d'entrée chargé");
const lazy = await import("./lazy.ts");
lazy.hello();
ts
export function hello() {
  console.log("Module lazy chargé");
}
bash
./build/entry
txt
Point d'entrée chargé
Module lazy chargé

Arguments CLI non pris en charge

Actuellement, l'option --compile ne peut accepter qu'un seul point d'entrée à la fois et ne prend pas en charge les options suivantes :

  • --outdir — utilisez outfile à la place (sauf lors de l'utilisation avec --splitting).
  • --public-path
  • --target=node ou --target=browser
  • --no-bundle - nous bundle toujours tout dans l'exécutable.

Bun édité par www.bunjs.com.cn