aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/bundler/loaders.md284
-rw-r--r--docs/cli/build.md299
-rw-r--r--packages/bun-types/bun.d.ts20
-rw-r--r--src/bun.js/api/JSBundler.zig41
-rw-r--r--src/cli.zig2
5 files changed, 394 insertions, 252 deletions
diff --git a/docs/bundler/loaders.md b/docs/bundler/loaders.md
index c8f067385..7cac75648 100644
--- a/docs/bundler/loaders.md
+++ b/docs/bundler/loaders.md
@@ -1,136 +1,234 @@
The Bun bundler implements a set of default loaders out of the box. As a rule of thumb, the bundler and the runtime both support the same set of file types out of the box.
-`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.toml` `.json`
+`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.toml` `.json` `.txt` `.wasm` `.node`
-{% callout %}
-The runtime also supports `.wasm` and `.node` binaries, which are not easily embedded in a bundle. These are effectively not supported by Bun's bundler.
-{% /callout %}
+Bun uses the file extension to determine which built-in _loader_ should be used to parse the file. Every loader has a name, such as `js`, `tsx`, or `json`. These names are used when building [plugins](/docs/bundler/plugins) that extend Bun with custom loaders.
-This document describes how these extensions map onto Bun's set of built-in _loaders_. Every loader has a name, such as `js`, `tsx`, or `json`. These names are used when building [plugins](/docs/bundler/plugins) that extend Bun with custom loaders.
+## Built-in loaders
-{% table %}
+### `js`
-- Loader
-- Extensions
-- Description
+**JavaScript**. Default for `.cjs` and `.mjs`.
----
+Parses the code and applies a set if default transforms, like dead-code elimination, tree shaking, and environment variable inlining. Note that Bun does not attempt to down-convert syntax at the moment.
-- `js`
-- `.cjs` `.mjs`
-- **JavaScript.** Parses the code and applies a set if default transforms, like dead-code elimination, tree shaking, and environment variable inlining. Note that Bun does not attempt to down-convert syntax at the moment.
+### `jsx`
----
+**JavaScript + JSX.**. Default for `.js` and `.jsx`.
-- `jsx`
-- `.js` `.jsx`
-- **JavaScript + JSX.** Same as the `js` loader, but JSX syntax is supported. By default, JSX is downconverted to `createElement` syntax and a `jsx` factory is injected into the bundle. This can be configured using the relevant `jsx*` compiler options in `tsconfig.json`.
+Same as the `js` loader, but JSX syntax is supported. By default, JSX is downconverted to plain JavaScript; the details of how this is done depends on the `jsx*` compiler options in your `tsconfig.json`. Refer to the TypeScript documentation [on JSX](https://www.typescriptlang.org/docs/handbook/jsx.html) for more information.
----
+### `ts`
-- `ts`
-- `.mts` `.cts`
-- **TypeScript.** Strips out all TypeScript syntax, then behaves identically to the `js` loader. Bun does not perform typechecking.
+**TypeScript loader**. Default for `.ts`, `.mts`, and `.cts`.
----
+Strips out all TypeScript syntax, then behaves identically to the `js` loader. Bun does not perform typechecking.
-- `tsx`
-- `.ts` `.tsx`
-- **TypeScript + JSX**. Transpiles both TypeScript and JSX to vanilla JavaScript.
+### `tsx`
----
+**TypeScript + JSX loader**. Default for `.tsx`. Transpiles both TypeScript and JSX to vanilla JavaScript.
-- `json`
-- `.json`
-- **JSON**. JSON files are parsed and inlined into the bundle as a JavaScript object.
+### `json`
- ```ts
- import pkg from "./package.json";
- pkg.name; // => "my-package"
- ```
+**JSON loader**. Default for `.json`.
- If a `.json` file is passed as an entrypoint, it will be converted to a `.js` with the parsed object as a default export.
+JSON files can be directly imported.
- {% codetabs %}
+```ts
+import pkg from "./package.json";
+pkg.name; // => "my-package"
+```
- ```json#Input
- {
- "name": "John Doe",
- "age": 35,
- "email": "johndoe@example.com"
- }
- ```
+During bundling, the parsed JSON is inlined into the bundle as a JavaScript object.
- ```js#Output
- export default {
- name: "John Doe",
- age: 35,
- email: "johndoe@example.com"
- }
- ```
+```ts
+var pkg = {
+ name: "my-package",
+ // ... other fields
+};
+pkg.name;
+```
- {% /codetabs %}
+If a `.json` file is passed as an entrypoint to the bundler, it will be converted to a `.js` module that `export default`s the parsed object.
----
+{% codetabs %}
-- `toml`
-- `.toml`
-- **TOML**. TOML files are parsed and inlined into the bundle as a JavaScript object.
+```json#Input
+{
+ "name": "John Doe",
+ "age": 35,
+ "email": "johndoe@example.com"
+}
+```
- ```ts
- import config from "./bunfig.toml";
- config.logLevel; // => "debug"
- ```
+```js#Output
+export default {
+ name: "John Doe",
+ age: 35,
+ email: "johndoe@example.com"
+}
+```
- If a `.toml` file is passed as an entrypoint, it will be converted to a `.js` with the parsed object as a default export.
+{% /codetabs %}
- {% codetabs %}
+### `toml`
- ```toml#Input
- name = "John Doe"
- age = 35
- email = "johndoe@example.com"
- ```
+**TOML loader**. Default for `.toml`.
- ```js#Output
- export default {
- name: "John Doe",
- age: 35,
- email: "johndoe@example.com"
- }
- ```
+TOML files can be directly imported. Bun will parse them with its fast native TOML parser.
- {% /codetabs %}
+```ts
+import config from "./bunfig.toml";
+config.logLevel; // => "debug"
+```
----
+During bundling, the parsed TOML is inlined into the bundle as a JavaScript object.
+
+```ts
+var config = {
+ logLevel: "debug",
+ // ...other fields
+};
+config.logLevel;
+```
+
+If a `.toml` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the parsed object.
+
+{% codetabs %}
+
+```toml#Input
+name = "John Doe"
+age = 35
+email = "johndoe@example.com"
+```
+
+```js#Output
+export default {
+ name: "John Doe",
+ age: 35,
+ email: "johndoe@example.com"
+}
+```
+
+{% /codetabs %}
+
+### `text`
+
+**Text loader**. Default for `.txt`.
+
+The contents of the text file are read and inlined into the bundle as a string.
+Text files can be directly imported. The file is read and returned as a string.
+
+```ts
+import contents from "./file.txt";
+console.log(contents); // => "Hello, world!"
+```
+
+When referenced during a build, the contents are into the bundle as a string.
+
+```ts
+var contents = `Hello, world!`;
+console.log(contents);
+```
+
+If a `.txt` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the file contents.
+
+{% codetabs %}
+
+```txt#Input
+Hello, world!
+```
+
+```js#Output
+export default "Hello, world!";
+```
+
+{% /codetabs %}
-- `text`
-- `.txt`
-- **Text files**. The contents of the text file are read and inlined into the bundle as a string.
+### `wasm`
- ```ts
- import contents from "./file.txt";
- console.log(contents); // => "Hello, world!"
- ```
+**WebAssembly loader**. Default for `.wasm`.
- If a `.txt` file is passed as an entrypoint, it will be converted to a `.js` with the contents of the file as a default export.
+In the runtime, WebAssembly files can be directly imported. The file is read and returned as a `WebAssembly.Module`.
- {% codetabs %}
+```ts
+import wasm from "./module.wasm";
+console.log(wasm); // => WebAssembly.Module
+```
- ```txt#Input
- Hello, world!
- ```
+In the bundler, `.wasm` files are handled using the [`file`](#file) loader.
- ```js#Output
- export default "Hello, world!";
- ```
+### `napi`
- {% /codetabs %}
+**Native addon loader**. Default for `.node`.
+
+In the runtime, native addons can be directly imported.
+
+```ts
+import addon from "./addon.node";
+console.log(addon);
+```
+
+In the bundler, `.node` files are handled using the [`file`](#file) loader.
+
+### `file`
+
+**File loader**. Default for all unrecognized file types.
+
+The file loader resolves the import as a _path/URL_ to the imported file. It's commonly used for referencing media or font assets.
+
+```ts#logo.ts
+import logo from "./logo.svg";
+console.log(logo);
+```
+
+_In the runtime_, Bun checks that the `logo.svg` file exists and converts it to an absolute path to the location of `logo.svg` on disk.
+
+```bash
+$ bun run logo.ts
+/path/to/project/logo.svg
+```
+
+_In the bundler_, things are slightly different. The file is copied into `outdir` as-is, and the import is resolved as a relative path pointing to the copied file.
+
+```ts#Output
+var logo = "./logo.svg";
+console.log(logo);
+```
+
+If a value is specified for `publicPath`, the import will use value as a prefix to construct an absolute path/URL.
+
+{% table %}
+
+- Public path
+- Resolved import
---
-- `file`
-- `.*`
-- **File loader**. Any unrecognized file type is handled using the `file` loader. The file is copied into the `outdir` as-is. The name of the copied file is determined using the value of `naming.asset`.
+- `""` (default)
+- `/logo.svg`
+
+---
+
+- `"/assets"`
+- `/assets/logo.svg`
+
+---
+
+- `"https://cdn.example.com/"`
+- `https://cdn.example.com/`
{% /table %}
+
+{% callout %}
+The location and file name of the copied file is determined by the value of [`naming.asset`](/docs/cli/build#naming).
+{% callout %}
+This loader is copied into the `outdir` as-is. The name of the copied file is determined using the value of `naming.asset`.
+
+{% details summary="Fixing TypeScript import errors" %}
+If you're using TypeScript, you may get an error like this:
+
+```ts
+// TypeScript error
+// Cannot find module './logo.svg' or its corresponding type declarations.
+```
diff --git a/docs/cli/build.md b/docs/cli/build.md
index 2c7c78d4f..b4c7984dc 100644
--- a/docs/cli/build.md
+++ b/docs/cli/build.md
@@ -1,5 +1,5 @@
{% callout %}
-**Note** — Added in Bun v0.6.0
+**Note** — Available in the Bun v0.6.0 nightly. Run `bun upgrade --canary` to try it out.
{% /callout %}
Bun's fast native bundler is now in beta. It can be used via the `bun build` CLI command or the `Bun.build()` JavaScript API.
@@ -58,7 +58,7 @@ To create our bundle:
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
})
@@ -70,12 +70,7 @@ $ bun build ./index.tsx --outdir ./out
{% /codetabs %}
-Let's break that down.
-
-- `entrypoints` — **Required.** An array of paths corresponding to the entrypoints of our application. In this case, we just have one.
-- `outdir` — **Required.** The directory where output files will be written.
-
-Running this build will generate a new file `./out/index.js`.
+For each file specified in `entrypoints`, Bun will generate a new bundle. This bundle will be written to disk in the `./out` directory (as resolved from the current working directory). After running the build, the file system looks like this:
```ts
.
@@ -85,18 +80,18 @@ Running this build will generate a new file `./out/index.js`.
└── index.js
```
-It looks something like this:
+The contents of the `out/index.js` file looks something like this:
```js#out/index.js
// ...
// ~20k lines of code
// including the contents of `react-dom/client` and all its dependencies
-// this is where the $jsx and $createRoot functions are defined
+// this is where the $jsxDEV and $createRoot functions are defined
// Component.tsx
function Component(props) {
- return $jsx("p", {
+ return $jsxDEV("p", {
children: props.message
}, undefined, false, undefined, this);
}
@@ -104,7 +99,7 @@ function Component(props) {
// index.tsx
var rootNode = document.getElementById("root");
var root = $createRoot(rootNode);
-root.render($jsx(Component, {
+root.render($jsxDEV(Component, {
message: "Sup!"
}, undefined, false, undefined, this));
```
@@ -181,58 +176,42 @@ Like the Bun runtime, the bundler supports an array of file types out of the box
console.log(contents); // => "Hello, world!"
```
----
-
-- `.*`
-- If the bundler encounters a file with an unsupported extension, it treats it as an _external file_. That means the import is converted into a path, and the referenced file is copied into the `outdir` as-is.
-
- {% codetabs %}
-
- ```ts#Build_file
- Bun.build({
- entrypoints: ['./index.ts'],
- outdir: './out',
- origin: 'https://example.com',
- })
- ```
+{% /table %}
- ```ts#Input
- import logo from "./logo.svg";
- console.log(logo);
- ```
+### Assets
- ```ts#Output
- var logo = "./logo-ab237dfe.svg";
- console.log(logo);
- ```
+If the bundler encounters an import with an unrecognized extension, it treats the imported file as an _external file_. The referenced file is copied as-is into `outdir`, and the import is resolved as a _path_ to the file.
- {% /codetabs %}
+{% codetabs %}
- By default, a hash is added to the file name to avoid collisions; this behavior can be overridden with the [`naming.asset`](#naming) option.
+```ts#Build_file
+await Bun.build({
+ entrypoints: ['./index.ts'],
+ outdir: './out'
+})
+```
- If a value is provided for `origin`, the bundler will construct an absolute URL instead of using a relative path.
+```ts#Input
+import logo from "./logo.svg";
+console.log(logo);
+```
- {% codetabs %}
+```ts#Output
+var logo = "./logo-ab237dfe.svg";
+console.log(logo);
+```
- ```ts-diff#Build_file
- Bun.build({
- entrypoints: ['./index.ts'],
- outdir: './out',
- + origin: 'https://example.com',
- })
- ```
+{% /codetabs %}
- ```ts-diff#Output
- - var logo = "./logo-ab237dfe.svg";
- + var logo = "https://example.com/logo-ab237dfe.svg";
- console.log(logo);
- ```
+{% callout %}
+The exact behavior of the file loader is also impacted by [`naming`](#naming) and [`publicPath`](#publicpath).
+{% /callout %}
- {% /codetabs %}
+Refer to the [Bundler > Loaders](/docs/bundler/loaders#file) page for more complete documentation on the file loader.
-{% /table %}
+### Plugins
-The behavior described in this table can be overridden with [plugins](/docs/bundler/plugins). Refer to the [Bundler > Loaders](/docs/bundler/loaders) page for complete documentation on Bun's built-in loaders.
+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.
## API
@@ -240,9 +219,65 @@ The behavior described in this table can be overridden with [plugins](/docs/bund
**Required.** An array of paths corresponding to the entrypoints of our application. One bundle will be generated for each entrypoint.
+{% codetabs %}
+
+```ts#JavaScript
+const result = await Bun.build({
+ entrypoints: ['./index.ts']
+}); // => Promise
+
+await result;
+// => { outputs: Array<{ path: string; result: Blob }> }
+```
+
+```bash#CLI
+$ bun build --entrypoints ./index.ts
+# the bundle will be printed to stdout
+# <bundled code>
+```
+
+{% /codetabs %}
+
### `outdir`
-**Required.** The directory where output files will be written.
+The directory where output files will be written.
+
+{% codetabs %}
+
+```ts#JavaScript
+const result = await Bun.build({
+ entrypoints: ['./index.ts'],
+ outdir: './out'
+});
+
+result;
+// => { outputs: Array<{ path: string; result: BunFile }> }
+```
+
+```bash#CLI
+$ bun build --entrypoints ./index.ts --outdir ./out
+# the bundle will be printed to stdout
+# ...
+```
+
+{% /codetabs %}
+
+When `outdir` is specified:
+
+- The JavaScript API will write the generated bundles to the appropriate location in `outdir`. The result of the `Bun.build()` call will contain `BunFile` instances corresponding to the new files.
+
+ ```ts
+ const result = await Bun.build({
+ /* ... */
+ });
+ // => { outputs: Array<{ path: string; result: BunFile }> }
+
+ for (const { path, result } of result.outputs) {
+ console.log(`Wrote file: ${path}`);
+ }
+ ```
+
+- The CLI will print a summary of the written files. The bundled code will not be written to `stdout`.
### `target`
@@ -251,7 +286,7 @@ The intended execution environment for the bundle.
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out',
target: 'browser', // default
@@ -259,7 +294,7 @@ Bun.build({
```
```bash#CLI
-$ bunx build --entrypoints ./index.ts --outdir ./out --target browser
+$ bun build --entrypoints ./index.ts --outdir ./out --target browser
```
{% /codetabs %}
@@ -298,27 +333,27 @@ Currently the bundler only supports one module format: `"esm"`. Support for `"cj
{% codetabs %}
```ts#Bun.build
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
- module: "esm",
+ format: "esm",
})
```
```bash#CLI
-$ bun build ./index.tsx --outdir ./out --module esm
+$ bun build ./index.tsx --outdir ./out --format esm
```
{% /codetabs %} -->
-### `bundling`
+<!-- ### `bundling`
Whether to enable bundling.
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
bundling: true, // default
@@ -337,7 +372,7 @@ Set to `false` to disable bundling. Instead, files will be transpiled and indivi
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
bundling: false,
@@ -348,7 +383,7 @@ Bun.build({
$ bun build ./index.tsx --outdir ./out --no-bundling
```
-{% /codetabs %}
+{% /codetabs %} -->
### `splitting`
@@ -357,7 +392,7 @@ Whether to enable code splitting.
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
splitting: false, // default
@@ -393,7 +428,7 @@ To bundle `entry-a.ts` and `entry-b.ts` with code-splitting enabled:
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./entry-a.ts', './entry-b.ts'],
outdir: './out',
splitting: true,
@@ -429,7 +464,7 @@ A list of plugins to use during bundling.
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
plugins: [/* ... */],
@@ -458,6 +493,7 @@ const result = await Bun.build({
console.log(result.manifest);
```
+The manifest takes the following form:
{% details summary="Manifest structure" %}
The manifest has the following form:
@@ -503,6 +539,8 @@ export type ImportKind =
{% /details %}
+By design, the manifest is a simple JSON object that can easily be serialized or written to disk. It is also compatible with esbuild's [`metafile`](https://esbuild.github.io/api/#metafile) format.
+
### `sourcemap`
Specifies the type of sourcemap to generate.
@@ -510,7 +548,7 @@ Specifies the type of sourcemap to generate.
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
sourcemap: "inline", // default "none"
@@ -544,12 +582,18 @@ $ bun build ./index.tsx --outdir ./out --sourcemap=inline
### `minify`
-Whether to enable minification. Default `false`. To enable minification:
+Whether to enable minification. Default `false`.
+
+{% callout %}
+When targeting `bun`, identifiers will be minified by default.
+{% /callout %}
+
+To enable all minification options:
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: true, // default false
@@ -562,12 +606,12 @@ $ bun build ./index.tsx --outdir ./out --minify
{% /codetabs %}
-This will enable all minification options. To granularly enable certain minifications:
+To granularly enable certain minifications:
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: {
@@ -595,7 +639,7 @@ A list of import paths to consider _external_. Defaults to `[]`.
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ["lodash", "react"], // default: []
@@ -618,7 +662,6 @@ import {z} from "zod";
const value = z.string().parse("Hello world!")
console.log(_.upperCase(value));
-
```
Normally, bundling `index.tsx` would generate a bundle containing the entire source code of the `"zod"` package. If instead, we want to leave the `import` statement as-is, we can mark it as external:
@@ -626,7 +669,7 @@ Normally, bundling `index.tsx` would generate a bundle containing the entire sou
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['zod'],
@@ -659,10 +702,10 @@ Customizes the generated file names. Defaults to `./[dir]/[name].[ext]`.
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
- naming: "[dir]/[name].[ext]", // default
+ naming: "./[dir]/[name].[ext]", // default
})
```
@@ -694,12 +737,12 @@ With multiple entrypoints, the generated file hierarchy will reflect the directo
└── index.js
```
-The names of these files can be customized with the `naming` field. This field accepts a template string that is used to generate the filenames for all bundles corresponding to entrypoints. where the following tokens are replaced with their corresponding values:
+The names and locations of the generated files can be customized with the `naming` field. This field accepts a template string that is used to generate the filenames for all bundles corresponding to entrypoints. where the following tokens are replaced with their corresponding values:
-- `[name]` - The name of the entrypoint file, without the extension, e.g. `index`
-- `[ext]` - The extension of the generated bundle, e.g. `js`
-- `[hash]` - A hash of the bundle contents, e.g. `a1b2c3d4`
-- `[dir]` - The relative path from the build [`root`](#root) to the parent directory of the file, e.g. `nested`
+- `[name]` - The name of the entrypoint file, without the extension.
+- `[ext]` - The extension of the generated bundle.
+- `[hash]` - A hash of the bundle contents.
+- `[dir]` - The relative path from the build root to the parent directory of the file.
For example:
@@ -734,10 +777,10 @@ We can combine these tokens to create a template string. For instance, to includ
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
- naming: '[dir]/[name]-[hash].[ext]',
+ naming: 'files/[dir]/[name]-[hash].[ext]',
})
```
@@ -753,7 +796,8 @@ This build would result in the following file structure:
.
├── index.tsx
└── out
- └── index-a1b2c3d4.js
+ └── files
+ └── index-a1b2c3d4.js
```
When a `string` is provided for the `naming` field, it is used only for bundles _that correspond to entrypoints_. The names of [chunks](#splitting) and copied assets are not affected. Using the JavaScript API, separate template strings can be specified for each type of generated file.
@@ -761,7 +805,7 @@ When a `string` is provided for the `naming` field, it is used only for bundles
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: {
@@ -778,14 +822,14 @@ n/a
{% /codetabs %}
-### `root`
+<!-- ### `root`
The root directory of the project.
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./pages/a.tsx', './pages/b.tsx'],
outdir: './out',
root: '.',
@@ -812,7 +856,7 @@ We can build both entrypoints in the `pages` directory:
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
})
@@ -843,7 +887,7 @@ This behavior can be overridden by specifying the `root` option:
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
root: '.',
@@ -867,92 +911,80 @@ By specifying `.` as `root`, the generated file structure will look like this:
└── pages
└── index.js
└── settings.js
-```
+``` -->
-### `origin`
+### `publicPath`
-Used to generate absolute asset URLs.
+A prefix to be appended to any import paths in bundled code.
-{% codetabs %}
-
-```ts#JavaScript
-Bun.build({
- entrypoints: ['./index.tsx'],
- outdir: './out',
- origin: 'https://cdn.example.com', // default is undefined
-})
-```
+<!-- $ bun build ./index.tsx --outdir ./out --publicPath https://cdn.example.com -->
-```bash#CLI
-$ bun build ./index.tsx --outdir ./out --origin https://cdn.example.com
-```
+In many cases, generated bundles will contain no `import` statements. After all, the goal of bundling is to combine all of the code into a single file. However there are a number of cases with the generated bundles will contain `import` statements.
-{% /codetabs %}
+- **Asset imports** — When importing an unrecognized file type like `*.svg`, the bundler defers to the [`file` loader](/docs/bundler/loaders#file), which copies the file into `outdir` as is. The import is converted into a variable
+- **External modules** — Files and modules can be marked as [`external`](#external), in which case they will not be included in the bundle. Instead, the `import` statement will be left in the final bundle.
+- **Chunking**. When [`splitting`](#splitting) is enabled, the bundler may generate separate "chunk" files that represent code that is shared among multiple entrypoints.
-When the bundler encounters an unknown file type, it defaults to using the `"file"` loader. This converts the import path to an absolute URL that can be referenced in the file. This is useful for referencing images, fonts, and other static assets.
+In any of these cases, the final bundles may contain paths to other files. By default these imports are _relative_. Here is an example of a simple asset import:
-```tsx#Input
-import logo from "./images/logo.svg";
+{% codetabs %}
-export function Logo(){
- return <img src={logo} />
-}
+```ts#Input
+import logo from './logo.svg';
+console.log(logo);
```
-In the absence of a plugin that overrides `*.svg` loading, the `logo` import will be converted to a relative path:
-
-```ts
-var logo = "./logo.svg";
-
+```ts#Output
+// logo.svg is copied into <outdir>
+// and hash is added to the filename to prevent collisions
+var logo = './logo-a7305bdef.svg';
console.log(logo);
```
-This is fine for local development, but in production, we may want these imports to correspond to absolute URLs. To do this, we can specify the `origin` option:
+{% /codetabs %}
+
+Setting `publicPath` will prefix all file paths with the specified value.
{% codetabs %}
```ts#JavaScript
-Bun.build({
+await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
- origin: 'https://cdn.mydomain.com',
+ publicPath: 'https://cdn.example.com/', // default is undefined
})
```
```bash#CLI
-$ bun build ./index.tsx --outdir ./out --origin https://cdn.mydomain.com
+n/a
```
{% /codetabs %}
-With `origin` set to this value, the generated bundle will now be something like this:
+The output file would now look something like this.
-```ts-diff
-- var logo = "./logo.svg";
-+ var logo = "https://cdn.mydomain.com/logo.svg";
-
-console.log(logo);
+```ts-diff#Output
+- var logo = './logo-a7305bdef.svg';
++ var logo = 'https://cdn.example.com/logo-a7305bdef.svg';
```
## Reference
```ts
-Bun.build({
+await Bun.build({
entrypoints: string[]; // list of file path
- outdir: string; // output directory
+ outdir?: string; // output directory
target?: "browser" | "bun" | "node"; // default: "browser"
- bundling?: boolean, // default: false, transform instead of bundling
splitting?: boolean, // default true, enable code splitting
plugins?: BunPlugin[];
manifest?: boolean; // whether to return manifest
- external?: Array<string | RegExp>;
+ external?: Array<string>;
naming?: string | {
entrypoint?: string;
chunk?: string;
asset?: string;
}, // default './[dir]/[name].[ext]'
- root?: string; // project root
- origin?: string; // e.g. http://mydomain.com
+ publicPath?: string; // e.g. http://mydomain.com/
minify?: boolean | {
identifiers?: boolean;
whitespace?: boolean;
@@ -962,7 +994,8 @@ Bun.build({
```
<!--
-module?: "esm"; // later: "cjs", "iife"
+root?: string; // project root
+format?: "esm"; // later: "cjs", "iife"
loader?: { [k in string]: Loader };
sourcemap?: "none" | "inline" | "external"; // default: "none"
treeshaking?: boolean;
diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts
index ce7894b4e..14b9d3a38 100644
--- a/packages/bun-types/bun.d.ts
+++ b/packages/bun-types/bun.d.ts
@@ -966,23 +966,23 @@ declare module "bun" {
interface BuildConfig {
entrypoints: string[]; // list of file path
- target?: Target; // default: "browser"
- // module?: ModuleFormat; // later: "cjs", "iife"
outdir?: string; // output directory
+ target?: Target; // default: "browser"
+ // format?: ModuleFormat; // later: "cjs", "iife"
- naming?: {
- chunk?: string;
- entrypoint?: string;
- asset?: string;
- }; // | string;
+ naming?:
+ | string
+ | {
+ chunk?: string;
+ entrypoint?: string;
+ asset?: string;
+ }; // | string;
// root?: string; // project root
- // transform?: boolean; // default: false, transform instead of bundling
splitting?: boolean; // default true, enable code splitting
- bundling?: boolean; // default true, enable bundling
plugins?: BunPlugin[];
// manifest?: boolean; // whether to return manifest
external?: Array<string>;
- publicPath: string;
+ publicPath?: string;
// origin?: string; // e.g. http://mydomain.com
// loaders?: { [k in string]: Loader };
// sourcemap?: "none" | "inline" | "external"; // default: "none"
diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig
index 50160f1dc..eae4da646 100644
--- a/src/bun.js/api/JSBundler.zig
+++ b/src/bun.js/api/JSBundler.zig
@@ -167,23 +167,34 @@ pub const JSBundler = struct {
this.public_path.appendSliceExact(slice.slice()) catch unreachable;
}
- if (try config.getObject(globalThis, "naming")) |naming| {
- if (try naming.getOptional(globalThis, "entrypoint", ZigString.Slice)) |slice| {
- defer slice.deinit();
- this.names.owned_entry_point.appendSliceExact(slice.slice()) catch unreachable;
- this.names.entry_point.data = this.names.owned_entry_point.list.items;
- }
+ if (config.getTruthy(globalThis, "naming")) |naming| {
+ if (naming.isString()) {
+ if (try config.getOptional(globalThis, "naming", ZigString.Slice)) |slice| {
+ defer slice.deinit();
+ this.names.owned_entry_point.appendSliceExact(slice.slice()) catch unreachable;
+ this.names.entry_point.data = this.names.owned_entry_point.list.items;
+ }
+ } else if (naming.isObject()) {
+ if (try naming.getOptional(globalThis, "entrypoint", ZigString.Slice)) |slice| {
+ defer slice.deinit();
+ this.names.owned_entry_point.appendSliceExact(slice.slice()) catch unreachable;
+ this.names.entry_point.data = this.names.owned_entry_point.list.items;
+ }
- if (try naming.getOptional(globalThis, "chunk", ZigString.Slice)) |slice| {
- defer slice.deinit();
- this.names.owned_chunk.appendSliceExact(slice.slice()) catch unreachable;
- this.names.chunk.data = this.names.owned_chunk.list.items;
- }
+ if (try naming.getOptional(globalThis, "chunk", ZigString.Slice)) |slice| {
+ defer slice.deinit();
+ this.names.owned_chunk.appendSliceExact(slice.slice()) catch unreachable;
+ this.names.chunk.data = this.names.owned_chunk.list.items;
+ }
- if (try naming.getOptional(globalThis, "asset", ZigString.Slice)) |slice| {
- defer slice.deinit();
- this.names.owned_asset.appendSliceExact(slice.slice()) catch unreachable;
- this.names.asset.data = this.names.owned_asset.list.items;
+ if (try naming.getOptional(globalThis, "asset", ZigString.Slice)) |slice| {
+ defer slice.deinit();
+ this.names.owned_asset.appendSliceExact(slice.slice()) catch unreachable;
+ this.names.asset.data = this.names.owned_asset.list.items;
+ }
+ } else {
+ globalThis.throwInvalidArguments("Expected naming to be a string or an object", .{});
+ return error.JSException;
}
}
diff --git a/src/cli.zig b/src/cli.zig
index 142ab06e3..86dce4dca 100644
--- a/src/cli.zig
+++ b/src/cli.zig
@@ -162,7 +162,7 @@ pub const Arguments = struct {
clap.parseParam("-d, --define <STR>... Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:\"development\". Values are parsed as JSON.") catch unreachable,
clap.parseParam("-e, --external <STR>... Exclude module from transpilation (can use * wildcards). ex: -e react") catch unreachable,
clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
- clap.parseParam("-l, --loader <STR>... Parse files with .ext:loader, e.g. --loader .js:jsx. Valid loaders: jsx, js, json, tsx, ts, css") catch unreachable,
+ clap.parseParam("-l, --loader <STR>... Parse files with .ext:loader, e.g. --loader .js:jsx. Valid loaders: js, jsx, ts, tsx, json, toml, text, file, wasm, napi") catch unreachable,
clap.parseParam("-u, --origin <STR> Rewrite import URLs to start with --origin. Default: \"\"") catch unreachable,
clap.parseParam("-p, --port <STR> Port to serve bun's dev server on. Default: \"3000\"") catch unreachable,
clap.parseParam("--minify Minify (experimental)") catch unreachable,