import Build from "/ru/snippets/cli/build.mdx";
Быстрый нативный бандлер Bun можно использовать через команду CLI bun build или JavaScript API Bun.build().
Краткий обзор
- JS API:
await Bun.build({ entrypoints, outdir }) - CLI:
bun build <entry> --outdir ./out - Watch:
--watchдля инкрементальных пересборок - Targets:
--target browser|bun|node - Formats:
--format esm|cjs|iife(экспериментально для cjs/iife)
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './build',
});CLI
bun build ./index.tsx --outdir ./buildЭто быстро. Цифры ниже представляют производительность на бенчмарке three.js от esbuild.

Зачем использовать бандлер?
Бандлер является ключевым элементом инфраструктуры в экосистеме JavaScript. Краткий обзор того почему связывание так важно:
- Уменьшение HTTP-запросов. Один пакет в
node_modulesможет состоять из сотен файлов а крупные приложения могут иметь десятки таких зависимостей. Загрузка каждого из этих файлов отдельным HTTP-запросом быстро становится непрактичной поэтому бандлеры используются для преобразования исходного кода нашего приложения в меньшее количество самодостаточных «пакетов» которые можно загрузить одним запросом. - Трансформации кода. Современные приложения часто создаются с использованием TypeScript JSX CSS-модулей и других инструментов все из которых должны быть преобразованы в обычный JavaScript и CSS перед использованием в браузере. Бандлер является естественным местом для настройки этих преобразований.
- Возможности фреймворков. Фреймворки полагаются на плагины бандлера и преобразования кода для реализации общих паттернов таких как маршрутизация на основе файловой системы совместное размещение кода клиента и сервера (например
getServerSidePropsили загрузчики Remix) и серверные компоненты. - Полноценные приложения. Бандлер Bun может обрабатывать как серверный так и клиентский код в одной команде что позволяет создавать оптимизированные продакшн-сборки и однофайловые исполняемые файлы. С импортом HTML во время сборки вы можете связать все свое приложение — фронтенд-активы и бэкенд-сервер — в единый развертываемый модуль.
Перейдем к API бандлера.
NOTE
Бандлер Bun не предназначен для замены `tsc` для проверки типов или генерации объявлений типов.Базовый пример
Создадим наш первый бандл. У вас есть следующие два файла которые реализуют простое клиентское React-приложение.
import * as ReactDOM from "react-dom/client";
import { Component } from "./Component";
const root = ReactDOM.createRoot(document.getElementById("root")!);
root.render(<Component message="Sup!" />);export function Component(props: { message: string }) {
return <h1>{props.message}</h1>;
}Здесь index.tsx является «точкой входа» нашего приложения. Обычно это скрипт который выполняет некоторый побочный эффект например запуск сервера или в данном случае инициализацию React-корня. Поскольку мы используем TypeScript и JSX нам нужно связать наш код перед отправкой в браузер.
Для создания нашего бандла:
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
});bun build ./index.tsx --outdir ./outДля каждого файла указанного в entrypoints Bun создаст новый бандл. Этот бандл будет записан на диск в директории ./out (разрешенной относительно текущей рабочей директории). После запуска сборки файловая система выглядит так:
.
├── index.tsx
├── Component.tsx
└── out
└── index.jsСодержимое out/index.js будет выглядеть примерно так:
// out/index.js
// ...
// ~20k строк кода
// включая содержимое `react-dom/client` и всех его зависимостей
// здесь определены функции $jsxDEV и $createRoot
// 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,
),
);Режим наблюдения
Как и среда выполнения и тестовый раннер бандлер поддерживает режим наблюдения нативно.
bun build ./index.tsx --outdir ./out --watchТипы контента
Как и среда выполнения Bun бандлер поддерживает множество типов файлов из коробки. В следующей таблице представлен набор стандартных «загрузчиков» бандлера. Полную документацию смотрите на странице Bundler > File types.
| Расширения | Детали |
|---|---|
.js .jsx .cjs .mjs .mts .cts .ts .tsx | Использует встроенный транспайлер Bun для парсинга файла и транспиляции синтаксиса TypeScript/JSX в обычный JavaScript. Бандлер выполняет набор преобразований по умолчанию включая устранение мертвого кода и встряхивание дерева. На данный момент Bun не пытается понизить синтаксис; если вы используете недавний синтаксис ECMAScript это отразится в связанном коде. |
.json | JSON-файлы парсятся и встраиваются в бандл как JavaScript-объект.js<br/>import pkg from "./package.json";<br/>pkg.name; // => "my-package"<br/> |
.jsonc | JSON с комментариями. Файлы парсятся и встраиваются в бандл как JavaScript-объект.js<br/>import config from "./config.jsonc";<br/>config.name; // => "my-config"<br/> |
.toml | TOML-файлы парсятся и встраиваются в бандл как JavaScript-объект.js<br/>import config from "./bunfig.toml";<br/>config.logLevel; // => "debug"<br/> |
.yaml .yml | YAML-файлы парсятся и встраиваются в бандл как JavaScript-объект.js<br/>import config from "./config.yaml";<br/>config.name; // => "my-app"<br/> |
.txt | Содержимое текстового файла читается и встраивается в бандл как строка.js<br/>import contents from "./file.txt";<br/>console.log(contents); // => "Hello, world!"<br/> |
.html | HTML-файлы обрабатываются и любые ссылочные активы (скрипты стили изображения) связываются. |
.css | CSS-файлы объединяются в один .css файл в выходной директории. |
.node .wasm | Эти файлы поддерживаются средой выполнения Bun но во время связывания они обрабатываются как активы. |
Активы
Если бандлер встречает импорт с нераспознанным расширением он обрабатывает импортируемый файл как внешний файл. Ссылочный файл копируется как есть в outdir а импорт разрешается как путь к файлу.
// bundle entrypoint
import logo from "./logo.svg";
console.log(logo);// bundled output
var logo = "./logo-a7305bdef.svg";
console.log(logo);Точное поведение файлового загрузчика также зависит от naming и publicPath.
Плагины
Поведение описанное в этой таблице может быть переопределено или расширено с помощью плагинов. Полную документацию смотрите на странице Bundler > Loaders.
API
entrypoints
Массив путей соответствующих точкам входа нашего приложения. Для каждой точки входа будет создан один бандл.
JavaScript
const result = await Bun.build({
entrypoints: ["./index.ts"]
});CLI
bun build ./index.tsoutdir
Директория куда будут записаны выходные файлы.
JavaScript
const result = await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out'
});
// => { success: boolean, outputs: `BuildArtifact[]`, logs: `BuildMessage[]` }CLI
bun build ./index.ts --outdir ./outЕсли outdir не передан в JavaScript API связанный код не будет записан на диск. Связанные файлы возвращаются в массиве объектов BuildArtifact. Эти объекты являются Blob с дополнительными свойствами; полную документацию смотрите в разделе Outputs.
const result = await Bun.build({
entrypoints: ["./index.ts"],
});
for (const res of result.outputs) {
// Можно обрабатывать как blob
await res.text();
// Bun установит заголовки Content-Type и Etag
new Response(res);
// Можно записать вручную но в этом случае следует использовать `outdir`.
Bun.write(path.join("out", res.path), res);
}Когда установлен outdir свойство path на BuildArtifact будет абсолютным путем к месту записи.
target
Предполагаемая среда выполнения для бандла.
JavaScript
await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out',
target: 'browser', // по умолчанию
})CLI
bun build ./index.ts --outdir ./out --target browserВ зависимости от target Bun применяет различные правила разрешения модулей и оптимизации.
По умолчанию. Для генерации бандлов предназначенных для выполнения в браузере. Приоритет отдается условию экспорта "browser" при разрешении импортов. Импорт любых встроенных модулей таких как node:events или node:path будет работать но вызов некоторых функций таких как fs.readFile не будет работать.
Для генерации бандлов предназначенных для запуска средой выполнения Bun. Во многих случаях нет необходимости связывать серверный код; вы можете напрямую выполнять исходный код без изменений. Однако связывание серверного кода может сократить время запуска и улучшить производительность. Это target который следует использовать для создания полнофункциональных приложений с импортом HTML во время сборки где и серверный и клиентский код связываются вместе.
Все бандлы сгенерированные с target: "bun" помечены специальной прагмой // @bun которая указывает среде выполнения Bun что нет необходимости повторно транспилировать файл перед выполнением.
Если любая точка входа содержит shebang Bun (#!/usr/bin/env bun) бандлер по умолчанию будет использовать target: "bun" вместо "browser".
При совместном использовании target: "bun" и format: "cjs" добавляется прагма // @bun @bun-cjs и обертка CommonJS несовместима с Node.js.
Для генерации бандлов предназначенных для запуска Node.js. Приоритет отдается условию экспорта "node" при разрешении импортов и выводится .mjs. В будущем это будет автоматически полифилировать глобальный Bun и другие встроенные модули bun:* хотя это еще не реализовано.
format
Указывает формат модуля для использования в сгенерированных бандлах.
Bun по умолчанию использует "esm" и предоставляет экспериментальную поддержку "cjs" и "iife".
format: "esm" - ES Module
Это формат по умолчанию который поддерживает синтаксис ES Module включая top-level await import.meta и другие.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
format: "esm",
})CLI
bun build ./index.tsx --outdir ./out --format esmДля использования синтаксиса ES Module в браузерах установите format в "esm" и убедитесь что ваш тег <script type="module"> имеет type="module".
format: "cjs" - CommonJS
Для создания модуля CommonJS установите format в "cjs". При выборе "cjs" target по умолчанию меняется с "browser" (esm) на "node" (cjs). Модули CommonJS транспилированные с format: "cjs" target: "node" могут выполняться как в Bun так и в Node.js (при условии что используемые API поддерживаются обоими).
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
format: "cjs",
})CLI
bun build ./index.tsx --outdir ./out --format cjsformat: "iife" - IIFE
TODO: документировать IIFE как только мы поддержим globalNames.
jsx
Настройте поведение трансформации JSX. Позволяет точно контролировать как компилируется JSX.
Пример классического рантайма (использует factory и fragment):
await Bun.build({
entrypoints: ["./app.tsx"],
outdir: "./out",
jsx: {
factory: "h",
fragment: "Fragment",
runtime: "classic",
},
});# Настройка JSX обрабатывается через bunfig.toml или tsconfig.json
bun build ./app.tsx --outdir ./outПример автоматического рантайма (использует importSource):
await Bun.build({
entrypoints: ["./app.tsx"],
outdir: "./out",
jsx: {
importSource: "preact",
runtime: "automatic",
},
});# Настройка JSX обрабатывается через bunfig.toml или tsconfig.json
bun build ./app.tsx --outdir ./outsplitting
Включает ли разделение кода.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
splitting: false, // по умолчанию
})CLI
bun build ./index.tsx --outdir ./out --splittingКогда true бандлер включит разделение кода. Когда несколько точек входа импортируют один и тот же файл модуль или набор файлов/модулей часто полезно разделить общий код в отдельный бандл. Этот общий бандл известен как чанк. Рассмотрим следующие файлы:
import { shared } from "./shared.ts";import { shared } from "./shared.ts";export const shared = "shared";Для связывания entry-a.ts и entry-b.ts с включенным разделением кода:
JavaScript
await Bun.build({
entrypoints: ['./entry-a.ts', './entry-b.ts'],
outdir: './out',
splitting: true,
})CLI
bun build ./entry-a.ts ./entry-b.ts --outdir ./out --splittingВ результате выполнения этой сборки будут созданы следующие файлы:
.
├── entry-a.tsx
├── entry-b.tsx
├── shared.tsx
└── out
├── entry-a.js
├── entry-b.js
└── chunk-2fce6291bf86559d.jsСгенерированный файл chunk-2fce6291bf86559d.js содержит общий код. Чтобы избежать коллизий имя файла автоматически включает хеш содержимого по умолчанию. Это можно настроить с помощью naming.
plugins
Список плагинов для использования во время связывания.
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
plugins: [
/* ... */
],
});Bun реализует универсальную систему плагинов как для среды выполнения так и для бандлера Bun. Полную документацию смотрите в документации по плагинам.
env
Контролирует как обрабатываются переменные окружения во время связывания. Внутри используется define для внедрения переменных окружения в бандл но упрощает указание переменных окружения для внедрения.
env: "inline"
Внедряет переменные окружения в связанный вывод преобразуя ссылки process.env.FOO в строковые литералы содержащие фактические значения переменных окружения.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
env: "inline",
})CLI
bun build ./index.tsx --outdir ./out --env inlineДля ввода ниже:
// input.js
console.log(process.env.FOO);
console.log(process.env.BAZ);Сгенерированный бандл будет содержать следующий код:
// output.js
console.log("bar");
console.log("123");env: "PUBLIC_*" (префикс)
Встраивает переменные окружения соответствующие заданному префиксу (часть перед символом *) заменяя process.env.FOO фактическим значением переменной окружения. Это полезно для выборочного встраивания переменных окружения для таких вещей как публичные URL или клиентские токены не беспокоясь о внедрении приватных учетных данных в выходные бандлы.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
// Встроить все переменные окружения начинающиеся с "ACME_PUBLIC_"
env: "ACME_PUBLIC_*",
})CLI
bun build ./index.tsx --outdir ./out --env ACME_PUBLIC_*Например при следующих переменных окружения:
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.comИ исходном коде:
console.log(process.env.FOO);
console.log(process.env.ACME_PUBLIC_URL);
console.log(process.env.BAZ);Сгенерированный бандл будет содержать следующий код:
console.log(process.env.FOO);
console.log("https://acme.com");
console.log(process.env.BAZ);env: "disable"
Полностью отключает внедрение переменных окружения.
sourcemap
Указывает тип генерируемой карты исходного кода.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
sourcemap: 'linked', // по умолчанию 'none'
})CLI
bun build ./index.tsx --outdir ./out --sourcemap linked| Значение | Описание |
|---|---|
"none" | По умолчанию. Карта исходного кода не генерируется. |
"linked" | Отдельный файл *.js.map создается рядом с каждым бандлом *.js используя комментарий //# sourceMappingURL для связи обоих. Требуется установка --outdir. Базовый URL можно настроить с помощью --public-path.js<br/>// <связанный код здесь><br/><br/>//# sourceMappingURL=bundle.js.map<br/> |
"external" | Отдельный файл *.js.map создается рядом с каждым бандлом *.js без вставки комментария //# sourceMappingURL.Сгенерированные бандлы содержат debug id который можно использовать для ассоциации бандла с соответствующей картой исходного кода. Этот debugId добавляется как комментарий внизу файла.js<br/>// <сгенерированный код бандла><br/><br/>//# debugId=<DEBUG ID><br/> |
"inline" | Карта исходного кода генерируется и добавляется в конец сгенерированного бандла как base64 payload.js<br/>// <связанный код здесь><br/><br/>//# sourceMappingURL=data:application/json;base64,<закодированная карта исходного кода здесь><br/> |
Ассоциированный файл карты исходного кода *.js.map будет JSON-файлом содержащим эквивалентное свойство debugId.
minify
Включает ли минификацию. По умолчанию false.
NOTE
При таргетировании на `bun` идентификаторы будут минифицироваться по умолчанию.Для включения всех опций минификации:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: true, // по умолчанию false
})CLI
```bash
bun build ./index.tsx --outdir ./out --minify
```
Для выборочного включения определенных минификаций:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: {
whitespace: true,
identifiers: true,
syntax: true,
},
})CLI
bun build ./index.tsx --outdir ./out --minify-whitespace --minify-identifiers --minify-syntaxexternal
Список путей импорта которые следует считать внешними. По умолчанию [].
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ["lodash", "react"], // по умолчанию: []
})CLI
bun build ./index.tsx --outdir ./out --external lodash --external reactВнешний импорт — это тот который не будет включен в итоговый бандл. Вместо этого оператор импорта остается как есть для разрешения во время выполнения.
Например рассмотрим следующий файл точки входа:
import _ from "lodash";
import { z } from "zod";
const value = z.string().parse("Hello world!");
console.log(_.upperCase(value));Обычно связывание index.tsx создаст бандл содержащий весь исходный код пакета "zod". Если вместо этого мы хотим оставить оператор импорта как есть мы можем пометить его как внешний:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['zod'],
})CLI
bun build ./index.tsx --outdir ./out --external zodСгенерированный бандл будет выглядеть примерно так:
import { z } from "zod";
// ...
// содержимое пакета "lodash"
// включая функцию `_.upperCase`
var value = z.string().parse("Hello world!");
console.log(_.upperCase(value));Чтобы пометить все импорты как внешние используйте подстановочный знак *:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['*'],
})CLI
bun build ./index.tsx --outdir ./out --external '*'packages
Контролирует включение ли зависимостей пакетов в бандл или нет. Возможные значения: bundle (по умолчанию) external. Bun обрабатывает любой импорт путь которого не начинается с ., .. или / как пакет.
JavaScript
await Bun.build({
entrypoints: ['./index.ts'],
packages: 'external',
})CLI
bun build ./index.ts --packages externalnaming
Настраивает сгенерированные имена файлов. По умолчанию ./[dir]/[name].[ext].
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: "[dir]/[name].[ext]", // по умолчанию
})CLI
bun build ./index.tsx --outdir ./out --entry-naming "[dir]/[name].[ext]"По умолчанию имена сгенерированных бандлов основаны на имени соответствующей точки входа.
.
├── index.tsx
└── out
└── index.jsС несколькими точками входа иерархия сгенерированных файлов будет отражать структуру директорий точек входа.
.
├── index.tsx
└── nested
└── index.tsx
└── out
├── index.js
└── nested
└── index.jsИмена и расположения сгенерированных файлов можно настроить с помощью поля naming. Это поле принимает строку шаблона которая используется для генерации имен файлов для всех бандлов соответствующих точкам входа где следующие токены заменяются их соответствующими значениями:
[name]- Имя файла точки входа без расширения.[ext]- Расширение сгенерированного бандла.[hash]- Хеш содержимого бандла.[dir]- Относительный путь от корня проекта до родительской директории исходного файла.
Например:
| Токен | [name] | [ext] | [hash] | [dir] |
|---|---|---|---|---|
./index.tsx | index | js | a1b2c3d4 | "" (пустая строка) |
./nested/entry.ts | entry | js | c3d4e5f6 | "nested" |
Мы можем комбинировать эти токены для создания строки шаблона. Например чтобы включить хеш в имена сгенерированных бандлов:
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: 'files/[dir]/[name]-[hash].[ext]',
})CLI
bun build ./index.tsx --outdir ./out --entry-naming 'files/[dir]/[name]-[hash].[ext]'Эта сборка приведет к следующей структуре файлов:
.
├── index.tsx
└── out
└── files
└── index-a1b2c3d4.jsКогда для поля naming предоставлена строка она используется только для бандлов соответствующих точкам входа. Имена чанков и скопированных активов не затрагиваются. Используя JavaScript API можно указать отдельные строки шаблона для каждого типа сгенерированного файла.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: {
// значения по умолчанию
entry: '[dir]/[name].[ext]',
chunk: '[name]-[hash].[ext]',
asset: '[name]-[hash].[ext]',
},
})CLI
bun build ./index.tsx --outdir ./out \
--entry-naming '[dir]/[name].[ext]' \
--chunk-naming '[name]-[hash].[ext]' \
--asset-naming '[name]-[hash].[ext]'root
Корневая директория проекта.
JavaScript
await Bun.build({
entrypoints: ['./pages/a.tsx', './pages/b.tsx'],
outdir: './out',
root: '.',
})CLI
bun build ./pages/a.tsx ./pages/b.tsx --outdir ./out --root .Если не указано вычисляется как первый общий предок всех файлов точек входа. Рассмотрим следующую структуру файлов:
.
└── pages
└── index.tsx
└── settings.tsxМы можем собрать обе точки входа в директории pages:
JavaScript
await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
})CLI
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./outЭто приведет к следующей структуре файлов:
.
└── pages
└── index.tsx
└── settings.tsx
└── out
└── index.js
└── settings.jsПоскольку директория pages является первым общим предком файлов точек входа она считается корнем проекта. Это означает что сгенерированные бандлы находятся на верхнем уровне директории out; нет директории out/pages.
Таким поведением можно переопределить указав опцию root:
JavaScript
await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
root: '.',
})CLI
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out --root .Указав . как root сгенерированная структура файлов будет выглядеть так:
.
└── pages
└── index.tsx
└── settings.tsx
└── out
└── pages
└── index.js
└── settings.jspublicPath
Префикс который будет добавлен к любым путям импорта в связанном коде.
Во многих случаях сгенерированные бандлы не будут содержать операторов импорта. В конце концов цель связывания — объединить весь код в один файл. Однако есть ряд случаев когда сгенерированные бандлы будут содержать операторы импорта.
- Импорт активов — При импорте нераспознанного типа файла такого как
*.svgбандлер передает файловому загрузчику который копирует файл вoutdirкак есть. Импорт преобразуется в переменную - Внешние модули — Файлы и модули могут быть помечены как внешние в этом случае они не будут включены в бандл. Вместо этого оператор импорта останется в итоговом бандле.
- Разделение на чанки. Когда включено
splittingбандлер может генерировать отдельные файлы «чанков» которые представляют код общий для нескольких точек входа.
В любом из этих случаев итоговые бандлы могут содержать пути к другим файлам. По умолчанию эти импорты относительные. Вот пример простого импорта актива:
import logo from "./logo.svg";
console.log(logo);var logo = "./logo-a7305bdef.svg";
console.log(logo);Установка publicPath добавит префикс ко всем путям файлов с указанным значением.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
publicPath: 'https://cdn.example.com/', // по умолчанию undefined
})CLI
bun build ./index.tsx --outdir ./out --public-path 'https://cdn.example.com/'Файл вывода теперь будет выглядеть примерно так.
var logo = "https://cdn.example.com/logo-a7305bdef.svg";define
Карта глобальных идентификаторов которые будут заменены во время сборки. Ключи этого объекта — имена идентификаторов а значения — JSON-строки которые будут встроены.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
define: {
STRING: JSON.stringify("value"),
"nested.boolean": "true",
},
})CLI
bun build ./index.tsx --outdir ./out --define STRING='"value"' --define nested.boolean=trueloader
Карта расширений файлов к встроенным именам загрузчиков. Это можно использовать для быстрой настройки загрузки определенных файлов.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
loader: {
".png": "dataurl",
".txt": "file",
},
})CLI
bun build ./index.tsx --outdir ./out --loader .png:dataurl --loader .txt:filebanner
Заголовок который будет добавлен в итоговый бандл это может быть директива like use client для react или блок комментариев такой как лицензия для кода.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
banner: 'use client;'
})CLI
bun build ./index.tsx --outdir ./out --banner 'use client";'footer
Подвал который будет добавлен в итоговый бандл это может быть что-то вроде блока комментариев для лицензии или просто пасхалка.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
footer: '// built with love in SF'
})CLI
bun build ./index.tsx --outdir ./out --footer '// built with love in SF'drop
Удаляет вызовы функций из бандла. Например --drop=console удалит все вызовы console.log. Аргументы вызовов также будут удалены независимо от того могут ли эти аргументы иметь побочные эффекты. Удаление debugger удалит все операторы debugger.
JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
drop: ["console", "debugger", "anyIdentifier.or.propertyAccess"],
})CLI
bun build ./index.tsx --outdir ./out --drop console --drop debuggerOutputs
Функция Bun.build возвращает Promise<BuildOutput> определенный как:
interface BuildOutput {
outputs: BuildArtifact[];
success: boolean;
logs: Array<object>; // смотрите документацию для деталей
}
interface BuildArtifact extends Blob {
kind: "entry-point" | "chunk" | "asset" | "sourcemap";
path: string;
loader: Loader;
hash: string | null;
sourcemap: BuildArtifact | null;
}Массив outputs содержит все файлы сгенерированные сборкой. Каждый артефакт реализует интерфейс Blob.
const build = await Bun.build({
/* */
});
for (const output of build.outputs) {
await output.arrayBuffer(); // => ArrayBuffer
await output.bytes(); // => Uint8Array
await output.text(); // string
}Каждый артефакт также содержит следующие свойства:
| Свойство | Описание |
|---|---|
kind | Какой тип вывода файла. Сборка генерирует связанные точки входа чанки с разделением кода карты исходного кода байт-код и скопированные активы (например изображения). |
path | Абсолютный путь к файлу на диске |
loader | Загрузчик использованный для интерпретации файла. Смотрите Bundler > Loaders чтобы увидеть как Bun сопоставляет расширения файлов с соответствующим встроенным загрузчиком. |
hash | Хеш содержимого файла. Всегда определен для активов. |
sourcemap | Файл карты исходного кода соответствующий этому файлу если сгенерирован. Определен только для точек входа и чанков. |
Подобно BunFile объекты BuildArtifact можно передавать напрямую в new Response().
const build = await Bun.build({
/* */
});
const artifact = build.outputs[0];
// Заголовок Content-Type устанавливается автоматически
return new Response(artifact);Среда выполнения Bun реализует специальную печать объектов BuildArtifact для упрощения отладки.
// build.ts
const build = await Bun.build({
/* */
});
const artifact = build.outputs[0];
console.log(artifact);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
Опция bytecode: boolean может использоваться для генерации байт-кода для любых точек входа JavaScript/TypeScript. Это может значительно улучшить время запуска для больших приложений. Поддерживается только для формата "cjs" только поддерживает "target": "bun" и зависит от соответствующей версии Bun. Это добавляет соответствующий файл .jsc для каждой точки входа.
JavaScript
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
bytecode: true,
})CLI
bun build ./index.tsx --outdir ./out --bytecodeExecutables
Bun поддерживает «компиляцию» точки входа JavaScript/TypeScript в автономный исполняемый файл. Этот исполняемый файл содержит копию бинарного файла Bun.
bun build ./cli.tsx --outfile mycli --compile
./mycliПолную документацию смотрите на странице Bundler > Executables.
Logs and errors
При неудаче Bun.build возвращает отклоненный промис с AggregateError. Это можно вывести в консоль для красивого вывода списка ошибок или программно прочитать с помощью блока try/catch.
try {
const result = await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
});
} catch (e) {
// TypeScript не позволяет аннотациям в пункте catch
const error = e as AggregateError;
console.error("Build Failed");
// Пример: Использование встроенного форматирования
console.error(error);
// Пример: Сериализация ошибки как JSON-строки.
console.error(JSON.stringify(error, null, 2));
}В большинстве случаев явный try/catch не нужен так как Bun аккуратно выводит неперехваченные исключения. Достаточно просто использовать top-level await на вызове Bun.build.
Каждый элемент в error.errors является экземпляром BuildMessage или ResolveMessage (подклассы Error) содержащим подробную информацию для каждой ошибки.
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;
}При успешной сборке возвращенный объект содержит свойство logs которое содержит предупреждения бандлера и информационные сообщения.
const result = await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
});
if (result.logs.length > 0) {
console.warn("Build succeeded with warnings:");
for (const message of result.logs) {
// Bun красиво выведет объект сообщения
console.warn(message);
}
}Reference
interface Bun {
build(options: BuildOptions): Promise<BuildOutput>;
}
interface BuildConfig {
entrypoints: string[]; // список путей к файлам
outdir?: string; // выходная директория
target?: Target; // по умолчанию: "browser"
/**
* Формат выходного модуля. Top-level await поддерживается только для `"esm"`.
*
* Может быть:
* - `"esm"`
* - `"cjs"` (**экспериментально**)
* - `"iife"` (**экспериментально**)
*
* @default "esm"
*/
format?: "esm" | "cjs" | "iife";
/**
* Объект конфигурации JSX для контроля поведения трансформации 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; // корень проекта
splitting?: boolean; // по умолчанию true включает разделение кода
plugins?: BunPlugin[];
external?: string[];
packages?: "bundle" | "external";
publicPath?: string;
define?: Record<string, string>;
loader?: { [k in string]: Loader };
sourcemap?: "none" | "linked" | "inline" | "external" | boolean; // по умолчанию: "none", true -> "inline"
/**
* Условия экспорта package.json используемые при разрешении импортов
*
* Эквивалентно `--conditions` в `bun build` или `bun run`.
*
* https://nodejs.org/api/packages.html#exports
*/
conditions?: Array<string> | string;
/**
* Контролирует как обрабатываются переменные окружения во время связывания.
*
* Может быть одним из:
* - `"inline"`: Внедряет переменные окружения в связанный вывод преобразуя ссылки `process.env.FOO`
* в строковые литералы содержащие фактические значения переменных окружения
* - `"disable"`: Полностью отключает внедрение переменных окружения
* - Строка оканчивающаяся на `*`: Встраивает переменные окружения соответствующие заданному префиксу.
* Например `"MY_PUBLIC_"` включит только переменные окружения начинающиеся с "MY_PUBLIC_"
*/
env?: "inline" | "disable" | `${string}*`;
minify?:
| boolean
| {
whitespace?: boolean;
syntax?: boolean;
identifiers?: boolean;
};
/**
* Игнорировать аннотации устранения мертвого кода/встряхивания дерева такие как @__PURE__ и поля
* package.json "sideEffects". Это следует использовать только как временное решение для некорректных
* аннотаций в библиотеках.
*/
ignoreDCEAnnotations?: boolean;
/**
* Принудительно добавлять аннотации @__PURE__ даже если minify.whitespace равен true.
*/
emitDCEAnnotations?: boolean;
/**
* Генерировать байт-код для вывода. Это может значительно улучшить время
* холодного запуска но сделает итоговый вывод больше и немного увеличит
* использование памяти.
*
* Байт-код в настоящее время поддерживается только для CommonJS (`format: "cjs"`).
*
* Должен быть `target: "bun"`
* @default false
*/
bytecode?: boolean;
/**
* Добавить заголовок в связанный код такой как "use client";
*/
banner?: string;
/**
* Добавить подвал в связанный код такой как блок комментариев
*
* `// made with bun!`
*/
footer?: string;
/**
* Удалить вызовы функций к соответствующим доступа к свойствам.
*/
drop?: string[];
/**
* - Когда установлено в `true` возвращенный промис отклоняется с AggregateError при ошибке сборки.
* - Когда установлено в `false` возвращает {@link BuildOutput} с `{success: false}`
*
* @default true
*/
throw?: boolean;
/**
* Путь к пользовательскому файлу tsconfig.json для использования при разрешении путей.
* Эквивалентно `--tsconfig-override` в 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;
}