Skip to content

import Build from "/snippets/cli/build.mdx";

Le bundler natif rapide de Bun peut être utilisé via la commande CLI bun build ou l'API JavaScript Bun.build().

En bref

  • API JS : await Bun.build({ entrypoints, outdir })
  • CLI : bun build <entry> --outdir ./out
  • Watch : --watch pour les reconstructions incrémentielles
  • Cibles : --target browser|bun|node
  • Formats : --format esm|cjs|iife (expérimental pour cjs/iife)
ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './build',
});
bash
bun build ./index.tsx --outdir ./build

C'est rapide. Les chiffres ci-dessous représentent les performances sur le benchmark three.js d'esbuild.

Pourquoi bundler ?

Le bundler est un élément clé d'infrastructure dans l'écosystème JavaScript. Voici un bref aperçu de pourquoi le bundling est si important :

  • Réduction des requêtes HTTP. Un seul package dans node_modules peut comporter des centaines de fichiers, et les grandes applications peuvent avoir des dizaines de telles dépendances. Charger chacun de ces fichiers avec une requête HTTP séparée devient très rapidement intenable, donc les bundlers sont utilisés pour convertir le code source de notre application en un nombre réduit de "bundles" autonomes qui peuvent être chargés avec une seule requête.
  • Transformations de code. Les applications modernes sont couramment construites avec des langages ou outils comme TypeScript, JSX et les modules CSS, qui doivent tous être convertis en JavaScript et CSS purs avant de pouvoir être consommés par un navigateur. Le bundler est l'endroit naturel pour configurer ces transformations.
  • Fonctionnalités de framework. Les frameworks s'appuient sur des plugins de bundler et des transformations de code pour implémenter des modèles courants comme le routage basé sur le système de fichiers, la co-localisation du code client-serveur (pensez getServerSideProps ou les loaders Remix), et les composants serveur.
  • Applications full-stack. Le bundler de Bun peut gérer à la fois le code serveur et client en une seule commande, permettant des constructions de production optimisées et des exécutables en un seul fichier. Avec les importations HTML au moment de la construction, vous pouvez bundler toute votre application — assets frontend et serveur backend — en une seule unité déployable.

Passons à l'API du bundler.

NOTE

Le bundler Bun n'est pas destiné à remplacer `tsc` pour la vérification de type ou la génération de déclarations de type.

Exemple de base

Construisons notre premier bundle. Vous avez les deux fichiers suivants, qui implémentent une application React simple rendue côté client.

tsx
import * as ReactDOM from "react-dom/client";
import { Component } from "./Component";

const root = ReactDOM.createRoot(document.getElementById("root")!);
root.render(<Component message="Sup!" />);
tsx
export function Component(props: { message: string }) {
  return <h1>{props.message}</h1>;
}

Ici, index.tsx est le "point d'entrée" de notre application. Généralement, il s'agira d'un script qui effectue un effet de bord, comme démarrer un serveur ou — dans ce cas — initialiser une racine React. Parce que nous utilisons TypeScript & JSX, nous devons bundler notre code avant qu'il puisse être envoyé au navigateur.

Pour créer notre bundle :

ts
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
});
bash
bun build ./index.tsx --outdir ./out

Pour chaque fichier spécifié dans entrypoints, Bun générera un nouveau bundle. Ce bundle sera écrit sur le disque dans le répertoire ./out (tel que résolu depuis le répertoire de travail actuel). Après avoir exécuté la construction, le système de fichiers ressemble à ceci :

text
.
├── index.tsx
├── Component.tsx
└── out
    └── index.js

Le contenu de out/index.js ressemblera à quelque chose comme ceci :

js
// out/index.js
// ...
// ~20k lignes de code
// y compris le contenu de `react-dom/client` et toutes ses dépendances
// c'est ici que les fonctions $jsxDEV et $createRoot sont définies

// 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,
  ),
);

Mode watch

Comme le runtime et l'exécuteur de tests, le bundler prend en charge nativement le mode watch.

bash
bun build ./index.tsx --outdir ./out --watch

Types de contenu

Comme le runtime Bun, le bundler prend en charge un ensemble de types de fichiers nativement. Le tableau suivant détaille l'ensemble des "loaders" standard du bundler. Consultez Bundler > Types de fichiers pour la documentation complète.

ExtensionsDétails
.js .jsx .cjs .mjs .mts .cts .ts .tsxUtilise le transpileur intégré de Bun pour analyser le fichier et transpiler la syntaxe TypeScript/JSX en JavaScript vanilla. Le bundler exécute un ensemble de transformations par défaut incluant l'élimination du code mort et le tree shaking. Pour le moment, Bun n'essaie pas de rétrograder la syntaxe ; si vous utilisez une syntaxe ECMAScript récente, cela se reflétera dans le code bundle.
.jsonLes fichiers JSON sont analysés et intégrés dans le bundle en tant qu'objet JavaScript.

js<br/>import pkg from "./package.json";<br/>pkg.name; // => "my-package"<br/>
.jsoncJSON avec commentaires. Les fichiers sont analysés et intégrés dans le bundle en tant qu'objet JavaScript.

js<br/>import config from "./config.jsonc";<br/>config.name; // => "my-config"<br/>
.tomlLes fichiers TOML sont analysés et intégrés dans le bundle en tant qu'objet JavaScript.

js<br/>import config from "./bunfig.toml";<br/>config.logLevel; // => "debug"<br/>
.yaml .ymlLes fichiers YAML sont analysés et intégrés dans le bundle en tant qu'objet JavaScript.

js<br/>import config from "./config.yaml";<br/>config.name; // => "my-app"<br/>
.txtLe contenu du fichier texte est lu et intégré dans le bundle en tant que chaîne.

js<br/>import contents from "./file.txt";<br/>console.log(contents); // => "Hello, world!"<br/>
.htmlLes fichiers HTML sont traités et tous les assets référencés (scripts, feuilles de style, images) sont bundle.
.cssLes fichiers CSS sont bundle ensemble dans un seul fichier .css dans le répertoire de sortie.
.node .wasmCes fichiers sont pris en charge par le runtime Bun, mais pendant le bundling, ils sont traités comme des assets.

Assets

Si le bundler rencontre une importation avec une extension non reconnue, il traite le fichier importé comme un fichier externe. Le fichier référencé est copié tel quel dans outdir, et l'importation est résolue comme un chemin vers le fichier.

ts
// point d'entrée du bundle
import logo from "./logo.svg";
console.log(logo);
ts
// sortie bundle
var logo = "./logo-a7305bdef.svg";
console.log(logo);

Le comportement exact du chargeur de fichiers est également impacté par naming et publicPath.

Plugins

Le comportement décrit dans ce tableau peut être remplacé ou étendu avec des plugins. Consultez la page Bundler > Loaders pour la documentation complète.

API

entrypoints

Un tableau de chemins correspondant aux points d'entrée de notre application. Un bundle sera généré pour chaque point d'entrée.

ts
const result = await Bun.build({
  entrypoints: ["./index.ts"]
});
bash
bun build ./index.ts

outdir

Le répertoire où les fichiers de sortie seront écrits.

ts
const result = await Bun.build({
  entrypoints: ['./index.ts'],
  outdir: './out'
});
// => { success: boolean, outputs: `BuildArtifact[]`, logs: `BuildMessage[]` }
bash
bun build ./index.ts --outdir ./out

Si outdir n'est pas passé à l'API JavaScript, le code bundle ne sera pas écrit sur le disque. Les fichiers bundle sont retournés dans un tableau d'objets BuildArtifact. Ces objets sont des Blobs avec des propriétés supplémentaires ; consultez Sorties pour la documentation complète.

ts
const result = await Bun.build({
  entrypoints: ["./index.ts"],
});

for (const res of result.outputs) {
  // Peut être consommé comme des blobs
  await res.text();

  // Bun définira les en-têtes Content-Type et Etag
  new Response(res);

  // Peut être écrit manuellement, mais vous devriez utiliser `outdir` dans ce cas.
  Bun.write(path.join("out", res.path), res);
}

Lorsque outdir est défini, la propriété path sur un BuildArtifact sera le chemin absolu vers l'endroit où il a été écrit.

target

L'environnement d'exécution prévu pour le bundle.

ts
await Bun.build({
  entrypoints: ['./index.ts'],
  outdir: './out',
  target: 'browser', // par défaut
})
bash
bun build ./index.ts --outdir ./out --target browser

Selon la cible, Bun appliquera différentes règles de résolution de modules et optimisations.

Par défaut. Pour générer des bundles destinés à être exécutés par un navigateur. Priorise la condition d'export "browser" lors de la résolution des importations. L'importation de modules intégrés, comme node:events ou node:path fonctionnera, mais appeler certaines fonctions, comme fs.readFile ne fonctionnera pas.

Pour générer des bundles destinés à être exécutés par le runtime Bun. Dans de nombreux cas, il n'est pas nécessaire de bundler le code côté serveur ; vous pouvez exécuter directement le code source sans modification. Cependant, bundler votre code serveur peut réduire les temps de démarrage et améliorer les performances d'exécution. C'est la cible à utiliser pour construire des applications full-stack avec des importations HTML au moment de la construction, où le code serveur et client sont bundle ensemble.

Tous les bundles générés avec target: "bun" sont marqués avec un pragma spécial // @bun, qui indique au runtime Bun qu'il n'est pas nécessaire de re-transpiler le fichier avant l'exécution.

Si un point d'entrée contient un shebang Bun (#!/usr/bin/env bun), le bundler utilisera par défaut target: "bun" au lieu de "browser".

Lors de l'utilisation de target: "bun" et format: "cjs" ensemble, le pragma // @bun @bun-cjs est ajouté et la fonction wrapper CommonJS n'est pas compatible avec Node.js.

Pour générer des bundles destinés à être exécutés par Node.js. Priorise la condition d'export "node" lors de la résolution des importations et produit .mjs. À l'avenir, cela polyfillera automatiquement le global Bun et d'autres modules intégrés bun:*, bien que cela ne soit pas encore implémenté.

format

Spécifie le format de module à utiliser dans les bundles générés.

Bun utilise par défaut "esm" et fournit une prise en charge expérimentale pour "cjs" et "iife".

format: "esm" - Module ES

C'est le format par défaut, qui prend en charge la syntaxe des modules ES incluant l'await de haut niveau, import.meta, et plus encore.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  format: "esm",
})
bash
bun build ./index.tsx --outdir ./out --format esm

Pour utiliser la syntaxe des modules ES dans les navigateurs, définissez format sur "esm" et assurez-vous que votre balise <script type="module"> a type="module" défini.

format: "cjs" - CommonJS

Pour construire un module CommonJS, définissez format sur "cjs". Lors du choix de "cjs", la cible par défaut passe de "browser" (esm) à "node" (cjs). Les modules CommonJS transpilés avec format: "cjs", target: "node" peuvent être exécutés à la fois dans Bun et Node.js (en supposant que les API utilisées sont prises en charge par les deux).

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  format: "cjs",
})
bash
bun build ./index.tsx --outdir ./out --format cjs

format: "iife" - IIFE

TODO : documenter IIFE une fois que nous prenons en charge globalNames.

jsx

Configurez le comportement de transformation JSX. Permet un contrôle précis de la façon dont JSX est compilé.

Exemple de runtime classique (utilise factory et fragment) :

ts
await Bun.build({
  entrypoints: ["./app.tsx"],
  outdir: "./out",
  jsx: {
    factory: "h",
    fragment: "Fragment",
    runtime: "classic",
  },
});
bash
# La configuration JSX est gérée via bunfig.toml ou tsconfig.json
bun build ./app.tsx --outdir ./out

Exemple de runtime automatique (utilise importSource) :

ts
await Bun.build({
  entrypoints: ["./app.tsx"],
  outdir: "./out",
  jsx: {
    importSource: "preact",
    runtime: "automatic",
  },
});
bash
# La configuration JSX est gérée via bunfig.toml ou tsconfig.json
bun build ./app.tsx --outdir ./out

splitting

Permet d'activer le code splitting.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  splitting: false, // par défaut
})
bash
bun build ./index.tsx --outdir ./out --splitting

Lorsque true, le bundler activera le code splitting. Lorsque plusieurs points d'entrée importent le même fichier, module ou ensemble de fichiers/modules, il est souvent utile de diviser le code partagé dans un bundle séparé. Ce bundle partagé est connu sous le nom de chunk. Considérez les fichiers suivants :

ts
import { shared } from "./shared.ts";
ts
import { shared } from "./shared.ts";
ts
export const shared = "shared";

Pour bundler entry-a.ts et entry-b.ts avec le code-splitting activé :

ts
await Bun.build({
  entrypoints: ['./entry-a.ts', './entry-b.ts'],
  outdir: './out',
  splitting: true,
})
bash
bun build ./entry-a.ts ./entry-b.ts --outdir ./out --splitting

L'exécution de cette construction produira les fichiers suivants :

text
.
├── entry-a.tsx
├── entry-b.tsx
├── shared.tsx
└── out
    ├── entry-a.js
    ├── entry-b.js
    └── chunk-2fce6291bf86559d.js

Le fichier généré chunk-2fce6291bf86559d.js contient le code partagé. Pour éviter les collisions, le nom du fichier inclut automatiquement un hachage de contenu par défaut. Cela peut être personnalisé avec naming.

plugins

Une liste de plugins à utiliser pendant le bundling.

ts
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
  plugins: [
    /* ... */
  ],
});

Bun implémente un système de plugins universel pour le runtime et le bundler de Bun. Consultez la documentation des plugins pour la documentation complète.

env

Contrôle la façon dont les variables d'environnement sont gérées pendant le bundling. En interne, cela utilise define pour injecter des variables d'environnement dans le bundle, mais facilite la spécification des variables d'environnement à injecter.

env: "inline"

Injecte des variables d'environnement dans la sortie bundle en convertissant les références process.env.FOO en littéraux de chaîne contenant les valeurs réelles des variables d'environnement.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  env: "inline",
})
bash
bun build ./index.tsx --outdir ./out --env inline

Pour l'entrée ci-dessous :

js
// input.js
console.log(process.env.FOO);
console.log(process.env.BAZ);

Le bundle généré contiendra le code suivant :

js
// output.js
console.log("bar");
console.log("123");

env: "PUBLIC_*" (préfixe)

Inline les variables d'environnement correspondant au préfixe donné (la partie avant le caractère *), remplaçant process.env.FOO par la valeur réelle de la variable d'environnement. Cela est utile pour inline sélectivement des variables d'environnement pour des choses comme des URL publiques ou des tokens côté client, sans s'inquiéter d'injecter des identifiants privés dans les bundles de sortie.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  
  // Inline toutes les variables d'environnement qui commencent par "ACME_PUBLIC_"
  env: "ACME_PUBLIC_*",
})
bash
bun build ./index.tsx --outdir ./out --env ACME_PUBLIC_*

Par exemple, étant donné les variables d'environnement suivantes :

bash
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.com

Et le code source :

tsx
console.log(process.env.FOO);
console.log(process.env.ACME_PUBLIC_URL);
console.log(process.env.BAZ);

Le bundle généré contiendra le code suivant :

js
console.log(process.env.FOO);
console.log("https://acme.com");
console.log(process.env.BAZ);

env: "disable"

Désactive complètement l'injection de variables d'environnement.

sourcemap

Spécifie le type de sourcemap à générer.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  sourcemap: 'linked', // par défaut 'none'
})
bash
bun build ./index.tsx --outdir ./out --sourcemap linked
ValeurDescription
"none"Par défaut. Aucune sourcemap n'est générée.
"linked"Un fichier *.js.map séparé est créé à côté de chaque bundle *.js en utilisant un commentaire //# sourceMappingURL pour lier les deux. Nécessite que --outdir soit défini. L'URL de base peut être personnalisée avec --public-path.

js<br/>// <code bundle ici><br/><br/>//# sourceMappingURL=bundle.js.map<br/>
"external"Un fichier *.js.map séparé est créé à côté de chaque bundle *.js sans insérer de commentaire //# sourceMappingURL.

Les bundles générés contiennent un identifiant de débogage qui peut être utilisé pour associer un bundle à sa sourcemap correspondante. Ce debugId est ajouté en commentaire au bas du fichier.

js<br/>// <code de bundle généré><br/><br/>//# debugId=<DEBUG ID><br/>
"inline"Une sourcemap est générée et ajoutée à la fin du bundle généré en tant que charge utile base64.

js<br/>// <code bundle ici><br/><br/>//# sourceMappingURL=data:application/json;base64,<sourcemap encodée ici><br/>

La sourcemap *.js.map associée sera un fichier JSON contenant une propriété debugId équivalente.

minify

Permet d'activer la minification. Par défaut false.

NOTE

Lors du ciblage de `bun`, les identifiants seront minifiés par défaut.

Pour activer toutes les options de minification :

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  minify: true, // par défaut false
})
bash
bun build ./index.tsx --outdir ./out --minify

Pour activer de manière granulaire certaines minifications :

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  minify: {
    whitespace: true,
    identifiers: true,
    syntax: true,
  },
})
bash
bun build ./index.tsx --outdir ./out --minify-whitespace --minify-identifiers --minify-syntax

external

Une liste de chemins d'importation à considérer comme externes. Par défaut [].

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ["lodash", "react"], // par défaut : []
})
bash
bun build ./index.tsx --outdir ./out --external lodash --external react

Une importation externe est une importation qui ne sera pas incluse dans le bundle final. Au lieu de cela, l'instruction d'importation sera laissée telle quelle, pour être résolue au moment de l'exécution.

Par exemple, considérons le fichier de point d'entrée suivant :

tsx
import _ from "lodash";
import { z } from "zod";

const value = z.string().parse("Hello world!");
console.log(_.upperCase(value));

Normalement, bundler index.tsx générerait un bundle contenant tout le code source du package "zod". Si à la place, nous voulons laisser l'instruction d'importation telle quelle, nous pouvons la marquer comme externe :

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ['zod'],
})
bash
bun build ./index.tsx --outdir ./out --external zod

Le bundle généré ressemblera à quelque chose comme ceci :

js
import { z } from "zod";

// ...
// le contenu du package "lodash"
// y compris la fonction `_.upperCase`

var value = z.string().parse("Hello world!");
console.log(_.upperCase(value));

Pour marquer toutes les importations comme externes, utilisez le joker * :

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ['*'],
})
bash
bun build ./index.tsx --outdir ./out --external '*'

packages

Contrôle si les dépendances de package sont incluses dans le bundle ou non. Valeurs possibles : bundle (par défaut), external. Bun traite toute importation dont le chemin ne commence pas par ., .. ou / comme un package.

ts
await Bun.build({
  entrypoints: ['./index.ts'],
  packages: 'external',
})
bash
bun build ./index.ts --packages external

naming

Personnalise les noms de fichiers générés. Par défaut ./[dir]/[name].[ext].

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: "[dir]/[name].[ext]", // par défaut
})
bash
bun build ./index.tsx --outdir ./out --entry-naming "[dir]/[name].[ext]"

Par défaut, les noms des bundles générés sont basés sur le nom du point d'entrée associé.

text
.
├── index.tsx
└── out
    └── index.js

Avec plusieurs points d'entrée, la hiérarchie de fichiers générée reflétera la structure de répertoire des points d'entrée.

text
.
├── index.tsx
└── nested
    └── index.tsx
└── out
    ├── index.js
    └── nested
        └── index.js

Les noms et emplacements des fichiers générés peuvent être personnalisés avec le champ naming. Ce champ accepte une chaîne de modèle utilisée pour générer les noms de fichiers pour tous les bundles correspondant aux points d'entrée, où les jetons suivants sont remplacés par leurs valeurs correspondantes :

  • [name] - Le nom du fichier de point d'entrée, sans l'extension.
  • [ext] - L'extension du bundle généré.
  • [hash] - Un hachage du contenu du bundle.
  • [dir] - Le chemin relatif depuis la racine du projet jusqu'au répertoire parent du fichier source.

Par exemple :

Jeton[name][ext][hash][dir]
./index.tsxindexjsa1b2c3d4"" (chaîne vide)
./nested/entry.tsentryjsc3d4e5f6"nested"

Nous pouvons combiner ces jetons pour créer une chaîne de modèle. Par exemple, pour inclure le hachage dans les noms de bundles générés :

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: 'files/[dir]/[name]-[hash].[ext]',
})
bash
bun build ./index.tsx --outdir ./out --entry-naming 'files/[dir]/[name]-[hash].[ext]'

Cette construction produirait la structure de fichiers suivante :

text
.
├── index.tsx
└── out
    └── files
        └── index-a1b2c3d4.js

Lorsqu'une chaîne est fournie pour le champ naming, elle est utilisée uniquement pour les bundles correspondant aux points d'entrée. Les noms des chunks et des assets copiés ne sont pas affectés. En utilisant l'API JavaScript, des chaînes de modèle séparées peuvent être spécifiées pour chaque type de fichier généré.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: {
    // valeurs par défaut
    entry: '[dir]/[name].[ext]',
    chunk: '[name]-[hash].[ext]',
    asset: '[name]-[hash].[ext]',
  },
})
bash
bun build ./index.tsx --outdir ./out \
  --entry-naming '[dir]/[name].[ext]' \
  --chunk-naming '[name]-[hash].[ext]' \
  --asset-naming '[name]-[hash].[ext]'

root

Le répertoire racine du projet.

ts
await Bun.build({
  entrypoints: ['./pages/a.tsx', './pages/b.tsx'],
  outdir: './out',
  root: '.',
})
bash
bun build ./pages/a.tsx ./pages/b.tsx --outdir ./out --root .

S'il n'est pas spécifié, il est calculé comme étant le premier ancêtre commun de tous les fichiers de point d'entrée. Considérez la structure de fichiers suivante :

text
.
└── pages
  └── index.tsx
  └── settings.tsx

Nous pouvons construire les deux points d'entrée dans le répertoire pages :

js
await Bun.build({
  entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
  outdir: './out',
})
bash
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out

Cela produirait une structure de fichiers comme ceci :

text
.
└── pages
  └── index.tsx
  └── settings.tsx
└── out
  └── index.js
  └── settings.js

Puisque le répertoire pages est le premier ancêtre commun des fichiers de point d'entrée, il est considéré comme la racine du projet. Cela signifie que les bundles générés se trouvent au niveau supérieur du répertoire out ; il n'y a pas de répertoire out/pages.

Ce comportement peut être remplacé en spécifiant l'option root :

js
await Bun.build({
  entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
  outdir: './out',
  root: '.',
})
bash
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out --root .

En spécifiant . comme root, la structure de fichiers générée ressemblera à ceci :

.
└── pages
  └── index.tsx
  └── settings.tsx
└── out
  └── pages
    └── index.js
    └── settings.js

publicPath

Un préfixe à ajouter à tous les chemins d'importation dans le code bundle.

Dans de nombreux cas, les bundles générés ne contiendront aucune instruction d'importation. Après tout, l'objectif du bundling est de combiner tout le code en un seul fichier. Cependant, il y a un certain nombre de cas où les bundles générés contiendront des instructions d'importation.

  • Importations d'assets — Lors de l'importation d'un type de fichier non reconnu comme *.svg, le bundler s'en remet au chargeur de fichiers, qui copie le fichier dans outdir tel quel. L'importation est convertie en une variable
  • Modules externes — Les fichiers et modules peuvent être marqués comme externes, auquel cas ils ne seront pas inclus dans le bundle. Au lieu de cela, l'instruction d'importation sera laissée dans le bundle final.
  • Chunking. Lorsque splitting est activé, le bundler peut générer des fichiers "chunk" séparés qui représentent du code partagé entre plusieurs points d'entrée.

Dans l'un de ces cas, les bundles finaux peuvent contenir des chemins vers d'autres fichiers. Par défaut, ces importations sont relatives. Voici un exemple d'une simple importation d'asset :

ts
import logo from "./logo.svg";
console.log(logo);
ts
var logo = "./logo-a7305bdef.svg";
console.log(logo);

Définir publicPath préfixera tous les chemins de fichiers avec la valeur spécifiée.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  publicPath: 'https://cdn.example.com/', // par défaut est undefined
})
bash
bun build ./index.tsx --outdir ./out --public-path 'https://cdn.example.com/'

Le fichier de sortie ressemblerait maintenant à quelque chose comme ceci.

js
var logo = "https://cdn.example.com/logo-a7305bdef.svg";

define

Une carte d'identifiants globaux à remplacer au moment de la construction. Les clés de cet objet sont des noms d'identifiants et les valeurs sont des chaînes JSON qui seront intégrées.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  define: {
    STRING: JSON.stringify("value"),
    "nested.boolean": "true",
  },
})
bash
bun build ./index.tsx --outdir ./out --define STRING='"value"' --define nested.boolean=true

loader

Une carte d'extensions de fichier vers des noms de loaders intégrés. Cela peut être utilisé pour personnaliser rapidement la façon dont certains fichiers sont chargés.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  loader: {
    ".png": "dataurl",
    ".txt": "file",
  },
})
bash
bun build ./index.tsx --outdir ./out --loader .png:dataurl --loader .txt:file

Un banner à ajouter au bundle final, cela peut être une directive comme use client pour react ou un bloc de commentaires tel qu'une licence pour le code.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  banner: 'use client;'
})
bash
bun build ./index.tsx --outdir ./out --banner 'use client";'

Un footer à ajouter au bundle final, cela peut être quelque chose comme un bloc de commentaires pour une licence ou juste un easter egg amusant.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  footer: '// built with love in SF'
})
bash
bun build ./index.tsx --outdir ./out --footer '// built with love in SF'

drop

Supprime les appels de fonction d'un bundle. Par exemple, --drop=console supprimera tous les appels à console.log. Les arguments des appels seront également supprimés, indépendamment du fait que ces arguments puissent avoir des effets de bord. Supprimer debugger supprimera toutes les instructions debugger.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  drop: ["console", "debugger", "anyIdentifier.or.propertyAccess"],
})
bash
bun build ./index.tsx --outdir ./out --drop console --drop debugger

Sorties

La fonction Bun.build retourne une Promise<BuildOutput>, définie comme :

ts
interface BuildOutput {
  outputs: BuildArtifact[];
  success: boolean;
  logs: Array<object>; // consultez la documentation pour les détails
}

interface BuildArtifact extends Blob {
  kind: "entry-point" | "chunk" | "asset" | "sourcemap";
  path: string;
  loader: Loader;
  hash: string | null;
  sourcemap: BuildArtifact | null;
}

Le tableau outputs contient tous les fichiers qui ont été générés par la construction. Chaque artefact implémente l'interface Blob.

ts
const build = await Bun.build({
  /* */
});

for (const output of build.outputs) {
  await output.arrayBuffer(); // => ArrayBuffer
  await output.bytes(); // => Uint8Array
  await output.text(); // string
}

Chaque artefact contient également les propriétés suivantes :

PropriétéDescription
kindQuel type de sortie de construction est ce fichier. Une construction génère des points d'entrée bundle, des "chunks" de code-split, des sourcemaps, du bytecode et des assets copiés (comme des images).
pathChemin absolu vers le fichier sur le disque
loaderLe loader utilisé pour interpréter le fichier. Consultez Bundler > Loaders pour voir comment Bun mappe les extensions de fichier au loader intégré approprié.
hashLe hachage du contenu du fichier. Toujours défini pour les assets.
sourcemapLe fichier sourcemap correspondant à ce fichier, s'il est généré. Uniquement défini pour les points d'entrée et les chunks.

Semblable à BunFile, les objets BuildArtifact peuvent être passés directement dans new Response().

ts
const build = await Bun.build({
  /* */
});

const artifact = build.outputs[0];

// L'en-tête Content-Type est automatiquement défini
return new Response(artifact);

Le runtime Bun implémente un affichage spécial des objets BuildArtifact pour faciliter le débogage.

ts
// build.ts
const build = await Bun.build({
  /* */
});

const artifact = build.outputs[0];
console.log(artifact);
bash
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

L'option bytecode: boolean peut être utilisée pour générer du bytecode pour tout point d'entrée JavaScript/TypeScript. Cela peut considérablement améliorer les temps de démarrage pour les grandes applications. Uniquement pris en charge pour le format "cjs", prend uniquement en charge "target": "bun" et dépend d'une version correspondante de Bun. Cela ajoute un fichier .jsc correspondant pour chaque point d'entrée.

ts
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
  bytecode: true,
})
bash
bun build ./index.tsx --outdir ./out --bytecode

Exécutables

Bun prend en charge la "compilation" d'un point d'entrée JavaScript/TypeScript en un exécutable autonome. Cet exécutable contient une copie du binaire Bun.

bash
bun build ./cli.tsx --outfile mycli --compile
./mycli

Consultez Bundler > Exécutables pour la documentation complète.

Logs et erreurs

En cas d'échec, Bun.build retourne une promesse rejetée avec une AggregateError. Cela peut être journalisé dans la console pour un affichage joli de la liste d'erreurs, ou lu programmatiquement avec un bloc try/catch.

ts
try {
  const result = await Bun.build({
    entrypoints: ["./index.tsx"],
    outdir: "./out",
  });
} catch (e) {
  // TypeScript n'autorise pas les annotations sur la clause catch
  const error = e as AggregateError;
  console.error("Échec de la construction");

  // Exemple : Utilisation du formateur intégré
  console.error(error);

  // Exemple : Sérialisation de l'échec en chaîne JSON.
  console.error(JSON.stringify(error, null, 2));
}

La plupart du temps, un try/catch explicite n'est pas nécessaire, car Bun affichera proprement les exceptions non attrapées. Il suffit d'utiliser un await de haut niveau sur l'appel Bun.build.

Chaque élément dans error.errors est une instance de BuildMessage ou ResolveMessage (sous-classes de Error), contenant des informations détaillées pour chaque erreur.

ts
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;
}

En cas de succès de la construction, l'objet retourné contient une propriété logs, qui contient les avertissements et messages d'information du bundler.

ts
const result = await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
});

if (result.logs.length > 0) {
  console.warn("La construction a réussi avec des avertissements :");
  for (const message of result.logs) {
    // Bun affichera proprement l'objet message
    console.warn(message);
  }
}

Référence

ts
interface Bun {
  build(options: BuildOptions): Promise<BuildOutput>;
}

interface BuildConfig {
  entrypoints: string[]; // liste de chemins de fichiers
  outdir?: string; // répertoire de sortie
  target?: Target; // par défaut : "browser"
  /**
   * Format de module de sortie. L'await de haut niveau est uniquement pris en charge pour `"esm"`.
   *
   * Peut être :
   * - `"esm"`
   * - `"cjs"` (**expérimental**)
   * - `"iife"` (**expérimental**)
   *
   * @default "esm"
   */
  format?: "esm" | "cjs" | "iife";
  /**
   * Objet de configuration JSX pour contrôler le comportement de transformation 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; // racine du projet
  splitting?: boolean; // par défaut true, activer le 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; // par défaut : "none", true -> "inline"
  /**
   * Conditions d'export package.json `exports` utilisées lors de la résolution des importations
   *
   * Équivalent à `--conditions` dans `bun build` ou `bun run`.
   *
   * https://nodejs.org/api/packages.html#exports
   */
  conditions?: Array<string> | string;

  /**
   * Contrôle la façon dont les variables d'environnement sont gérées pendant le bundling.
   *
   * Peut être l'un des :
   * - `"inline"` : Injecte des variables d'environnement dans la sortie bundle en convertissant `process.env.FOO`
   *   en littéraux de chaîne contenant les valeurs réelles des variables d'environnement
   * - `"disable"` : Désactive complètement l'injection de variables d'environnement
   * - Une chaîne se terminant par `*` : Inline les variables d'environnement correspondant au préfixe donné.
   *   Par exemple, `"MY_PUBLIC_*"` inclura uniquement les variables d'environnement commençant par "MY_PUBLIC_"
   */
  env?: "inline" | "disable" | `${string}*`;
  minify?:
    | boolean
    | {
        whitespace?: boolean;
        syntax?: boolean;
        identifiers?: boolean;
      };
  /**
   * Ignorer les annotations d'élimination de code mort/tree-shaking telles que @__PURE__ et les champs
   * "sideEffects" de package.json. Cela ne devrait être utilisé que comme solution temporaire pour des
   * annotations incorrectes dans les bibliothèques.
   */
  ignoreDCEAnnotations?: boolean;
  /**
   * Forcer l'émission d'annotations @__PURE__ même si minify.whitespace est true.
   */
  emitDCEAnnotations?: boolean;

  /**
   * Générer du bytecode pour la sortie. Cela peut considérablement améliorer les temps de démarrage à froid,
   * mais rendra la sortie finale plus grande et augmentera légèrement l'utilisation de la mémoire.
   *
   * Le bytecode est actuellement uniquement pris en charge pour CommonJS (`format: "cjs"`).
   *
   * Doit être `target: "bun"`
   * @default false
   */
  bytecode?: boolean;
  /**
   * Ajouter un banner au code bundle tel que "use client";
   */
  banner?: string;
  /**
   * Ajouter un footer au code bundle tel qu'un bloc de commentaires comme
   *
   * `// made with bun!`
   */
  footer?: string;

  /**
   * Supprime les appels de fonction aux accès de propriétés correspondants.
   */
  drop?: string[];

  /**
   * - Lorsqu'il est défini sur `true`, la promesse retournée rejette avec une AggregateError lorsqu'une erreur de construction se produit.
   * - Lorsqu'il est défini sur `false`, retourne un {@link BuildOutput} avec `{success: false}`
   *
   * @default true
   */
  throw?: boolean;

  /**
   * Chemin de fichier tsconfig.json personnalisé à utiliser pour la résolution de chemins.
   * Équivalent à `--tsconfig-override` dans la 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;
}

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