aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Colin McDonnell <colinmcd94@gmail.com> 2023-05-16 10:47:00 -0700
committerGravatar GitHub <noreply@github.com> 2023-05-16 10:47:00 -0700
commit366eba78f0b9b2c58cdd46b906275fc8382da977 (patch)
tree8966c3964aeacc4a7f61a69164467e9ebf37b6e1
parent60bc804c58b18e99763b2d05e81bafa46800092f (diff)
downloadbun-366eba78f0b9b2c58cdd46b906275fc8382da977.tar.gz
bun-366eba78f0b9b2c58cdd46b906275fc8382da977.tar.zst
bun-366eba78f0b9b2c58cdd46b906275fc8382da977.zip
Tweaks to bundler docs (#2867)
* WIP * Fix typo * Updates * Document --compile * Add bundler benchmark * Remove esbuild * Add bench to docs * Add buttons * Updates
-rw-r--r--bench/bundle/.gitignore171
-rw-r--r--bench/bundle/README.md40
-rwxr-xr-xbench/bundle/bun.lockbbin0 -> 1139 bytes
-rw-r--r--bench/bundle/index.ts1
-rw-r--r--bench/bundle/package.json8
-rwxr-xr-xbench/bundle/run-bench.sh3
-rw-r--r--bench/bundle/tsconfig.json20
-rw-r--r--docs/bundler/executables.md33
-rw-r--r--docs/bundler/migration.md2
-rw-r--r--docs/cli/build.md194
-rw-r--r--docs/index.md2
-rw-r--r--docs/nav.ts3
-rw-r--r--packages/bun-types/bun.d.ts22
13 files changed, 454 insertions, 45 deletions
diff --git a/bench/bundle/.gitignore b/bench/bundle/.gitignore
new file mode 100644
index 000000000..6463d8435
--- /dev/null
+++ b/bench/bundle/.gitignore
@@ -0,0 +1,171 @@
+# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
+
+# Logs
+
+logs
+_.log
+npm-debug.log_
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+
+report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
+
+# Runtime data
+
+pids
+_.pid
+_.seed
+\*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+
+lib-cov
+
+# Coverage directory used by tools like istanbul
+
+coverage
+\*.lcov
+
+# nyc test coverage
+
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+
+bower_components
+
+# node-waf configuration
+
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+
+build/Release
+
+# Dependency directories
+
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+
+web_modules/
+
+# TypeScript cache
+
+\*.tsbuildinfo
+
+# Optional npm cache directory
+
+.npm
+
+# Optional eslint cache
+
+.eslintcache
+
+# Optional stylelint cache
+
+.stylelintcache
+
+# Microbundle cache
+
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+
+.node_repl_history
+
+# Output of 'npm pack'
+
+\*.tgz
+
+# Yarn Integrity file
+
+.yarn-integrity
+
+# dotenv environment variable files
+
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+
+.cache
+.parcel-cache
+
+# Next.js build output
+
+.next
+out
+
+# Nuxt.js build / generate output
+
+.nuxt
+dist
+
+# Gatsby files
+
+.cache/
+
+# Comment in the public line in if your project uses Gatsby and not Next.js
+
+# https://nextjs.org/blog/next-9-1#public-directory-support
+
+# public
+
+# vuepress build output
+
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+
+.temp
+.cache
+
+# Docusaurus cache and generated files
+
+.docusaurus
+
+# Serverless directories
+
+.serverless/
+
+# FuseBox cache
+
+.fusebox/
+
+# DynamoDB Local files
+
+.dynamodb/
+
+# TernJS port file
+
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+
+.vscode-test
+
+# yarn v2
+
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.\*
+
+esbuild \ No newline at end of file
diff --git a/bench/bundle/README.md b/bench/bundle/README.md
new file mode 100644
index 000000000..e973fcd35
--- /dev/null
+++ b/bench/bundle/README.md
@@ -0,0 +1,40 @@
+# Bundler benchmark
+
+This is a performance benchmark of the following bundlers:
+
+- Bun
+- esbuild
+- Parcel 2
+- Rollup + Terser
+- Webpack
+
+It is an exact copy of [`esbuild`'s benchmark](https://github.com/evanw/esbuild/blob/main/Makefile), aside from the fast that Bun [has been added](https://github.com/colinhacks/esbuild/commit/1b928b7981aa7edfadf77fcf8931bb8d6f38cd96). The benchmark bundles 10 copies of the large [three.js](https://threejs.org/), with minification and source maps enabled.
+
+To run the benchmark:
+
+```sh
+$ chmod +x run-bench.sh
+$ ./run-bench.sh
+```
+
+Various output will be written to the console by each bundler. Scan through the results for lines that look like this underneath each bundler output:
+
+```sh
+real <number>
+user <number>
+sys <number>
+```
+
+These lines are generated by the `time` command which is used to benchmark each build.
+
+## Results
+
+The `real` results, as run on a 16-inch M1 Macbook Pro:
+
+| Bundler | Time |
+| ------- | ------ |
+| Bun | 0.17s |
+| esbuild | 0.33s |
+| Rollup | 18.82s |
+| Webpack | 26.21 |
+| Parcel | 17.95s |
diff --git a/bench/bundle/bun.lockb b/bench/bundle/bun.lockb
new file mode 100755
index 000000000..b5ea51df5
--- /dev/null
+++ b/bench/bundle/bun.lockb
Binary files differ
diff --git a/bench/bundle/index.ts b/bench/bundle/index.ts
new file mode 100644
index 000000000..f67b2c645
--- /dev/null
+++ b/bench/bundle/index.ts
@@ -0,0 +1 @@
+console.log("Hello via Bun!"); \ No newline at end of file
diff --git a/bench/bundle/package.json b/bench/bundle/package.json
new file mode 100644
index 000000000..c80d9b81e
--- /dev/null
+++ b/bench/bundle/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "bundle",
+ "module": "index.ts",
+ "type": "module",
+ "devDependencies": {
+ "bun-types": "^0.5.0"
+ }
+} \ No newline at end of file
diff --git a/bench/bundle/run-bench.sh b/bench/bundle/run-bench.sh
new file mode 100755
index 000000000..c14a370d5
--- /dev/null
+++ b/bench/bundle/run-bench.sh
@@ -0,0 +1,3 @@
+git clone git@github.com:colinhacks/esbuild.git
+cd esbuild
+make bench-three \ No newline at end of file
diff --git a/bench/bundle/tsconfig.json b/bench/bundle/tsconfig.json
new file mode 100644
index 000000000..5c0ced989
--- /dev/null
+++ b/bench/bundle/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "lib": [
+ "ESNext"
+ ],
+ "module": "esnext",
+ "target": "esnext",
+ "moduleResolution": "bundler",
+ "strict": true,
+ "downlevelIteration": true,
+ "skipLibCheck": true,
+ "jsx": "react-jsx",
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowJs": true,
+ "types": [
+ "bun-types" // add Bun global
+ ]
+ }
+} \ No newline at end of file
diff --git a/docs/bundler/executables.md b/docs/bundler/executables.md
new file mode 100644
index 000000000..9a0fc639e
--- /dev/null
+++ b/docs/bundler/executables.md
@@ -0,0 +1,33 @@
+Bun's bundler implements a `--compile` flag for generating a standalone binary from a TypeScript or JavaScript file.
+
+{% codetabs %}
+
+```bash
+$ bun build ./cli.ts --compile --outfile mycli
+```
+
+```ts#cli.ts
+console.log("Hello world!");
+```
+
+{% /codetabs %}
+
+This bundles `cli.ts` into an executable that can be executed directly:
+
+```
+$ ./mycli
+Hello world!
+```
+
+All imported files and packages are bundled into the executable, along with a copy of the Bun runtime. All built-in Bun and Node.js APIs are supported.
+
+{% callout %}
+
+**Note** — Currently, the `--compile` flag can only accept a single entrypoint at a time and does not support the following flags:
+
+- `--outdir` — use `outfile` instead.
+- `--external`
+- `--splitting`
+- `--publicPath`
+
+{% /callout %}
diff --git a/docs/bundler/migration.md b/docs/bundler/migration.md
index e76d50103..1bf9d52dc 100644
--- a/docs/bundler/migration.md
+++ b/docs/bundler/migration.md
@@ -6,7 +6,7 @@ Bun's bundler API is inspired heavily by [esbuild](https://esbuild.github.io/).
There are a few behavioral differences to note.
-- **Bundling by default**. Unlike esbuild, Bun _always bundles by default_. This is why the `--bundle` flag isn't necessary in the Bun example. To transpile each file individually, use [`Bun.Transpiler`](/docs/api/transpiler.md).
+- **Bundling by default**. Unlike esbuild, Bun _always bundles by default_. This is why the `--bundle` flag isn't necessary in the Bun example. To transpile each file individually, use [`Bun.Transpiler`](/docs/api/transpiler).
- **It's just a bundler**. Unlike esbuild, Bun's bundler does not include a built-in development server or file watcher. It's just a bundler. The bundler is intended for use in conjunction with `Bun.serve` and other runtime APIs to achieve the same effect. As such, all options relating to HTTP/file watching are not applicable.
## Performance
diff --git a/docs/cli/build.md b/docs/cli/build.md
index f7113ae9f..e0cd36651 100644
--- a/docs/cli/build.md
+++ b/docs/cli/build.md
@@ -15,6 +15,10 @@ $ bun build ./index.tsx --outdir ./build
{% /codetabs %}
+It's fast. The numbers below represent performance on esbuild's [three.js benchmark](https://github.com/oven-sh/bun/tree/main/bench/bundle).
+
+{% image src="/images/bundler-speed.png" caption="Bundling 10 copies of three.js from scratch, with sourcemaps and minification" /%}
+
## Why bundle?
The bundler is a key piece of infrastructure in the JavaScript ecosystem. As a brief overview of why bundling is so important:
@@ -207,7 +211,7 @@ Refer to the [Bundler > Loaders](/docs/bundler/loaders#file) page for more compl
### Plugins
-The behavior described in this table can be overridden with [plugins](/docs/bundler/plugins). Refer to the [Bundler > Loaders](/docs/bundler/plugins) page for complete documentation.
+The behavior described in this table can be overridden or extended with [plugins](/docs/bundler/plugins). Refer to the [Bundler > Loaders](/docs/bundler/plugins) page for complete documentation.
## API
@@ -217,9 +221,9 @@ The behavior described in this table can be overridden with [plugins](/docs/bund
{% codetabs group="a" %}
-```ts #JavaScript
+```ts#JavaScript
const result = await Bun.build({
- entrypoints: ['./index.ts']
+ entrypoints: ["./index.ts"],
});
// => { success: boolean, outputs: BuildArtifact[], logs: BuildMessage[] }
```
@@ -253,11 +257,11 @@ $ bun build --entrypoints ./index.ts --outdir ./out
{% /codetabs %}
-If `outdir` is not passed to the JavaScript API, bundled code will not be written to disk. Bundled files are returned in an array of `BuildArtifact` objects. These objects are Blobs with extra properties.
+If `outdir` is not passed to the JavaScript API, bundled code will not be written to disk. Bundled files are returned in an array of `BuildArtifact` objects. These objects are Blobs with extra properties; see [Outputs](#outputs) for complete documentation.
```ts
const result = await Bun.build({
- entrypoints: ['./index.ts']
+ entrypoints: ["./index.ts"],
});
for (const result of result.outputs) {
@@ -272,7 +276,7 @@ for (const result of result.outputs) {
}
```
-When `outdir` is set, the `.path` on `BuildArtifact` will be the absolute path to where it was written to.
+When `outdir` is set, the `path` property on a `BuildArtifact` will be the absolute path to where it was written to.
### `target`
@@ -312,6 +316,8 @@ Depending on the target, Bun will apply different module resolution rules and op
All bundles generated with `target: "bun"` are marked with a special `// @bun` pragma, which indicates to the Bun runtime that there's no need to re-transpile the file before execution.
+ If any entrypoints contains a Bun shebang (`#!/usr/bin/env bun`) the bundler will default to `target: "bun"` instead of `"browser`.
+
---
- `node`
@@ -319,6 +325,10 @@ Depending on the target, Bun will apply different module resolution rules and op
{% /table %}
+{% callout %}
+
+{% /callout %}
+
### `format`
Specifies the module format to be used in the generated bundles.
@@ -1051,18 +1061,133 @@ $ bun build ./index.tsx --outdir ./out --loader .png:dataurl --loader .txt:file
{% /codetabs %}
+## Outputs
+
+The `Bun.build` function returns a `Promise<BuildOutput>`, defined as:
+
+```ts
+interface BuildOutput {
+ outputs: BuildArtifact[];
+ success: boolean;
+ logs: Array<object>; // see docs for details
+}
-## Error handling
+interface BuildArtifact extends Blob {
+ kind: "entry-point" | "chunk" | "asset" | "sourcemap";
+ path: string;
+ loader: Loader;
+ hash: string | null;
+ sourcemap: BuildArtifact | null;
+}
+```
-`Bun.build` only throws if invalid options are provided. You should read the `success` and `logs` properties of the result to determine whether the build was successful.
+The `outputs` array contains all the files that were generated by the build. Each artifact implements the `Blob` interface.
+
+```ts
+const build = Bun.build({
+ /* */
+});
+
+for (const output of build.outputs) {
+ await output.arrayBuffer(); // => ArrayBuffer
+ await output.text(); // string
+}
+```
+
+Each artifact also contains the following properties:
+
+{% table %}
+
+---
+
+- `kind`
+- What kind of build output this file is. A build generates bundled entrypoints, code-split "chunks", sourcemaps, and copied assets (like images).
+
+---
+
+- `path`
+- Absolute path to the file on disk
+
+---
+
+- `loader`
+- The loader was used to interpret the file. See [Bundler > Loaders](/docs/bundler/loaders) to see how Bun maps file extensions to the appropriate built-in loader.
+
+---
+
+- `hash`
+- The hash of the file contents. Always defined for assets.
+
+---
+
+- `sourcemap`
+- The sourcemap file corresponding to this file, if generated. Only defined for entrypoints and chunks.
+
+{% /table %}
+
+Similar to `BunFile`, `BuildArtifact` objects can be passed directly into `new Response()`.
+
+```ts
+const build = Bun.build({
+ /* */
+});
+
+const artifact = build.outputs[0];
+
+// Content-Type header is automatically set
+return new Response(artifact);
+```
+
+The Bun runtime implements special pretty-printing of `BuildArtifact` object to make debugging easier.
+
+{% codetabs %}
+
+```ts#Build_script
+// build.ts
+const build = Bun.build({/* */});
+
+const artifact = build.outputs[0];
+console.log(artifact);
+```
+
+```sh#Shell_output
+$ bun run build.ts
+BuildArtifact (entry-point) {
+ path: "./index.js",
+ loader: "tsx",
+ kind: "entry-point",
+ hash: "824a039620219640",
+ Blob (114 bytes) {
+ type: "text/javascript;charset=utf-8"
+ },
+ sourcemap: null
+}
+```
+
+{% /codetabs %}
+
+### Executables
+
+Bun supports "compiling" a JavaScript/TypeScript entrypoint into a standalone executable. This executable contains a copy of the Bun binary.
+
+```sh
+$ bun build ./cli.tsx --outfile mycli --compile
+$ ./mycli
+```
+
+Refer to [Bundler > Executables](/docs/bundler/executables) for complete documentation.
+
+## Logs and errors
+
+`Bun.build` only throws if invalid options are provided. Read the `success` property to determine if the build was successful; the `logs` property will contain additional details.
```ts
const result = await Bun.build({
- entrypoints: ['./index.tsx'],
- outdir: './out',
+ entrypoints: ["./index.tsx"],
+ outdir: "./out",
});
-if(!result.success) {
+if (!result.success) {
console.error("Build failed");
for (const message of result.logs) {
// Bun will pretty print the message object
@@ -1089,7 +1214,7 @@ class ResolveMessage extends BuildMessage {
}
```
-If you want to throw an error from a failed build, consider passing the logs to an `AggregateError`. If uncaught, Bun will pretty print the contained messages nicely.
+If you want to throw an error from a failed build, consider passing the logs to an `AggregateError`. If uncaught, Bun will pretty-print the contained messages nicely.
```ts
if (!result.success) {
@@ -1143,24 +1268,43 @@ interface BuildArtifact extends Blob {
path: string;
loader: Loader;
hash?: string;
- kind: "entry-point" | "chunk" | "asset" | "sourecemap";
+ kind: "entry-point" | "chunk" | "asset" | "sourcemap";
sourcemap?: BuildArtifact;
}
-type Loader =
- | "js"
- | "jsx"
- | "ts"
- | "tsx"
- | "json"
- | "toml"
- | "file"
- | "napi"
- | "wasm"
- | "text";
+type Loader = "js" | "jsx" | "ts" | "tsx" | "json" | "toml" | "file" | "napi" | "wasm" | "text";
+
+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;
+}
```
-<!--
+<!--
interface BuildManifest {
inputs: {
[path: string]: {
diff --git a/docs/index.md b/docs/index.md
index b0bff82f1..6b5891cdf 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -25,6 +25,8 @@ Get started with one of the quick links below, or read on to learn more about Bu
{% arrowbutton href="/docs/installation" text="Install Bun" /%}
{% arrowbutton href="/docs/quickstart" text="Do the quickstart" /%}
{% arrowbutton href="/docs/cli/install" text="Install a package" /%}
+{% arrowbutton href="//docs/templates" text="Use a project template" /%}
+{% arrowbutton href="/docs/cli/build" text="Bundle code for production" /%}
{% arrowbutton href="/docs/api/http" text="Build an HTTP server" /%}
{% arrowbutton href="/docs/api/websockets" text="Build a Websocket server" /%}
{% arrowbutton href="/docs/api/file-io" text="Read and write files" /%}
diff --git a/docs/nav.ts b/docs/nav.ts
index f1dd92c35..448d661af 100644
--- a/docs/nav.ts
+++ b/docs/nav.ts
@@ -166,6 +166,9 @@ export default {
page("bundler/plugins", "Plugins", {
description: `Implement custom loaders and module resolution logic with Bun's plugin system.`,
}),
+ page("bundler/executables", "Executables", {
+ description: "Compile a TypeScript or JavaScript file to a standalone cross-platform executable",
+ }),
page("bundler/migration", "Migration", {
description: `Guides for migrating from other bundlers to Bun.`,
}),
diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts
index 3dea90969..dffe37b35 100644
--- a/packages/bun-types/bun.d.ts
+++ b/packages/bun-types/bun.d.ts
@@ -999,28 +999,12 @@ declare module "bun" {
path: string;
loader: Loader;
hash: string | null;
- kind: "entry-point" | "chunk";
+ kind: "entry-point" | "chunk" | "asset" | "sourcemap";
sourcemap: BuildArtifact | null;
}
- interface SourceMapBuildArtifact extends Blob {
- path: string;
- loader: Loader;
- hash: null;
- kind: "sourecemap";
- sourcemap: null;
- }
-
- interface AssetBuildArtifact extends Blob {
- path: string;
- loader: Loader;
- hash: string;
- kind: "asset";
- sourcemap: null;
- }
-
interface BuildOutput {
- outputs: Array<BuildArtifact | AssetBuildArtifact | SourceMapBuildArtifact>;
+ outputs: Array<BuildArtifact>;
success: boolean;
logs: Array<BuildMessage | ResolveMessage>;
}
@@ -2751,7 +2735,7 @@ declare module "bun" {
/**
* The config object passed to `Bun.build` as is. Can be mutated.
*/
- config: BuildConfig & { plugins: BunPlugin[]; };
+ config: BuildConfig & { plugins: BunPlugin[] };
}
interface BunPlugin {