feat: new bun_build and bun_compile, extend bun_install

This commit is contained in:
eric
2026-03-15 00:11:55 +01:00
parent c446f23a35
commit a0bc998bd2
58 changed files with 1845 additions and 191 deletions

43
MODULE.bazel.lock generated
View File

@@ -34,8 +34,9 @@
"https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9",
"https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87",
"https://bcr.bazel.build/modules/bazel_features/1.33.0/MODULE.bazel": "8b8dc9d2a4c88609409c3191165bccec0e4cb044cd7a72ccbe826583303459f6",
"https://bcr.bazel.build/modules/bazel_features/1.33.0/source.json": "13617db3930328c2cd2807a0f13d52ca870ac05f96db9668655113265147b2a6",
"https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7",
"https://bcr.bazel.build/modules/bazel_features/1.42.1/MODULE.bazel": "275a59b5406ff18c01739860aa70ad7ccb3cfb474579411decca11c93b951080",
"https://bcr.bazel.build/modules/bazel_features/1.42.1/source.json": "fcd4396b2df85f64f2b3bb436ad870793ecf39180f1d796f913cc9276d355309",
"https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a",
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
"https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e",
@@ -51,8 +52,8 @@
"https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.2/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.2/source.json": "34a3c8bcf233b835eb74be9d628899bb32999d3e0eadef1947a0a562a2b16ffb",
"https://bcr.bazel.build/modules/buildozer/8.2.1/MODULE.bazel": "61e9433c574c2bd9519cad7fa66b9c1d2b8e8d5f3ae5d6528a2c2d26e68d874d",
"https://bcr.bazel.build/modules/buildozer/8.2.1/source.json": "7c33f6a26ee0216f85544b4bca5e9044579e0219b6898dd653f5fb449cf2e484",
"https://bcr.bazel.build/modules/buildozer/8.5.1/MODULE.bazel": "a35d9561b3fc5b18797c330793e99e3b834a473d5fbd3d7d7634aafc9bdb6f8f",
"https://bcr.bazel.build/modules/buildozer/8.5.1/source.json": "e3386e6ff4529f2442800dee47ad28d3e6487f36a1f75ae39ae56c70f0cd2fbd",
"https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb",
"https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6",
@@ -112,8 +113,8 @@
"https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8",
"https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c",
"https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": "eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37",
"https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8",
"https://bcr.bazel.build/modules/rules_cc/0.2.14/source.json": "55d0a4587c5592fad350f6e698530f4faf0e7dd15e69d43f8d87e220c78bea54",
"https://bcr.bazel.build/modules/rules_cc/0.2.17/MODULE.bazel": "1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84",
"https://bcr.bazel.build/modules/rules_cc/0.2.17/source.json": "3832f45d145354049137c0090df04629d9c2b5493dc5c2bf46f1834040133a07",
"https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642",
"https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
@@ -192,7 +193,7 @@
"moduleExtensions": {
"//bun:extensions.bzl%bun": {
"general": {
"bzlTransitiveDigest": "mWoMIEcKvXURFuMv68yk2TPrpNykLSLygedENme3WrQ=",
"bzlTransitiveDigest": "lzOUyaXDbkH922ruNkkwEF2cnI4m0XpzrOti0qypwtA=",
"usagesDigest": "/0BcCMA6AOzLhQaRK6DquxrCfpPHJUjSUaFz4zmQrsM=",
"recordedInputs": [
"REPO_MAPPING:,bazel_tools bazel_tools"
@@ -218,6 +219,26 @@
"build_file_content": "\nexports_files([\"bun-linux-aarch64/bun\"])\n\nfilegroup(\n name = \"bun\",\n srcs = [\"bun-linux-aarch64/bun\"],\n visibility = [\"//visibility:public\"],\n)\n"
}
},
"bun_linux_x64_musl": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"urls": [
"https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-x64-musl.zip"
],
"sha256": "48a6c32277d343db0148ce066336472ffd380358a4d26bb1329714742492d824",
"build_file_content": "\nexports_files([\"bun-linux-x64-musl/bun\"])\n\nfilegroup(\n name = \"bun\",\n srcs = [\"bun-linux-x64-musl/bun\"],\n visibility = [\"//visibility:public\"],\n)\n"
}
},
"bun_linux_aarch64_musl": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"urls": [
"https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-linux-aarch64-musl.zip"
],
"sha256": "d2c81365a2e529b78a42330d3a0056e8dbd7896b4a6782c8e392b6532141e34d",
"build_file_content": "\nexports_files([\"bun-linux-aarch64-musl/bun\"])\n\nfilegroup(\n name = \"bun\",\n srcs = [\"bun-linux-aarch64-musl/bun\"],\n visibility = [\"//visibility:public\"],\n)\n"
}
},
"bun_darwin_x64": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
@@ -247,6 +268,16 @@
"sha256": "7a77b3e245e2e26965c93089a4a1332e8a326d3364c89fae1d1fd99cdd3cd73d",
"build_file_content": "\nexports_files([\"bun-windows-x64/bun.exe\"])\n\nfilegroup(\n name = \"bun\",\n srcs = [\"bun-windows-x64/bun.exe\"],\n visibility = [\"//visibility:public\"],\n)\n"
}
},
"bun_windows_aarch64": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"urls": [
"https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-windows-aarch64.zip"
],
"sha256": "6822f3aa7bd2be40fb94c194a1185aae1c6fade54ca4fc2efdc722e37f3257d2",
"build_file_content": "\nexports_files([\"bun-windows-aarch64/bun.exe\"])\n\nfilegroup(\n name = \"bun\",\n srcs = [\"bun-windows-aarch64/bun.exe\"],\n visibility = [\"//visibility:public\"],\n)\n"
}
}
}
}

View File

@@ -1,7 +1,7 @@
# Bun rules for [Bazel](https://bazel.build)
`rules_bun` provides Bazel rules for running, testing, bundling, and developing
JavaScript and TypeScript code with Bun.
`rules_bun` provides Bazel rules for running, testing, building, compiling,
bundling, and developing JavaScript and TypeScript code with Bun.
## Repository layout
@@ -29,6 +29,8 @@ The public entrypoint for rule authors and users is `@rules_bun//bun:defs.bzl`.
`rules_bun` exports these primary rules:
- `bun_binary`
- `bun_build`
- `bun_compile`
- `bun_bundle`
- `bun_dev`
- `bun_script`
@@ -70,9 +72,12 @@ use_repo(
bun_ext,
"bun_linux_x64",
"bun_linux_aarch64",
"bun_linux_x64_musl",
"bun_linux_aarch64_musl",
"bun_darwin_x64",
"bun_darwin_aarch64",
"bun_windows_x64",
"bun_windows_aarch64",
)
register_toolchains(
@@ -155,6 +160,8 @@ bun_register_toolchains()
load(
"@rules_bun//bun:defs.bzl",
"bun_binary",
"bun_build",
"bun_compile",
"bun_bundle",
"bun_dev",
"bun_script",
@@ -194,6 +201,32 @@ When `node_modules` is provided, executables from `node_modules/.bin` are added
to `PATH`. This label typically comes from `bun_install`, which still produces a
standard `node_modules/` directory.
### `bun_build` and `bun_compile`
Use `bun_build` for general-purpose `bun build` output directories and
`bun_compile` for standalone executables built with `bun build --compile`.
```starlark
load("@rules_bun//bun:defs.bzl", "bun_build", "bun_compile")
bun_build(
name = "site",
entry_points = ["src/index.html"],
data = glob(["src/**"]),
splitting = True,
metafile = True,
)
bun_compile(
name = "cli",
entry_point = "src/cli.ts",
)
```
`bun_build` exposes a directory output so Bun can emit HTML, CSS, assets, and
split chunks. `bun_compile` produces a single executable artifact and supports
explicit cross-compilation via `compile_executable`.
### `bun_dev` for local development
Use `bun_dev` for long-running watch or hot-reload development targets.

View File

@@ -35,7 +35,9 @@ bzl_library(
visibility = ["//visibility:public"],
deps = [
":toolchain_bzl",
"//internal:bun_build_support_bzl",
"//internal:bun_binary_bzl",
"//internal:bun_compile_bzl",
"//internal:bun_bundle_bzl",
"//internal:bun_dev_bzl",
"//internal:bun_script_bzl",

View File

@@ -1,4 +1,5 @@
"""Public API surface for Bun Bazel rules."""
load("//internal:bun_compile.bzl", _bun_build = "bun_build", _bun_compile = "bun_compile")
load("//internal:bun_binary.bzl", _bun_binary = "bun_binary")
load("//internal:bun_bundle.bzl", _bun_bundle = "bun_bundle")
load("//internal:bun_dev.bzl", _bun_dev = "bun_dev")
@@ -11,6 +12,8 @@ load(":toolchain.bzl", _BunToolchainInfo = "BunToolchainInfo", _bun_toolchain =
visibility("public")
bun_binary = _bun_binary
bun_build = _bun_build
bun_compile = _bun_compile
bun_bundle = _bun_bundle
bun_dev = _bun_dev
bun_script = _bun_script

View File

@@ -13,6 +13,16 @@ _BUN_ARCHIVES = {
"asset": "bun-linux-aarch64.zip",
"binary": "bun-linux-aarch64/bun",
},
"bun_linux_x64_musl": {
"sha256": "48a6c32277d343db0148ce066336472ffd380358a4d26bb1329714742492d824",
"asset": "bun-linux-x64-musl.zip",
"binary": "bun-linux-x64-musl/bun",
},
"bun_linux_aarch64_musl": {
"sha256": "d2c81365a2e529b78a42330d3a0056e8dbd7896b4a6782c8e392b6532141e34d",
"asset": "bun-linux-aarch64-musl.zip",
"binary": "bun-linux-aarch64-musl/bun",
},
"bun_darwin_x64": {
"sha256": "c1d90bf6140f20e572c473065dc6b37a4b036349b5e9e4133779cc642ad94323",
"asset": "bun-darwin-x64.zip",
@@ -28,6 +38,11 @@ _BUN_ARCHIVES = {
"asset": "bun-windows-x64.zip",
"binary": "bun-windows-x64/bun.exe",
},
"bun_windows_aarch64": {
"sha256": "6822f3aa7bd2be40fb94c194a1185aae1c6fade54ca4fc2efdc722e37f3257d2",
"asset": "bun-windows-aarch64.zip",
"binary": "bun-windows-aarch64/bun.exe",
},
}
_BUN_GITHUB_RELEASE_URL_TEMPLATE = "https://github.com/oven-sh/bun/releases/download/bun-v{}/{}"
@@ -62,6 +77,12 @@ _install = tag_class(
"bun_lockfile": attr.label(mandatory = True),
"install_inputs": attr.label_list(allow_files = True),
"isolated_home": attr.bool(default = True),
"production": attr.bool(default = False),
"omit": attr.string_list(),
"linker": attr.string(),
"backend": attr.string(),
"ignore_scripts": attr.bool(default = False),
"install_flags": attr.string_list(),
},
)
@@ -75,6 +96,12 @@ def _bun_install_impl(ctx):
bun_lockfile = install.bun_lockfile,
install_inputs = install.install_inputs,
isolated_home = install.isolated_home,
production = install.production,
omit = install.omit,
linker = install.linker,
backend = install.backend,
ignore_scripts = install.ignore_scripts,
install_flags = install.install_flags,
visible_repo_name = install.name,
)

View File

@@ -12,6 +12,16 @@ _BUN_ARCHIVES = {
"asset": "bun-linux-aarch64.zip",
"binary": "bun-linux-aarch64/bun",
},
"bun_linux_x64_musl": {
"sha256": "48a6c32277d343db0148ce066336472ffd380358a4d26bb1329714742492d824",
"asset": "bun-linux-x64-musl.zip",
"binary": "bun-linux-x64-musl/bun",
},
"bun_linux_aarch64_musl": {
"sha256": "d2c81365a2e529b78a42330d3a0056e8dbd7896b4a6782c8e392b6532141e34d",
"asset": "bun-linux-aarch64-musl.zip",
"binary": "bun-linux-aarch64-musl/bun",
},
"bun_darwin_x64": {
"sha256": "c1d90bf6140f20e572c473065dc6b37a4b036349b5e9e4133779cc642ad94323",
"asset": "bun-darwin-x64.zip",
@@ -27,6 +37,11 @@ _BUN_ARCHIVES = {
"asset": "bun-windows-x64.zip",
"binary": "bun-windows-x64/bun.exe",
},
"bun_windows_aarch64": {
"sha256": "6822f3aa7bd2be40fb94c194a1185aae1c6fade54ca4fc2efdc722e37f3257d2",
"asset": "bun-windows-aarch64.zip",
"binary": "bun-windows-aarch64/bun.exe",
},
}
_BUN_GITHUB_RELEASE_URL_TEMPLATE = "https://github.com/oven-sh/bun/releases/download/bun-v{}/{}"

View File

@@ -8,6 +8,8 @@ stardoc(
input = "//bun:defs.bzl",
symbol_names = [
"bun_binary",
"bun_build",
"bun_compile",
"bun_bundle",
"bun_dev",
"bun_script",
@@ -19,5 +21,4 @@ stardoc(
"ts_library",
],
deps = ["//bun:defs_bzl"],
target_compatible_with = ["@platforms//os:linux"],
)

View File

@@ -29,6 +29,8 @@ bun_install_ext.install(
name = "bun_deps",
package_json = "//:package.json",
bun_lockfile = "//:bun.lock",
production = True,
omit = ["peer"],
)
use_repo(bun_install_ext, "bun_deps")
@@ -113,6 +115,45 @@ repository root.
- `False`: lets Bun use the host `HOME`, which can improve repeated-install
performance when Bun's cache is home-scoped
### `production`
Optional boolean controlling whether Bun installs only production dependencies.
Example:
```starlark
production = True
```
### `omit`
Optional list of dependency groups to omit, forwarded as repeated
`--omit` flags. Common values are `dev`, `optional`, and `peer`.
### `linker`
Optional Bun linker strategy, forwarded as `--linker`.
Common values:
- `isolated`
- `hoisted`
### `backend`
Optional Bun install backend, forwarded as `--backend`.
Examples include `hardlink`, `symlink`, and `copyfile`.
### `ignore_scripts`
Optional boolean controlling whether Bun skips lifecycle scripts in the project
manifest.
### `install_flags`
Optional list of additional raw flags forwarded to `bun install`.
## Notes
- `bun_install` runs Bun, not npm.

View File

@@ -36,9 +36,12 @@ use_repo(
bun_ext,
"bun_linux_x64",
"bun_linux_aarch64",
"bun_linux_x64_musl",
"bun_linux_aarch64_musl",
"bun_darwin_x64",
"bun_darwin_aarch64",
"bun_windows_x64",
"bun_windows_aarch64",
)
register_toolchains(
@@ -79,6 +82,12 @@ bun_script(
`bun_script` runs from the package directory by default and adds
`node_modules/.bin` to `PATH`.
## Build and compile
Use `bun_build` when Bun may emit a directory of outputs such as HTML, CSS,
chunks, and static assets. Use `bun_compile` for standalone executables created
with `bun build --compile`.
## Regeneration
The rule reference is generated from the public Starlark symbols in

View File

@@ -1,135 +1,484 @@
# rules_bun rule reference
<!-- Generated with Stardoc: http://skydoc.bazel.build -->
This file documents the public rules exported from `@rules_bun//bun:defs.bzl`.
Public API surface for Bun Bazel rules.
## js_binary
Runs a JS/TS entry point with Bun behind a `rules_js`-style name.
Attributes:
- `entry_point` (label, required): path to the main JS/TS file to execute.
- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install` or `npm_translate_lock`, made available in runfiles.
- `data` (label_list, optional): additional runtime files.
- `deps` (label_list, optional): library dependencies required by the program.
- `args` (string_list, optional): default arguments appended before command-line arguments passed to the binary.
- `working_dir` (string, default: `"workspace"`, values: `"workspace" | "entry_point"`): runtime working directory.
## js_test
Runs Bun tests behind a `rules_js`-style name.
Attributes:
- `srcs` (label_list, required): test source files passed to `bun test`.
- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install` or `npm_translate_lock`, made available in runfiles.
- `deps` (label_list, optional): library dependencies required by tests.
- `data` (label_list, optional): additional runtime files needed by tests.
- `args` (string_list, optional): default arguments appended after the test source list.
## js_run_devserver
Runs an executable target from a staged JS workspace.
Attributes:
- `tool` (label, required): executable target to launch as the dev server.
- `args` (string_list, optional): default arguments appended before command-line arguments passed to the dev server.
- `package_json` (label, optional): package manifest used to resolve the package working directory.
- `package_dir_hint` (string, default: `"."`): package-relative directory hint when `package_json` is omitted.
- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install` or `npm_translate_lock`, made available in runfiles.
- `deps` (label_list, optional): library dependencies required by the dev server.
- `data` (label_list, optional): additional runtime files.
- `working_dir` (string, default: `"workspace"`, values: `"workspace" | "package"`): runtime working directory.
<a id="bun_binary"></a>
## bun_binary
Runs a JS/TS entry point with Bun as an executable target (`bazel run`).
<pre>
load("@rules_bun//bun:defs.bzl", "bun_binary")
Attributes:
bun_binary(<a href="#bun_binary-name">name</a>, <a href="#bun_binary-deps">deps</a>, <a href="#bun_binary-data">data</a>, <a href="#bun_binary-conditions">conditions</a>, <a href="#bun_binary-entry_point">entry_point</a>, <a href="#bun_binary-env_files">env_files</a>, <a href="#bun_binary-install_mode">install_mode</a>, <a href="#bun_binary-no_env_file">no_env_file</a>,
<a href="#bun_binary-node_modules">node_modules</a>, <a href="#bun_binary-preload">preload</a>, <a href="#bun_binary-run_flags">run_flags</a>, <a href="#bun_binary-smol">smol</a>, <a href="#bun_binary-working_dir">working_dir</a>)
</pre>
- `entry_point` (label, required): path to the main JS/TS file to execute.
- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install`, made available in runfiles.
- `data` (label_list, optional): additional runtime files.
- `deps` (label_list, optional): library dependencies required by the program.
- `args` (string_list, optional): default arguments appended before command-line arguments passed to the binary.
- `working_dir` (string, default: `"workspace"`, values: `"workspace" | "entry_point"`): runtime working directory.
Runs a JS/TS entry point with Bun as an executable target.
## bun_dev
Use this rule for non-test scripts and CLIs that should run via `bazel run`.
Runs a JS/TS entry point in Bun development watch mode (`bazel run`).
**ATTRIBUTES**
Attributes:
- `entry_point` (label, required): path to the main JS/TS file.
- `watch_mode` (string, default: `"watch"`, values: `"watch" | "hot"`): Bun live-reload mode.
- `restart_on` (label_list, optional): files that trigger full process restart when changed.
- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install`, made available in runfiles.
- `data` (label_list, optional): additional runtime files for dev process.
- `working_dir` (string, default: `"workspace"`, values: `"workspace" | "entry_point"`): runtime working directory.
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="bun_binary-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="bun_binary-deps"></a>deps | Library dependencies required by the program. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_binary-data"></a>data | Additional runtime files required by the program. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_binary-conditions"></a>conditions | Custom package resolve conditions passed to Bun. | List of strings | optional | `[]` |
| <a id="bun_binary-entry_point"></a>entry_point | Path to the main JS/TS file to execute. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="bun_binary-env_files"></a>env_files | Additional environment files loaded with `--env-file`. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_binary-install_mode"></a>install_mode | Whether Bun may auto-install missing packages at runtime. | String | optional | `"disable"` |
| <a id="bun_binary-no_env_file"></a>no_env_file | If true, disables Bun's automatic `.env` loading. | Boolean | optional | `False` |
| <a id="bun_binary-node_modules"></a>node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="bun_binary-preload"></a>preload | Modules to preload with `--preload` before running the entry point. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_binary-run_flags"></a>run_flags | Additional raw flags forwarded to `bun run` before the entry point. | List of strings | optional | `[]` |
| <a id="bun_binary-smol"></a>smol | If true, enables Bun's lower-memory runtime mode. | Boolean | optional | `False` |
| <a id="bun_binary-working_dir"></a>working_dir | Working directory at runtime: `workspace` root or nearest `entry_point` ancestor containing `.env`/`package.json`. | String | optional | `"workspace"` |
## bun_script
Runs a named `package.json` script with Bun as an executable target (`bazel run`).
<a id="bun_build"></a>
Recommended for package-script based tools such as Vite (`dev`, `build`, `preview`).
When `node_modules` is provided, executables from `node_modules/.bin` are added
to `PATH`, so scripts like `vite` work without wrapper scripts.
## bun_build
Attributes:
<pre>
load("@rules_bun//bun:defs.bzl", "bun_build")
- `script` (string, required): package script name passed to `bun run <script>`.
- `package_json` (label, required): `package.json` file containing the named script.
- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install`, made available in runfiles.
- `data` (label_list, optional): additional runtime files for the script.
- `working_dir` (string, default: `"package"`, values: `"workspace" | "package"`): runtime working directory. The default is a good fit for Vite and similar package-script based tools.
bun_build(<a href="#bun_build-name">name</a>, <a href="#bun_build-deps">deps</a>, <a href="#bun_build-data">data</a>, <a href="#bun_build-asset_naming">asset_naming</a>, <a href="#bun_build-banner">banner</a>, <a href="#bun_build-build_flags">build_flags</a>, <a href="#bun_build-chunk_naming">chunk_naming</a>, <a href="#bun_build-conditions">conditions</a>,
<a href="#bun_build-css_chunking">css_chunking</a>, <a href="#bun_build-define">define</a>, <a href="#bun_build-drop">drop</a>, <a href="#bun_build-emit_dce_annotations">emit_dce_annotations</a>, <a href="#bun_build-entry_naming">entry_naming</a>, <a href="#bun_build-entry_points">entry_points</a>, <a href="#bun_build-env">env</a>, <a href="#bun_build-external">external</a>,
<a href="#bun_build-feature">feature</a>, <a href="#bun_build-footer">footer</a>, <a href="#bun_build-format">format</a>, <a href="#bun_build-install_mode">install_mode</a>, <a href="#bun_build-jsx_factory">jsx_factory</a>, <a href="#bun_build-jsx_fragment">jsx_fragment</a>, <a href="#bun_build-jsx_import_source">jsx_import_source</a>,
<a href="#bun_build-jsx_runtime">jsx_runtime</a>, <a href="#bun_build-jsx_side_effects">jsx_side_effects</a>, <a href="#bun_build-keep_names">keep_names</a>, <a href="#bun_build-loader">loader</a>, <a href="#bun_build-metafile">metafile</a>, <a href="#bun_build-metafile_md">metafile_md</a>, <a href="#bun_build-minify">minify</a>,
<a href="#bun_build-minify_identifiers">minify_identifiers</a>, <a href="#bun_build-minify_syntax">minify_syntax</a>, <a href="#bun_build-minify_whitespace">minify_whitespace</a>, <a href="#bun_build-no_bundle">no_bundle</a>, <a href="#bun_build-node_modules">node_modules</a>, <a href="#bun_build-packages">packages</a>,
<a href="#bun_build-production">production</a>, <a href="#bun_build-public_path">public_path</a>, <a href="#bun_build-react_fast_refresh">react_fast_refresh</a>, <a href="#bun_build-root">root</a>, <a href="#bun_build-sourcemap">sourcemap</a>, <a href="#bun_build-splitting">splitting</a>, <a href="#bun_build-target">target</a>)
</pre>
Builds one or more entry points with `bun build`.
The rule emits a directory artifact so Bun can materialize multi-file output
graphs such as HTML, CSS, assets, and split chunks. Optional metafile outputs
may be requested with `metafile` and `metafile_md`.
**ATTRIBUTES**
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="bun_build-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="bun_build-deps"></a>deps | Source/library dependencies that provide transitive inputs. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_build-data"></a>data | Additional non-source files needed during building. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_build-asset_naming"></a>asset_naming | Optional asset naming template. | String | optional | `""` |
| <a id="bun_build-banner"></a>banner | Optional bundle banner text. | String | optional | `""` |
| <a id="bun_build-build_flags"></a>build_flags | Additional raw flags forwarded to `bun build`. | List of strings | optional | `[]` |
| <a id="bun_build-chunk_naming"></a>chunk_naming | Optional chunk naming template. | String | optional | `""` |
| <a id="bun_build-conditions"></a>conditions | Custom resolve conditions passed to Bun. | List of strings | optional | `[]` |
| <a id="bun_build-css_chunking"></a>css_chunking | If true, Bun chunks CSS across multiple entry points. | Boolean | optional | `False` |
| <a id="bun_build-define"></a>define | Repeated `--define` values such as `process.env.NODE_ENV:"production"`. | List of strings | optional | `[]` |
| <a id="bun_build-drop"></a>drop | Repeated `--drop` values, for example `console`. | List of strings | optional | `[]` |
| <a id="bun_build-emit_dce_annotations"></a>emit_dce_annotations | If true, re-emits DCE annotations in the bundle. | Boolean | optional | `False` |
| <a id="bun_build-entry_naming"></a>entry_naming | Optional entry naming template. | String | optional | `""` |
| <a id="bun_build-entry_points"></a>entry_points | Entry files to build, including JS/TS or HTML entry points. | <a href="https://bazel.build/concepts/labels">List of labels</a> | required | |
| <a id="bun_build-env"></a>env | Inline environment variable behavior passed to `--env`. | String | optional | `""` |
| <a id="bun_build-external"></a>external | Modules treated as externals (not bundled). | List of strings | optional | `[]` |
| <a id="bun_build-feature"></a>feature | Repeated `--feature` values for dead-code elimination. | List of strings | optional | `[]` |
| <a id="bun_build-footer"></a>footer | Optional bundle footer text. | String | optional | `""` |
| <a id="bun_build-format"></a>format | Output module format. | String | optional | `"esm"` |
| <a id="bun_build-install_mode"></a>install_mode | Whether Bun may auto-install missing packages while executing the build. | String | optional | `"disable"` |
| <a id="bun_build-jsx_factory"></a>jsx_factory | Optional JSX factory override. | String | optional | `""` |
| <a id="bun_build-jsx_fragment"></a>jsx_fragment | Optional JSX fragment override. | String | optional | `""` |
| <a id="bun_build-jsx_import_source"></a>jsx_import_source | Optional JSX import source override. | String | optional | `""` |
| <a id="bun_build-jsx_runtime"></a>jsx_runtime | Optional JSX runtime override. | String | optional | `""` |
| <a id="bun_build-jsx_side_effects"></a>jsx_side_effects | If true, treats JSX as having side effects. | Boolean | optional | `False` |
| <a id="bun_build-keep_names"></a>keep_names | If true, preserves function and class names when minifying. | Boolean | optional | `False` |
| <a id="bun_build-loader"></a>loader | Repeated `--loader` values such as `.svg:file`. | List of strings | optional | `[]` |
| <a id="bun_build-metafile"></a>metafile | If true, emits Bun's JSON metafile alongside the output directory. | Boolean | optional | `False` |
| <a id="bun_build-metafile_md"></a>metafile_md | If true, emits Bun's markdown metafile alongside the output directory. | Boolean | optional | `False` |
| <a id="bun_build-minify"></a>minify | If true, enables all Bun minification passes. | Boolean | optional | `False` |
| <a id="bun_build-minify_identifiers"></a>minify_identifiers | If true, minifies identifiers only. | Boolean | optional | `False` |
| <a id="bun_build-minify_syntax"></a>minify_syntax | If true, minifies syntax only. | Boolean | optional | `False` |
| <a id="bun_build-minify_whitespace"></a>minify_whitespace | If true, minifies whitespace only. | Boolean | optional | `False` |
| <a id="bun_build-no_bundle"></a>no_bundle | If true, transpiles without bundling. | Boolean | optional | `False` |
| <a id="bun_build-node_modules"></a>node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, for package resolution. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="bun_build-packages"></a>packages | Whether packages stay bundled or are treated as external. | String | optional | `"bundle"` |
| <a id="bun_build-production"></a>production | If true, sets `NODE_ENV=production` and enables Bun production mode. | Boolean | optional | `False` |
| <a id="bun_build-public_path"></a>public_path | Optional public path prefix for emitted imports. | String | optional | `""` |
| <a id="bun_build-react_fast_refresh"></a>react_fast_refresh | If true, enables Bun's React fast refresh transform. | Boolean | optional | `False` |
| <a id="bun_build-root"></a>root | Optional root directory for multiple entry points. | String | optional | `""` |
| <a id="bun_build-sourcemap"></a>sourcemap | Sourcemap emission mode. | String | optional | `"none"` |
| <a id="bun_build-splitting"></a>splitting | If true, enables code splitting. | Boolean | optional | `False` |
| <a id="bun_build-target"></a>target | Bun build target environment. | String | optional | `"browser"` |
<a id="bun_bundle"></a>
## bun_bundle
Bundles one or more JS/TS entry points with Bun build.
<pre>
load("@rules_bun//bun:defs.bzl", "bun_bundle")
Attributes:
bun_bundle(<a href="#bun_bundle-name">name</a>, <a href="#bun_bundle-deps">deps</a>, <a href="#bun_bundle-data">data</a>, <a href="#bun_bundle-build_flags">build_flags</a>, <a href="#bun_bundle-entry_points">entry_points</a>, <a href="#bun_bundle-external">external</a>, <a href="#bun_bundle-format">format</a>, <a href="#bun_bundle-install_mode">install_mode</a>, <a href="#bun_bundle-minify">minify</a>,
<a href="#bun_bundle-node_modules">node_modules</a>, <a href="#bun_bundle-sourcemap">sourcemap</a>, <a href="#bun_bundle-target">target</a>)
</pre>
- `entry_points` (label_list, required): entry files to bundle.
- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install`, used for package resolution.
- `deps` (label_list, optional): source/library dependencies for transitive inputs.
- `data` (label_list, optional): additional non-source files needed during bundling.
- `target` (string, default: `"browser"`, values: `"browser" | "node" | "bun"`): Bun build target.
- `format` (string, default: `"esm"`, values: `"esm" | "cjs" | "iife"`): module format.
- `minify` (bool, default: `False`): minifies bundle output.
- `sourcemap` (bool, default: `False`): emits source maps.
- `external` (string_list, optional): package names treated as external (not bundled).
Bundles one or more JS/TS entry points using Bun build.
Each entry point produces one output JavaScript artifact.
**ATTRIBUTES**
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="bun_bundle-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="bun_bundle-deps"></a>deps | Source/library dependencies that provide transitive inputs. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_bundle-data"></a>data | Additional non-source files needed during bundling. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_bundle-build_flags"></a>build_flags | Additional raw flags forwarded to `bun build`. | List of strings | optional | `[]` |
| <a id="bun_bundle-entry_points"></a>entry_points | Entry files to bundle. | <a href="https://bazel.build/concepts/labels">List of labels</a> | required | |
| <a id="bun_bundle-external"></a>external | Package names to treat as externals (not bundled). | List of strings | optional | `[]` |
| <a id="bun_bundle-format"></a>format | Output module format. | String | optional | `"esm"` |
| <a id="bun_bundle-install_mode"></a>install_mode | Whether Bun may auto-install missing packages during bundling. | String | optional | `"disable"` |
| <a id="bun_bundle-minify"></a>minify | If true, minifies bundle output. | Boolean | optional | `False` |
| <a id="bun_bundle-node_modules"></a>node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, for package resolution. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="bun_bundle-sourcemap"></a>sourcemap | If true, emits source maps. | Boolean | optional | `False` |
| <a id="bun_bundle-target"></a>target | Bun build target environment. | String | optional | `"browser"` |
<a id="bun_compile"></a>
## bun_compile
<pre>
load("@rules_bun//bun:defs.bzl", "bun_compile")
bun_compile(<a href="#bun_compile-name">name</a>, <a href="#bun_compile-deps">deps</a>, <a href="#bun_compile-data">data</a>, <a href="#bun_compile-asset_naming">asset_naming</a>, <a href="#bun_compile-banner">banner</a>, <a href="#bun_compile-build_flags">build_flags</a>, <a href="#bun_compile-bytecode">bytecode</a>, <a href="#bun_compile-chunk_naming">chunk_naming</a>,
<a href="#bun_compile-compile_autoload_bunfig">compile_autoload_bunfig</a>, <a href="#bun_compile-compile_autoload_dotenv">compile_autoload_dotenv</a>, <a href="#bun_compile-compile_autoload_package_json">compile_autoload_package_json</a>,
<a href="#bun_compile-compile_autoload_tsconfig">compile_autoload_tsconfig</a>, <a href="#bun_compile-compile_exec_argv">compile_exec_argv</a>, <a href="#bun_compile-compile_executable">compile_executable</a>, <a href="#bun_compile-conditions">conditions</a>,
<a href="#bun_compile-css_chunking">css_chunking</a>, <a href="#bun_compile-define">define</a>, <a href="#bun_compile-drop">drop</a>, <a href="#bun_compile-emit_dce_annotations">emit_dce_annotations</a>, <a href="#bun_compile-entry_naming">entry_naming</a>, <a href="#bun_compile-entry_point">entry_point</a>, <a href="#bun_compile-env">env</a>,
<a href="#bun_compile-external">external</a>, <a href="#bun_compile-feature">feature</a>, <a href="#bun_compile-footer">footer</a>, <a href="#bun_compile-format">format</a>, <a href="#bun_compile-install_mode">install_mode</a>, <a href="#bun_compile-jsx_factory">jsx_factory</a>, <a href="#bun_compile-jsx_fragment">jsx_fragment</a>,
<a href="#bun_compile-jsx_import_source">jsx_import_source</a>, <a href="#bun_compile-jsx_runtime">jsx_runtime</a>, <a href="#bun_compile-jsx_side_effects">jsx_side_effects</a>, <a href="#bun_compile-keep_names">keep_names</a>, <a href="#bun_compile-loader">loader</a>, <a href="#bun_compile-minify">minify</a>,
<a href="#bun_compile-minify_identifiers">minify_identifiers</a>, <a href="#bun_compile-minify_syntax">minify_syntax</a>, <a href="#bun_compile-minify_whitespace">minify_whitespace</a>, <a href="#bun_compile-no_bundle">no_bundle</a>, <a href="#bun_compile-node_modules">node_modules</a>, <a href="#bun_compile-packages">packages</a>,
<a href="#bun_compile-production">production</a>, <a href="#bun_compile-public_path">public_path</a>, <a href="#bun_compile-react_fast_refresh">react_fast_refresh</a>, <a href="#bun_compile-root">root</a>, <a href="#bun_compile-sourcemap">sourcemap</a>, <a href="#bun_compile-splitting">splitting</a>, <a href="#bun_compile-target">target</a>,
<a href="#bun_compile-windows_copyright">windows_copyright</a>, <a href="#bun_compile-windows_description">windows_description</a>, <a href="#bun_compile-windows_hide_console">windows_hide_console</a>, <a href="#bun_compile-windows_icon">windows_icon</a>,
<a href="#bun_compile-windows_publisher">windows_publisher</a>, <a href="#bun_compile-windows_title">windows_title</a>, <a href="#bun_compile-windows_version">windows_version</a>)
</pre>
Compiles a Bun program into a standalone executable with `bun build --compile`.
**ATTRIBUTES**
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="bun_compile-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="bun_compile-deps"></a>deps | Source/library dependencies that provide transitive inputs. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_compile-data"></a>data | Additional non-source files needed during building. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_compile-asset_naming"></a>asset_naming | Optional asset naming template. | String | optional | `""` |
| <a id="bun_compile-banner"></a>banner | Optional bundle banner text. | String | optional | `""` |
| <a id="bun_compile-build_flags"></a>build_flags | Additional raw flags forwarded to `bun build`. | List of strings | optional | `[]` |
| <a id="bun_compile-bytecode"></a>bytecode | If true, enables Bun bytecode caching in the compiled executable. | Boolean | optional | `False` |
| <a id="bun_compile-chunk_naming"></a>chunk_naming | Optional chunk naming template. | String | optional | `""` |
| <a id="bun_compile-compile_autoload_bunfig"></a>compile_autoload_bunfig | Whether the compiled executable auto-loads `bunfig.toml` at runtime. | Boolean | optional | `True` |
| <a id="bun_compile-compile_autoload_dotenv"></a>compile_autoload_dotenv | Whether the compiled executable auto-loads `.env` files at runtime. | Boolean | optional | `True` |
| <a id="bun_compile-compile_autoload_package_json"></a>compile_autoload_package_json | Whether the compiled executable auto-loads `package.json` at runtime. | Boolean | optional | `False` |
| <a id="bun_compile-compile_autoload_tsconfig"></a>compile_autoload_tsconfig | Whether the compiled executable auto-loads `tsconfig.json` at runtime. | Boolean | optional | `False` |
| <a id="bun_compile-compile_exec_argv"></a>compile_exec_argv | Repeated `--compile-exec-argv` values prepended to the executable's `execArgv`. | List of strings | optional | `[]` |
| <a id="bun_compile-compile_executable"></a>compile_executable | Optional Bun executable used for cross-compilation via `--compile-executable-path`. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="bun_compile-conditions"></a>conditions | Custom resolve conditions passed to Bun. | List of strings | optional | `[]` |
| <a id="bun_compile-css_chunking"></a>css_chunking | If true, Bun chunks CSS across multiple entry points. | Boolean | optional | `False` |
| <a id="bun_compile-define"></a>define | Repeated `--define` values such as `process.env.NODE_ENV:"production"`. | List of strings | optional | `[]` |
| <a id="bun_compile-drop"></a>drop | Repeated `--drop` values, for example `console`. | List of strings | optional | `[]` |
| <a id="bun_compile-emit_dce_annotations"></a>emit_dce_annotations | If true, re-emits DCE annotations in the bundle. | Boolean | optional | `False` |
| <a id="bun_compile-entry_naming"></a>entry_naming | Optional entry naming template. | String | optional | `""` |
| <a id="bun_compile-entry_point"></a>entry_point | Entry file to compile into an executable. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="bun_compile-env"></a>env | Inline environment variable behavior passed to `--env`. | String | optional | `""` |
| <a id="bun_compile-external"></a>external | Modules treated as externals (not bundled). | List of strings | optional | `[]` |
| <a id="bun_compile-feature"></a>feature | Repeated `--feature` values for dead-code elimination. | List of strings | optional | `[]` |
| <a id="bun_compile-footer"></a>footer | Optional bundle footer text. | String | optional | `""` |
| <a id="bun_compile-format"></a>format | Output module format. | String | optional | `"esm"` |
| <a id="bun_compile-install_mode"></a>install_mode | Whether Bun may auto-install missing packages while executing the build. | String | optional | `"disable"` |
| <a id="bun_compile-jsx_factory"></a>jsx_factory | Optional JSX factory override. | String | optional | `""` |
| <a id="bun_compile-jsx_fragment"></a>jsx_fragment | Optional JSX fragment override. | String | optional | `""` |
| <a id="bun_compile-jsx_import_source"></a>jsx_import_source | Optional JSX import source override. | String | optional | `""` |
| <a id="bun_compile-jsx_runtime"></a>jsx_runtime | Optional JSX runtime override. | String | optional | `""` |
| <a id="bun_compile-jsx_side_effects"></a>jsx_side_effects | If true, treats JSX as having side effects. | Boolean | optional | `False` |
| <a id="bun_compile-keep_names"></a>keep_names | If true, preserves function and class names when minifying. | Boolean | optional | `False` |
| <a id="bun_compile-loader"></a>loader | Repeated `--loader` values such as `.svg:file`. | List of strings | optional | `[]` |
| <a id="bun_compile-minify"></a>minify | If true, enables all Bun minification passes. | Boolean | optional | `False` |
| <a id="bun_compile-minify_identifiers"></a>minify_identifiers | If true, minifies identifiers only. | Boolean | optional | `False` |
| <a id="bun_compile-minify_syntax"></a>minify_syntax | If true, minifies syntax only. | Boolean | optional | `False` |
| <a id="bun_compile-minify_whitespace"></a>minify_whitespace | If true, minifies whitespace only. | Boolean | optional | `False` |
| <a id="bun_compile-no_bundle"></a>no_bundle | If true, transpiles without bundling. | Boolean | optional | `False` |
| <a id="bun_compile-node_modules"></a>node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, for package resolution. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="bun_compile-packages"></a>packages | Whether packages stay bundled or are treated as external. | String | optional | `"bundle"` |
| <a id="bun_compile-production"></a>production | If true, sets `NODE_ENV=production` and enables Bun production mode. | Boolean | optional | `False` |
| <a id="bun_compile-public_path"></a>public_path | Optional public path prefix for emitted imports. | String | optional | `""` |
| <a id="bun_compile-react_fast_refresh"></a>react_fast_refresh | If true, enables Bun's React fast refresh transform. | Boolean | optional | `False` |
| <a id="bun_compile-root"></a>root | Optional root directory for multiple entry points. | String | optional | `""` |
| <a id="bun_compile-sourcemap"></a>sourcemap | Sourcemap emission mode. | String | optional | `"none"` |
| <a id="bun_compile-splitting"></a>splitting | If true, enables code splitting. | Boolean | optional | `False` |
| <a id="bun_compile-target"></a>target | Bun build target environment for the compiled executable. | String | optional | `"bun"` |
| <a id="bun_compile-windows_copyright"></a>windows_copyright | Optional Windows copyright metadata. | String | optional | `""` |
| <a id="bun_compile-windows_description"></a>windows_description | Optional Windows description metadata. | String | optional | `""` |
| <a id="bun_compile-windows_hide_console"></a>windows_hide_console | When targeting Windows, hides the console window for GUI-style executables. | Boolean | optional | `False` |
| <a id="bun_compile-windows_icon"></a>windows_icon | Optional Windows icon path passed directly to Bun. | String | optional | `""` |
| <a id="bun_compile-windows_publisher"></a>windows_publisher | Optional Windows publisher metadata. | String | optional | `""` |
| <a id="bun_compile-windows_title"></a>windows_title | Optional Windows executable title. | String | optional | `""` |
| <a id="bun_compile-windows_version"></a>windows_version | Optional Windows version metadata. | String | optional | `""` |
<a id="bun_dev"></a>
## bun_dev
<pre>
load("@rules_bun//bun:defs.bzl", "bun_dev")
bun_dev(<a href="#bun_dev-name">name</a>, <a href="#bun_dev-data">data</a>, <a href="#bun_dev-conditions">conditions</a>, <a href="#bun_dev-entry_point">entry_point</a>, <a href="#bun_dev-env_files">env_files</a>, <a href="#bun_dev-install_mode">install_mode</a>, <a href="#bun_dev-no_clear_screen">no_clear_screen</a>, <a href="#bun_dev-no_env_file">no_env_file</a>,
<a href="#bun_dev-node_modules">node_modules</a>, <a href="#bun_dev-preload">preload</a>, <a href="#bun_dev-restart_on">restart_on</a>, <a href="#bun_dev-run_flags">run_flags</a>, <a href="#bun_dev-smol">smol</a>, <a href="#bun_dev-watch_mode">watch_mode</a>, <a href="#bun_dev-working_dir">working_dir</a>)
</pre>
Runs a JS/TS entry point in Bun development watch mode.
This rule is intended for local dev loops (`bazel run`) and supports Bun
watch/HMR plus optional full restarts on selected file changes.
**ATTRIBUTES**
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="bun_dev-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="bun_dev-data"></a>data | Additional runtime files required by the dev process. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_dev-conditions"></a>conditions | Custom package resolve conditions passed to Bun. | List of strings | optional | `[]` |
| <a id="bun_dev-entry_point"></a>entry_point | Path to the main JS/TS file to execute in dev mode. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="bun_dev-env_files"></a>env_files | Additional environment files loaded with `--env-file`. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_dev-install_mode"></a>install_mode | Whether Bun may auto-install missing packages in dev mode. | String | optional | `"disable"` |
| <a id="bun_dev-no_clear_screen"></a>no_clear_screen | If true, disables terminal clearing on Bun reloads. | Boolean | optional | `False` |
| <a id="bun_dev-no_env_file"></a>no_env_file | If true, disables Bun's automatic `.env` loading. | Boolean | optional | `False` |
| <a id="bun_dev-node_modules"></a>node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="bun_dev-preload"></a>preload | Modules to preload with `--preload` before running the entry point. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_dev-restart_on"></a>restart_on | Files that trigger a full Bun process restart when they change. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_dev-run_flags"></a>run_flags | Additional raw flags forwarded to `bun run` before the entry point. | List of strings | optional | `[]` |
| <a id="bun_dev-smol"></a>smol | If true, enables Bun's lower-memory runtime mode. | Boolean | optional | `False` |
| <a id="bun_dev-watch_mode"></a>watch_mode | Bun live-reload mode: `watch` (default) or `hot`. | String | optional | `"watch"` |
| <a id="bun_dev-working_dir"></a>working_dir | Working directory at runtime: `workspace` root or nearest `entry_point` ancestor containing `.env`/`package.json`. | String | optional | `"workspace"` |
<a id="bun_script"></a>
## bun_script
<pre>
load("@rules_bun//bun:defs.bzl", "bun_script")
bun_script(<a href="#bun_script-name">name</a>, <a href="#bun_script-data">data</a>, <a href="#bun_script-conditions">conditions</a>, <a href="#bun_script-env_files">env_files</a>, <a href="#bun_script-execution_mode">execution_mode</a>, <a href="#bun_script-filters">filters</a>, <a href="#bun_script-install_mode">install_mode</a>, <a href="#bun_script-no_env_file">no_env_file</a>,
<a href="#bun_script-no_exit_on_error">no_exit_on_error</a>, <a href="#bun_script-node_modules">node_modules</a>, <a href="#bun_script-package_json">package_json</a>, <a href="#bun_script-preload">preload</a>, <a href="#bun_script-run_flags">run_flags</a>, <a href="#bun_script-script">script</a>, <a href="#bun_script-shell">shell</a>, <a href="#bun_script-silent">silent</a>,
<a href="#bun_script-smol">smol</a>, <a href="#bun_script-working_dir">working_dir</a>, <a href="#bun_script-workspaces">workspaces</a>)
</pre>
Runs a named `package.json` script with Bun as an executable target.
Use this rule to expose existing package scripts such as `dev`, `build`, or
`check` via `bazel run` without adding wrapper shell scripts. This is a good fit
for Vite-style workflows, where scripts like `vite dev` or `vite build` are
declared in `package.json` and expect to run from the package directory with
`node_modules/.bin` available on `PATH`.
**ATTRIBUTES**
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="bun_script-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="bun_script-data"></a>data | Additional runtime files required by the script. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_script-conditions"></a>conditions | Custom package resolve conditions passed to Bun. | List of strings | optional | `[]` |
| <a id="bun_script-env_files"></a>env_files | Additional environment files loaded with `--env-file`. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_script-execution_mode"></a>execution_mode | How Bun should execute matching workspace scripts. | String | optional | `"single"` |
| <a id="bun_script-filters"></a>filters | Workspace package filters passed via repeated `--filter` flags. | List of strings | optional | `[]` |
| <a id="bun_script-install_mode"></a>install_mode | Whether Bun may auto-install missing packages while running the script. | String | optional | `"disable"` |
| <a id="bun_script-no_env_file"></a>no_env_file | If true, disables Bun's automatic `.env` loading. | Boolean | optional | `False` |
| <a id="bun_script-no_exit_on_error"></a>no_exit_on_error | If true, Bun keeps running other workspace scripts when one fails. | Boolean | optional | `False` |
| <a id="bun_script-node_modules"></a>node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. Executables from `node_modules/.bin` are added to `PATH`, which is useful for scripts such as `vite`. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="bun_script-package_json"></a>package_json | Label of the `package.json` file containing the named script. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="bun_script-preload"></a>preload | Modules to preload with `--preload` before running the script. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_script-run_flags"></a>run_flags | Additional raw flags forwarded to `bun run` before the script name. | List of strings | optional | `[]` |
| <a id="bun_script-script"></a>script | Name of the `package.json` script to execute via `bun run <script>`. | String | required | |
| <a id="bun_script-shell"></a>shell | Optional shell implementation for package scripts. | String | optional | `""` |
| <a id="bun_script-silent"></a>silent | If true, suppresses Bun's command echo for package scripts. | Boolean | optional | `False` |
| <a id="bun_script-smol"></a>smol | If true, enables Bun's lower-memory runtime mode. | Boolean | optional | `False` |
| <a id="bun_script-working_dir"></a>working_dir | Working directory at runtime: Bazel runfiles `workspace` root or the directory containing `package.json`. The default `package` mode matches tools such as Vite that resolve config and assets relative to the package directory. | String | optional | `"package"` |
| <a id="bun_script-workspaces"></a>workspaces | If true, runs the script in all workspace packages. | Boolean | optional | `False` |
<a id="bun_test"></a>
## bun_test
Runs Bun tests as a Bazel test target (`bazel test`).
<pre>
load("@rules_bun//bun:defs.bzl", "bun_test")
Attributes:
bun_test(<a href="#bun_test-name">name</a>, <a href="#bun_test-deps">deps</a>, <a href="#bun_test-srcs">srcs</a>, <a href="#bun_test-data">data</a>, <a href="#bun_test-bail">bail</a>, <a href="#bun_test-concurrent">concurrent</a>, <a href="#bun_test-coverage">coverage</a>, <a href="#bun_test-coverage_reporters">coverage_reporters</a>, <a href="#bun_test-env_files">env_files</a>,
<a href="#bun_test-install_mode">install_mode</a>, <a href="#bun_test-max_concurrency">max_concurrency</a>, <a href="#bun_test-no_env_file">no_env_file</a>, <a href="#bun_test-node_modules">node_modules</a>, <a href="#bun_test-only">only</a>, <a href="#bun_test-pass_with_no_tests">pass_with_no_tests</a>, <a href="#bun_test-preload">preload</a>,
<a href="#bun_test-randomize">randomize</a>, <a href="#bun_test-reporter">reporter</a>, <a href="#bun_test-rerun_each">rerun_each</a>, <a href="#bun_test-retry">retry</a>, <a href="#bun_test-seed">seed</a>, <a href="#bun_test-smol">smol</a>, <a href="#bun_test-test_flags">test_flags</a>, <a href="#bun_test-timeout_ms">timeout_ms</a>, <a href="#bun_test-todo">todo</a>,
<a href="#bun_test-update_snapshots">update_snapshots</a>)
</pre>
- `srcs` (label_list, required): test source files passed to `bun test`.
- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install`, made available in runfiles.
- `deps` (label_list, optional): library dependencies required by tests.
- `data` (label_list, optional): additional runtime files needed by tests.
- `args` (string_list, optional): default arguments appended after the test source list.
Runs Bun tests as a Bazel test target.
Supports Bazel test filtering (`--test_filter`) and coverage integration.
**ATTRIBUTES**
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="bun_test-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="bun_test-deps"></a>deps | Library dependencies required by test sources. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_test-srcs"></a>srcs | Test source files passed to `bun test`. | <a href="https://bazel.build/concepts/labels">List of labels</a> | required | |
| <a id="bun_test-data"></a>data | Additional runtime files needed by tests. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_test-bail"></a>bail | Optional failure count after which Bun exits the test run. | Integer | optional | `0` |
| <a id="bun_test-concurrent"></a>concurrent | If true, treats all tests as concurrent tests. | Boolean | optional | `False` |
| <a id="bun_test-coverage"></a>coverage | If true, always enables Bun coverage output. | Boolean | optional | `False` |
| <a id="bun_test-coverage_reporters"></a>coverage_reporters | Repeated Bun coverage reporters such as `text` or `lcov`. | List of strings | optional | `[]` |
| <a id="bun_test-env_files"></a>env_files | Additional environment files loaded with `--env-file`. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_test-install_mode"></a>install_mode | Whether Bun may auto-install missing packages while testing. | String | optional | `"disable"` |
| <a id="bun_test-max_concurrency"></a>max_concurrency | Optional maximum number of concurrent tests. | Integer | optional | `0` |
| <a id="bun_test-no_env_file"></a>no_env_file | If true, disables Bun's automatic `.env` loading. | Boolean | optional | `False` |
| <a id="bun_test-node_modules"></a>node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="bun_test-only"></a>only | If true, runs only tests marked with `test.only()` or `describe.only()`. | Boolean | optional | `False` |
| <a id="bun_test-pass_with_no_tests"></a>pass_with_no_tests | If true, exits successfully when no tests are found. | Boolean | optional | `False` |
| <a id="bun_test-preload"></a>preload | Modules to preload with `--preload` before running tests. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="bun_test-randomize"></a>randomize | If true, runs tests in random order. | Boolean | optional | `False` |
| <a id="bun_test-reporter"></a>reporter | Test reporter format. | String | optional | `"console"` |
| <a id="bun_test-rerun_each"></a>rerun_each | Optional number of times to rerun each test file. | Integer | optional | `0` |
| <a id="bun_test-retry"></a>retry | Optional default retry count for all tests. | Integer | optional | `0` |
| <a id="bun_test-seed"></a>seed | Optional randomization seed. | Integer | optional | `0` |
| <a id="bun_test-smol"></a>smol | If true, enables Bun's lower-memory runtime mode. | Boolean | optional | `False` |
| <a id="bun_test-test_flags"></a>test_flags | Additional raw flags forwarded to `bun test` before the test source list. | List of strings | optional | `[]` |
| <a id="bun_test-timeout_ms"></a>timeout_ms | Optional per-test timeout in milliseconds. | Integer | optional | `0` |
| <a id="bun_test-todo"></a>todo | If true, includes tests marked with `test.todo()`. | Boolean | optional | `False` |
| <a id="bun_test-update_snapshots"></a>update_snapshots | If true, updates Bun snapshot files. | Boolean | optional | `False` |
<a id="js_library"></a>
## js_library
<pre>
load("@rules_bun//bun:defs.bzl", "js_library")
js_library(<a href="#js_library-name">name</a>, <a href="#js_library-deps">deps</a>, <a href="#js_library-srcs">srcs</a>, <a href="#js_library-data">data</a>, <a href="#js_library-types">types</a>)
</pre>
Aggregates JavaScript sources and transitive Bun source dependencies.
Attributes:
**ATTRIBUTES**
- `srcs` (label_list, optional): `.js`, `.jsx`, `.mjs`, `.cjs` files.
- `types` (label_list, optional): `.d.ts` files propagated to dependents.
- `data` (label_list, optional): runtime files propagated to dependents.
- `deps` (label_list, optional): dependent source libraries.
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="js_library-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="js_library-deps"></a>deps | Other Bun source libraries to include transitively. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="js_library-srcs"></a>srcs | JavaScript source files in this library. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="js_library-data"></a>data | Optional runtime files propagated to dependents. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="js_library-types"></a>types | Optional declaration files associated with this library. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
<a id="js_run_devserver"></a>
## js_run_devserver
<pre>
load("@rules_bun//bun:defs.bzl", "js_run_devserver")
js_run_devserver(<a href="#js_run_devserver-name">name</a>, <a href="#js_run_devserver-deps">deps</a>, <a href="#js_run_devserver-data">data</a>, <a href="#js_run_devserver-node_modules">node_modules</a>, <a href="#js_run_devserver-package_dir_hint">package_dir_hint</a>, <a href="#js_run_devserver-package_json">package_json</a>, <a href="#js_run_devserver-tool">tool</a>, <a href="#js_run_devserver-working_dir">working_dir</a>)
</pre>
Runs an executable target from a staged JS workspace.
This is a Bun-backed compatibility adapter for `rules_js`-style devserver
targets. It stages the same runtime workspace as the Bun rules, then executes
the provided tool with any default arguments.
**ATTRIBUTES**
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="js_run_devserver-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="js_run_devserver-deps"></a>deps | Library dependencies required by the dev server. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="js_run_devserver-data"></a>data | Additional runtime files required by the dev server. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="js_run_devserver-node_modules"></a>node_modules | Optional label providing package files from a node_modules tree, typically produced by bun_install or npm_translate_lock, in runfiles. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="js_run_devserver-package_dir_hint"></a>package_dir_hint | Optional package-relative directory hint when package_json is not supplied. | String | optional | `"."` |
| <a id="js_run_devserver-package_json"></a>package_json | Optional package.json used to resolve the package working directory. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="js_run_devserver-tool"></a>tool | Executable target to launch as the dev server. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="js_run_devserver-working_dir"></a>working_dir | Working directory at runtime: Bazel runfiles workspace root or the resolved package directory. | String | optional | `"workspace"` |
<a id="ts_library"></a>
## ts_library
<pre>
load("@rules_bun//bun:defs.bzl", "ts_library")
ts_library(<a href="#ts_library-name">name</a>, <a href="#ts_library-deps">deps</a>, <a href="#ts_library-srcs">srcs</a>, <a href="#ts_library-data">data</a>, <a href="#ts_library-types">types</a>)
</pre>
Aggregates TypeScript sources and transitive Bun source dependencies.
Attributes:
**ATTRIBUTES**
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="ts_library-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="ts_library-deps"></a>deps | Other Bun source libraries to include transitively. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="ts_library-srcs"></a>srcs | TypeScript source files in this library. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="ts_library-data"></a>data | Optional runtime files propagated to dependents. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="ts_library-types"></a>types | Optional declaration files associated with this library. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
<a id="js_binary"></a>
## js_binary
<pre>
load("@rules_bun//bun:defs.bzl", "js_binary")
js_binary(<a href="#js_binary-name">name</a>, <a href="#js_binary-kwargs">**kwargs</a>)
</pre>
**PARAMETERS**
| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="js_binary-name"></a>name | <p align="center"> - </p> | none |
| <a id="js_binary-kwargs"></a>kwargs | <p align="center"> - </p> | none |
<a id="js_test"></a>
## js_test
<pre>
load("@rules_bun//bun:defs.bzl", "js_test")
js_test(<a href="#js_test-name">name</a>, <a href="#js_test-entry_point">entry_point</a>, <a href="#js_test-srcs">srcs</a>, <a href="#js_test-kwargs">**kwargs</a>)
</pre>
**PARAMETERS**
| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="js_test-name"></a>name | <p align="center"> - </p> | none |
| <a id="js_test-entry_point"></a>entry_point | <p align="center"> - </p> | `None` |
| <a id="js_test-srcs"></a>srcs | <p align="center"> - </p> | `None` |
| <a id="js_test-kwargs"></a>kwargs | <p align="center"> - </p> | none |
- `srcs` (label_list, optional): `.ts`, `.tsx` files.
- `types` (label_list, optional): `.d.ts` files propagated to dependents.
- `data` (label_list, optional): runtime files propagated to dependents.
- `deps` (label_list, optional): dependent source libraries.

View File

@@ -3,7 +3,10 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
package(default_visibility = ["//visibility:public"])
exports_files([
"bun_build_support.bzl",
"bun_binary.bzl",
"bun_command.bzl",
"bun_compile.bzl",
"bun_bundle.bzl",
"bun_dev.bzl",
"bun_install.bzl",
@@ -15,20 +18,53 @@ exports_files([
"workspace.bzl",
])
bzl_library(
name = "bun_command_bzl",
srcs = ["bun_command.bzl"],
)
bzl_library(
name = "bun_build_support_bzl",
srcs = ["bun_build_support.bzl"],
deps = [
":bun_command_bzl",
":js_library_bzl",
],
)
bzl_library(
name = "bun_binary_bzl",
srcs = ["bun_binary.bzl"],
deps = [
":bun_command_bzl",
":js_library_bzl",
":workspace_bzl",
],
)
bzl_library(
name = "bun_compile_bzl",
srcs = ["bun_compile.bzl"],
deps = [
":bun_build_support_bzl",
],
)
bzl_library(
name = "bun_bundle_bzl",
srcs = ["bun_bundle.bzl"],
deps = [":js_library_bzl"],
deps = [
":bun_build_support_bzl",
],
)
bzl_library(
name = "bun_dev_bzl",
srcs = ["bun_dev.bzl"],
deps = [
":bun_command_bzl",
":workspace_bzl",
],
)
bzl_library(
@@ -39,12 +75,20 @@ bzl_library(
bzl_library(
name = "bun_script_bzl",
srcs = ["bun_script.bzl"],
deps = [
":bun_command_bzl",
":workspace_bzl",
],
)
bzl_library(
name = "bun_test_bzl",
srcs = ["bun_test.bzl"],
deps = [":js_library_bzl"],
deps = [
":bun_command_bzl",
":js_library_bzl",
":workspace_bzl",
],
)
bzl_library(

View File

@@ -1,11 +1,9 @@
"""Rule for running JS/TS scripts with Bun."""
load("//internal:bun_command.bzl", "append_shell_flag", "append_shell_flag_files", "append_shell_flag_values", "append_shell_install_mode", "append_shell_raw_flags", "render_shell_array", "shell_quote")
load("//internal:js_library.bzl", "collect_js_runfiles")
load("//internal:workspace.bzl", "create_bun_workspace_info", "render_workspace_setup", "workspace_runfiles")
def _shell_quote(value):
return "'" + value.replace("'", "'\"'\"'") + "'"
def _bun_binary_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin
@@ -13,21 +11,28 @@ def _bun_binary_impl(ctx):
dep_runfiles = [collect_js_runfiles(dep) for dep in ctx.attr.deps]
workspace_info = create_bun_workspace_info(
ctx,
extra_files = ctx.files.data + [bun_bin],
extra_files = ctx.files.data + ctx.files.preload + ctx.files.env_files + [bun_bin],
primary_file = entry_point,
)
launcher_lines = [render_shell_array("bun_args", ["--bun", "run"])]
append_shell_install_mode(launcher_lines, "bun_args", ctx.attr.install_mode)
append_shell_flag_files(launcher_lines, "bun_args", "--preload", ctx.files.preload)
append_shell_flag_files(launcher_lines, "bun_args", "--env-file", ctx.files.env_files)
append_shell_flag(launcher_lines, "bun_args", "--no-env-file", ctx.attr.no_env_file)
append_shell_flag(launcher_lines, "bun_args", "--smol", ctx.attr.smol)
append_shell_flag_values(launcher_lines, "bun_args", "--conditions", ctx.attr.conditions)
append_shell_raw_flags(launcher_lines, "bun_args", ctx.attr.run_flags)
launcher_lines.append('bun_args+=("${primary_source}")')
for arg in ctx.attr.args:
launcher_lines.append("bun_args+=(%s)" % shell_quote(arg))
command = """
trap cleanup_runtime_workspace EXIT
cd "${runtime_exec_dir}"
exec "${bun_bin}" --bun run "${primary_source}" "$@"
"""
if ctx.attr.args:
command = """
trap cleanup_runtime_workspace EXIT
cd "${runtime_exec_dir}"
exec "${bun_bin}" --bun run "${primary_source}" __DEFAULT_ARGS__ "$@"
""".replace("__DEFAULT_ARGS__", " ".join([_shell_quote(arg) for arg in ctx.attr.args]))
__BUN_ARGS__
exec "${bun_bin}" "${bun_args[@]}" "$@"
""".replace("__BUN_ARGS__", "\n".join(launcher_lines))
launcher = ctx.actions.declare_file(ctx.label.name)
ctx.actions.write(
@@ -76,6 +81,33 @@ Use this rule for non-test scripts and CLIs that should run via `bazel run`.
"deps": attr.label_list(
doc = "Library dependencies required by the program.",
),
"preload": attr.label_list(
allow_files = True,
doc = "Modules to preload with `--preload` before running the entry point.",
),
"env_files": attr.label_list(
allow_files = True,
doc = "Additional environment files loaded with `--env-file`.",
),
"no_env_file": attr.bool(
default = False,
doc = "If true, disables Bun's automatic `.env` loading.",
),
"smol": attr.bool(
default = False,
doc = "If true, enables Bun's lower-memory runtime mode.",
),
"conditions": attr.string_list(
doc = "Custom package resolve conditions passed to Bun.",
),
"install_mode": attr.string(
default = "disable",
values = ["disable", "auto", "fallback", "force"],
doc = "Whether Bun may auto-install missing packages at runtime.",
),
"run_flags": attr.string_list(
doc = "Additional raw flags forwarded to `bun run` before the entry point.",
),
"working_dir": attr.string(
default = "workspace",
values = ["workspace", "entry_point"],

View File

@@ -0,0 +1,90 @@
"""Shared helpers for Bun build- and compile-style rules."""
load("//internal:bun_command.bzl", "add_flag", "add_flag_value", "add_flag_values", "add_install_mode", "add_raw_flags")
load("//internal:js_library.bzl", "collect_js_sources")
def bun_build_transitive_inputs(ctx):
transitive_inputs = []
if getattr(ctx.attr, "node_modules", None):
transitive_inputs.append(ctx.attr.node_modules[DefaultInfo].files)
for dep in getattr(ctx.attr, "deps", []):
transitive_inputs.append(collect_js_sources(dep))
return transitive_inputs
def add_bun_build_common_flags(args, attr, metafile = None, metafile_md = None):
add_install_mode(args, getattr(attr, "install_mode", "disable"))
add_flag_value(args, "--target", getattr(attr, "target", None))
add_flag_value(args, "--format", getattr(attr, "format", None))
add_flag(args, "--production", getattr(attr, "production", False))
add_flag(args, "--splitting", getattr(attr, "splitting", False))
add_flag_value(args, "--root", getattr(attr, "root", None))
sourcemap = getattr(attr, "sourcemap", None)
if sourcemap == True:
args.add("--sourcemap")
elif sourcemap and sourcemap != "none":
add_flag_value(args, "--sourcemap", sourcemap)
add_flag_value(args, "--banner", getattr(attr, "banner", None))
add_flag_value(args, "--footer", getattr(attr, "footer", None))
add_flag_value(args, "--public-path", getattr(attr, "public_path", None))
add_flag_value(args, "--packages", getattr(attr, "packages", None))
add_flag_values(args, "--external", getattr(attr, "external", []))
add_flag_value(args, "--entry-naming", getattr(attr, "entry_naming", None))
add_flag_value(args, "--chunk-naming", getattr(attr, "chunk_naming", None))
add_flag_value(args, "--asset-naming", getattr(attr, "asset_naming", None))
add_flag(args, "--minify", getattr(attr, "minify", False))
add_flag(args, "--minify-syntax", getattr(attr, "minify_syntax", False))
add_flag(args, "--minify-whitespace", getattr(attr, "minify_whitespace", False))
add_flag(args, "--minify-identifiers", getattr(attr, "minify_identifiers", False))
add_flag(args, "--keep-names", getattr(attr, "keep_names", False))
add_flag(args, "--css-chunking", getattr(attr, "css_chunking", False))
add_flag_values(args, "--conditions", getattr(attr, "conditions", []))
add_flag_value(args, "--env", getattr(attr, "env", None))
add_flag_values(args, "--define", getattr(attr, "define", []))
add_flag_values(args, "--drop", getattr(attr, "drop", []))
add_flag_values(args, "--feature", getattr(attr, "feature", []))
add_flag_values(args, "--loader", getattr(attr, "loader", []))
add_flag_value(args, "--jsx-factory", getattr(attr, "jsx_factory", None))
add_flag_value(args, "--jsx-fragment", getattr(attr, "jsx_fragment", None))
add_flag_value(args, "--jsx-import-source", getattr(attr, "jsx_import_source", None))
add_flag_value(args, "--jsx-runtime", getattr(attr, "jsx_runtime", None))
add_flag(args, "--jsx-side-effects", getattr(attr, "jsx_side_effects", False))
add_flag(args, "--react-fast-refresh", getattr(attr, "react_fast_refresh", False))
add_flag(args, "--emit-dce-annotations", getattr(attr, "emit_dce_annotations", False))
add_flag(args, "--no-bundle", getattr(attr, "no_bundle", False))
if metafile:
args.add("--metafile=%s" % metafile.path)
if metafile_md:
args.add("--metafile-md=%s" % metafile_md.path)
add_raw_flags(args, getattr(attr, "build_flags", []))
def add_bun_compile_flags(args, attr, compile_executable = None):
add_flag(args, "--compile", True)
add_flag(args, "--bytecode", getattr(attr, "bytecode", False))
add_flag_values(args, "--compile-exec-argv", getattr(attr, "compile_exec_argv", []))
if getattr(attr, "compile_autoload_dotenv", True):
args.add("--compile-autoload-dotenv")
else:
args.add("--no-compile-autoload-dotenv")
if getattr(attr, "compile_autoload_bunfig", True):
args.add("--compile-autoload-bunfig")
else:
args.add("--no-compile-autoload-bunfig")
if getattr(attr, "compile_autoload_tsconfig", False):
args.add("--compile-autoload-tsconfig")
else:
args.add("--no-compile-autoload-tsconfig")
if getattr(attr, "compile_autoload_package_json", False):
args.add("--compile-autoload-package-json")
else:
args.add("--no-compile-autoload-package-json")
if compile_executable:
add_flag_value(args, "--compile-executable-path", compile_executable.path)
add_flag(args, "--windows-hide-console", getattr(attr, "windows_hide_console", False))
add_flag_value(args, "--windows-icon", getattr(attr, "windows_icon", None))
add_flag_value(args, "--windows-title", getattr(attr, "windows_title", None))
add_flag_value(args, "--windows-publisher", getattr(attr, "windows_publisher", None))
add_flag_value(args, "--windows-version", getattr(attr, "windows_version", None))
add_flag_value(args, "--windows-description", getattr(attr, "windows_description", None))
add_flag_value(args, "--windows-copyright", getattr(attr, "windows_copyright", None))

View File

@@ -1,6 +1,6 @@
"""Rule for bundling JS/TS sources with Bun."""
load("//internal:js_library.bzl", "collect_js_sources")
load("//internal:bun_build_support.bzl", "add_bun_build_common_flags", "bun_build_transitive_inputs")
def _output_name(target_name, entry):
@@ -12,11 +12,7 @@ def _bun_bundle_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin
transitive_inputs = []
if ctx.attr.node_modules:
transitive_inputs.append(ctx.attr.node_modules[DefaultInfo].files)
for dep in ctx.attr.deps:
transitive_inputs.append(collect_js_sources(dep))
transitive_inputs = bun_build_transitive_inputs(ctx)
outputs = []
for entry in ctx.files.entry_points:
@@ -26,20 +22,12 @@ def _bun_bundle_impl(ctx):
args = ctx.actions.args()
args.add("--bun")
args.add("build")
args.add(entry.path)
add_bun_build_common_flags(args, ctx.attr)
args.add("--outfile")
args.add(output.path)
args.add("--target")
args.add(ctx.attr.target)
args.add("--format")
args.add(ctx.attr.format)
if ctx.attr.minify:
args.add("--minify")
if ctx.attr.sourcemap:
args.add("--sourcemap")
for package in ctx.attr.external:
args.add("--external")
args.add(package)
args.add(entry.path)
ctx.actions.run(
executable = bun_bin,
@@ -78,6 +66,11 @@ Each entry point produces one output JavaScript artifact.
allow_files = True,
doc = "Additional non-source files needed during bundling.",
),
"install_mode": attr.string(
default = "disable",
values = ["disable", "auto", "fallback", "force"],
doc = "Whether Bun may auto-install missing packages during bundling.",
),
"target": attr.string(
default = "browser",
values = ["browser", "node", "bun"],
@@ -99,6 +92,9 @@ Each entry point produces one output JavaScript artifact.
"external": attr.string_list(
doc = "Package names to treat as externals (not bundled).",
),
"build_flags": attr.string_list(
doc = "Additional raw flags forwarded to `bun build`.",
),
},
toolchains = ["//bun:toolchain_type"],
)

84
internal/bun_command.bzl Normal file
View File

@@ -0,0 +1,84 @@
"""Shared Bun CLI flag builders for rules and launchers."""
def shell_quote(value):
return "'" + str(value).replace("'", "'\"'\"'") + "'"
def _runfiles_workspace(file):
workspace_name = file.owner.workspace_name
if workspace_name:
return workspace_name
return "_main"
def runfiles_path_expr(file):
return '"${runfiles_dir}/%s/%s"' % (_runfiles_workspace(file), file.short_path)
def render_shell_array(name, values):
rendered = [shell_quote(value) for value in values]
return "%s=(%s)" % (name, " ".join(rendered))
def append_shell_arg(lines, name, value):
lines.append("%s+=(%s)" % (name, shell_quote(value)))
def append_shell_expr(lines, name, expr):
lines.append("%s+=(%s)" % (name, expr))
def append_shell_flag(lines, name, flag, enabled):
if enabled:
append_shell_arg(lines, name, flag)
def append_shell_flag_value(lines, name, flag, value):
if value == None:
return
if type(value) == type("") and not value:
return
append_shell_arg(lines, name, flag)
append_shell_arg(lines, name, value)
def append_shell_flag_values(lines, name, flag, values):
for value in values:
append_shell_flag_value(lines, name, flag, value)
def append_shell_flag_files(lines, name, flag, files):
for file in files:
append_shell_arg(lines, name, flag)
append_shell_expr(lines, name, runfiles_path_expr(file))
def append_shell_raw_flags(lines, name, values):
for value in values:
append_shell_arg(lines, name, value)
def append_shell_install_mode(lines, name, install_mode):
if install_mode == "disable":
append_shell_arg(lines, name, "--no-install")
elif install_mode in ["fallback", "force"]:
append_shell_flag_value(lines, name, "--install", install_mode)
def add_flag(args, flag, enabled):
if enabled:
args.add(flag)
def add_flag_value(args, flag, value):
if value == None:
return
if type(value) == type("") and not value:
return
args.add(flag)
args.add(value)
def add_flag_values(args, flag, values):
for value in values:
add_flag_value(args, flag, value)
def add_flag_files(args, flag, files):
for file in files:
args.add(flag)
args.add(file.path)
def add_raw_flags(args, values):
args.add_all(values)
def add_install_mode(args, install_mode):
if install_mode == "disable":
args.add("--no-install")
elif install_mode in ["fallback", "force"]:
add_flag_value(args, "--install", install_mode)

315
internal/bun_compile.bzl Normal file
View File

@@ -0,0 +1,315 @@
"""Rules for Bun build outputs and standalone executables."""
load("//internal:bun_build_support.bzl", "add_bun_build_common_flags", "add_bun_compile_flags", "bun_build_transitive_inputs")
def _bun_build_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin
output_dir = ctx.actions.declare_directory(ctx.label.name)
metafile = ctx.actions.declare_file(ctx.label.name + ".meta.json") if ctx.attr.metafile else None
metafile_md = ctx.actions.declare_file(ctx.label.name + ".meta.md") if ctx.attr.metafile_md else None
args = ctx.actions.args()
args.add("--bun")
args.add("build")
add_bun_build_common_flags(args, ctx.attr, metafile = metafile, metafile_md = metafile_md)
args.add("--outdir")
args.add(output_dir.path)
args.add_all(ctx.files.entry_points)
outputs = [output_dir]
if metafile:
outputs.append(metafile)
if metafile_md:
outputs.append(metafile_md)
ctx.actions.run(
executable = bun_bin,
arguments = [args],
inputs = depset(
direct = ctx.files.entry_points + ctx.files.data,
transitive = bun_build_transitive_inputs(ctx),
),
outputs = outputs,
mnemonic = "BunBuild",
progress_message = "Building {} with Bun".format(ctx.label.name),
)
return [DefaultInfo(files = depset(outputs))]
def _bun_compile_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin
output = ctx.actions.declare_file(ctx.label.name)
compile_executable = ctx.file.compile_executable
args = ctx.actions.args()
args.add("--bun")
args.add("build")
add_bun_build_common_flags(args, ctx.attr)
add_bun_compile_flags(args, ctx.attr, compile_executable = compile_executable)
args.add("--outfile")
args.add(output.path)
args.add(ctx.file.entry_point.path)
direct_inputs = [ctx.file.entry_point] + ctx.files.data
if compile_executable:
direct_inputs.append(compile_executable)
ctx.actions.run(
executable = bun_bin,
arguments = [args],
inputs = depset(
direct = direct_inputs,
transitive = bun_build_transitive_inputs(ctx),
),
outputs = [output],
mnemonic = "BunCompile",
progress_message = "Compiling {} with Bun".format(ctx.file.entry_point.short_path),
)
return [
DefaultInfo(
executable = output,
files = depset([output]),
),
]
_COMMON_BUILD_ATTRS = {
"node_modules": attr.label(
doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, for package resolution.",
),
"deps": attr.label_list(
doc = "Source/library dependencies that provide transitive inputs.",
),
"data": attr.label_list(
allow_files = True,
doc = "Additional non-source files needed during building.",
),
"install_mode": attr.string(
default = "disable",
values = ["disable", "auto", "fallback", "force"],
doc = "Whether Bun may auto-install missing packages while executing the build.",
),
"target": attr.string(
default = "browser",
values = ["browser", "node", "bun"],
doc = "Bun build target environment.",
),
"format": attr.string(
default = "esm",
values = ["esm", "cjs", "iife"],
doc = "Output module format.",
),
"production": attr.bool(
default = False,
doc = "If true, sets `NODE_ENV=production` and enables Bun production mode.",
),
"splitting": attr.bool(
default = False,
doc = "If true, enables code splitting.",
),
"root": attr.string(
doc = "Optional root directory for multiple entry points.",
),
"sourcemap": attr.string(
default = "none",
values = ["none", "linked", "inline", "external"],
doc = "Sourcemap emission mode.",
),
"banner": attr.string(
doc = "Optional bundle banner text.",
),
"footer": attr.string(
doc = "Optional bundle footer text.",
),
"public_path": attr.string(
doc = "Optional public path prefix for emitted imports.",
),
"packages": attr.string(
default = "bundle",
values = ["bundle", "external"],
doc = "Whether packages stay bundled or are treated as external.",
),
"external": attr.string_list(
doc = "Modules treated as externals (not bundled).",
),
"entry_naming": attr.string(
doc = "Optional entry naming template.",
),
"chunk_naming": attr.string(
doc = "Optional chunk naming template.",
),
"asset_naming": attr.string(
doc = "Optional asset naming template.",
),
"minify": attr.bool(
default = False,
doc = "If true, enables all Bun minification passes.",
),
"minify_syntax": attr.bool(
default = False,
doc = "If true, minifies syntax only.",
),
"minify_whitespace": attr.bool(
default = False,
doc = "If true, minifies whitespace only.",
),
"minify_identifiers": attr.bool(
default = False,
doc = "If true, minifies identifiers only.",
),
"keep_names": attr.bool(
default = False,
doc = "If true, preserves function and class names when minifying.",
),
"css_chunking": attr.bool(
default = False,
doc = "If true, Bun chunks CSS across multiple entry points.",
),
"conditions": attr.string_list(
doc = "Custom resolve conditions passed to Bun.",
),
"env": attr.string(
doc = "Inline environment variable behavior passed to `--env`.",
),
"define": attr.string_list(
doc = "Repeated `--define` values such as `process.env.NODE_ENV:\"production\"`.",
),
"drop": attr.string_list(
doc = "Repeated `--drop` values, for example `console`.",
),
"feature": attr.string_list(
doc = "Repeated `--feature` values for dead-code elimination.",
),
"loader": attr.string_list(
doc = "Repeated `--loader` values such as `.svg:file`.",
),
"jsx_factory": attr.string(
doc = "Optional JSX factory override.",
),
"jsx_fragment": attr.string(
doc = "Optional JSX fragment override.",
),
"jsx_import_source": attr.string(
doc = "Optional JSX import source override.",
),
"jsx_runtime": attr.string(
values = ["", "automatic", "classic"],
default = "",
doc = "Optional JSX runtime override.",
),
"jsx_side_effects": attr.bool(
default = False,
doc = "If true, treats JSX as having side effects.",
),
"react_fast_refresh": attr.bool(
default = False,
doc = "If true, enables Bun's React fast refresh transform.",
),
"emit_dce_annotations": attr.bool(
default = False,
doc = "If true, re-emits DCE annotations in the bundle.",
),
"no_bundle": attr.bool(
default = False,
doc = "If true, transpiles without bundling.",
),
"build_flags": attr.string_list(
doc = "Additional raw flags forwarded to `bun build`.",
),
}
bun_build = rule(
implementation = _bun_build_impl,
doc = """Builds one or more entry points with `bun build`.
The rule emits a directory artifact so Bun can materialize multi-file output
graphs such as HTML, CSS, assets, and split chunks. Optional metafile outputs
may be requested with `metafile` and `metafile_md`.
""",
attrs = dict(_COMMON_BUILD_ATTRS, **{
"entry_points": attr.label_list(
mandatory = True,
allow_files = True,
doc = "Entry files to build, including JS/TS or HTML entry points.",
),
"metafile": attr.bool(
default = False,
doc = "If true, emits Bun's JSON metafile alongside the output directory.",
),
"metafile_md": attr.bool(
default = False,
doc = "If true, emits Bun's markdown metafile alongside the output directory.",
),
}),
toolchains = ["//bun:toolchain_type"],
)
bun_compile = rule(
implementation = _bun_compile_impl,
doc = """Compiles a Bun program into a standalone executable with `bun build --compile`.""",
attrs = dict(_COMMON_BUILD_ATTRS, **{
"target": attr.string(
default = "bun",
values = ["browser", "node", "bun"],
doc = "Bun build target environment for the compiled executable.",
),
"entry_point": attr.label(
mandatory = True,
allow_single_file = True,
doc = "Entry file to compile into an executable.",
),
"bytecode": attr.bool(
default = False,
doc = "If true, enables Bun bytecode caching in the compiled executable.",
),
"compile_exec_argv": attr.string_list(
doc = "Repeated `--compile-exec-argv` values prepended to the executable's `execArgv`.",
),
"compile_executable": attr.label(
allow_single_file = True,
doc = "Optional Bun executable used for cross-compilation via `--compile-executable-path`.",
),
"compile_autoload_dotenv": attr.bool(
default = True,
doc = "Whether the compiled executable auto-loads `.env` files at runtime.",
),
"compile_autoload_bunfig": attr.bool(
default = True,
doc = "Whether the compiled executable auto-loads `bunfig.toml` at runtime.",
),
"compile_autoload_tsconfig": attr.bool(
default = False,
doc = "Whether the compiled executable auto-loads `tsconfig.json` at runtime.",
),
"compile_autoload_package_json": attr.bool(
default = False,
doc = "Whether the compiled executable auto-loads `package.json` at runtime.",
),
"windows_hide_console": attr.bool(
default = False,
doc = "When targeting Windows, hides the console window for GUI-style executables.",
),
"windows_icon": attr.string(
doc = "Optional Windows icon path passed directly to Bun.",
),
"windows_title": attr.string(
doc = "Optional Windows executable title.",
),
"windows_publisher": attr.string(
doc = "Optional Windows publisher metadata.",
),
"windows_version": attr.string(
doc = "Optional Windows version metadata.",
),
"windows_description": attr.string(
doc = "Optional Windows description metadata.",
),
"windows_copyright": attr.string(
doc = "Optional Windows copyright metadata.",
),
}),
executable = True,
toolchains = ["//bun:toolchain_type"],
)

View File

@@ -1,5 +1,6 @@
"""Rule for running JS/TS scripts with Bun in watch mode for development."""
load("//internal:bun_command.bzl", "append_shell_flag", "append_shell_flag_files", "append_shell_flag_values", "append_shell_install_mode", "append_shell_raw_flags", "render_shell_array", "shell_quote")
load("//internal:workspace.bzl", "create_bun_workspace_info", "render_workspace_setup", "workspace_runfiles")
def _bun_dev_impl(ctx):
@@ -8,23 +9,37 @@ def _bun_dev_impl(ctx):
entry_point = ctx.file.entry_point
workspace_info = create_bun_workspace_info(
ctx,
extra_files = ctx.files.data + ctx.files.restart_on + [bun_bin],
extra_files = ctx.files.data + ctx.files.restart_on + ctx.files.preload + ctx.files.env_files + [bun_bin],
primary_file = entry_point,
)
restart_watch_paths = "\n".join([path.short_path for path in ctx.files.restart_on])
launcher_lines = [render_shell_array("bun_args", ["--bun", "run"])]
append_shell_install_mode(launcher_lines, "bun_args", ctx.attr.install_mode)
append_shell_flag_files(launcher_lines, "bun_args", "--preload", ctx.files.preload)
append_shell_flag_files(launcher_lines, "bun_args", "--env-file", ctx.files.env_files)
append_shell_flag(launcher_lines, "bun_args", "--no-env-file", ctx.attr.no_env_file)
append_shell_flag(launcher_lines, "bun_args", "--smol", ctx.attr.smol)
append_shell_flag_values(launcher_lines, "bun_args", "--conditions", ctx.attr.conditions)
append_shell_flag(launcher_lines, "bun_args", "--no-clear-screen", ctx.attr.no_clear_screen)
append_shell_raw_flags(launcher_lines, "bun_args", ctx.attr.run_flags)
launcher_lines.append('bun_args+=("${primary_source}")')
for arg in ctx.attr.args:
launcher_lines.append("bun_args+=(%s)" % shell_quote(arg))
command = """
__BUN_ARGS__
watch_mode="__WATCH_MODE__"
if [[ "${watch_mode}" == "hot" ]]; then
dev_flag="--hot"
bun_args+=("--hot")
else
dev_flag="--watch"
bun_args+=("--watch")
fi
if [[ __RESTART_COUNT__ -eq 0 ]]; then
trap cleanup_runtime_workspace EXIT
cd "${runtime_exec_dir}"
exec "${bun_bin}" --bun "${dev_flag}" run "${primary_source}" "$@"
exec "${bun_bin}" "${bun_args[@]}" "$@"
fi
readarray -t restart_paths <<'EOF_RESTART_PATHS'
@@ -59,7 +74,7 @@ restart_child() {
(
cd "${runtime_exec_dir}"
exec "${bun_bin}" --bun "${dev_flag}" run "${primary_source}" "$@"
exec "${bun_bin}" "${bun_args[@]}" "$@"
) &
child_pid=$!
}
@@ -101,6 +116,9 @@ done
).replace(
"__RESTART_PATHS__",
restart_watch_paths,
).replace(
"__BUN_ARGS__",
"\n".join(launcher_lines),
)
launcher = ctx.actions.declare_file(ctx.label.name)
@@ -151,6 +169,37 @@ watch/HMR plus optional full restarts on selected file changes.
allow_files = True,
doc = "Additional runtime files required by the dev process.",
),
"preload": attr.label_list(
allow_files = True,
doc = "Modules to preload with `--preload` before running the entry point.",
),
"env_files": attr.label_list(
allow_files = True,
doc = "Additional environment files loaded with `--env-file`.",
),
"no_env_file": attr.bool(
default = False,
doc = "If true, disables Bun's automatic `.env` loading.",
),
"smol": attr.bool(
default = False,
doc = "If true, enables Bun's lower-memory runtime mode.",
),
"conditions": attr.string_list(
doc = "Custom package resolve conditions passed to Bun.",
),
"install_mode": attr.string(
default = "disable",
values = ["disable", "auto", "fallback", "force"],
doc = "Whether Bun may auto-install missing packages in dev mode.",
),
"no_clear_screen": attr.bool(
default = False,
doc = "If true, disables terminal clearing on Bun reloads.",
),
"run_flags": attr.string_list(
doc = "Additional raw flags forwarded to `bun run` before the entry point.",
),
"working_dir": attr.string(
default = "workspace",
values = ["workspace", "entry_point"],

View File

@@ -344,6 +344,17 @@ def _bun_install_repository_impl(repository_ctx):
workspace_packages = _materialize_workspace_packages(repository_ctx, package_json)
install_args = [str(bun_bin), "--bun", "install", "--frozen-lockfile", "--no-progress"]
if repository_ctx.attr.production:
install_args.append("--production")
for omit in repository_ctx.attr.omit:
install_args.extend(["--omit", omit])
if repository_ctx.attr.linker:
install_args.extend(["--linker", repository_ctx.attr.linker])
if repository_ctx.attr.backend:
install_args.extend(["--backend", repository_ctx.attr.backend])
if repository_ctx.attr.ignore_scripts:
install_args.append("--ignore-scripts")
install_args.extend(repository_ctx.attr.install_flags)
if repository_ctx.attr.isolated_home:
result = repository_ctx.execute(
install_args,
@@ -394,6 +405,12 @@ bun_install_repository = repository_rule(
"bun_lockfile": attr.label(mandatory = True, allow_single_file = True),
"install_inputs": attr.label_list(allow_files = True),
"isolated_home": attr.bool(default = True),
"production": attr.bool(default = False),
"omit": attr.string_list(),
"linker": attr.string(),
"backend": attr.string(),
"ignore_scripts": attr.bool(default = False),
"install_flags": attr.string_list(),
"visible_repo_name": attr.string(),
"bun_linux_x64": attr.label(default = "@bun_linux_x64//:bun-linux-x64/bun", allow_single_file = True),
"bun_linux_aarch64": attr.label(default = "@bun_linux_aarch64//:bun-linux-aarch64/bun", allow_single_file = True),
@@ -403,7 +420,18 @@ bun_install_repository = repository_rule(
},
)
def bun_install(name, package_json, bun_lockfile, install_inputs = [], isolated_home = True):
def bun_install(
name,
package_json,
bun_lockfile,
install_inputs = [],
isolated_home = True,
production = False,
omit = [],
linker = "",
backend = "",
ignore_scripts = False,
install_flags = []):
"""Create an external repository containing installed node_modules.
Args:
@@ -414,6 +442,12 @@ def bun_install(name, package_json, bun_lockfile, install_inputs = [], isolated_
into the install context, such as patch files or auth/config files.
isolated_home: Whether to run Bun with HOME set to the generated
repository root for a more isolated install context.
production: Whether to omit devDependencies during install.
omit: Optional Bun dependency groups to omit, such as `dev` or `peer`.
linker: Optional Bun linker strategy, such as `isolated` or `hoisted`.
backend: Optional Bun install backend, such as `hardlink` or `copyfile`.
ignore_scripts: Whether to skip lifecycle scripts in the project manifest.
install_flags: Additional raw flags forwarded to `bun install`.
Usage (WORKSPACE):
bun_install(
@@ -429,5 +463,11 @@ def bun_install(name, package_json, bun_lockfile, install_inputs = [], isolated_
bun_lockfile = bun_lockfile,
install_inputs = install_inputs,
isolated_home = isolated_home,
production = production,
omit = omit,
linker = linker,
backend = backend,
ignore_scripts = ignore_scripts,
install_flags = install_flags,
visible_repo_name = name,
)

View File

@@ -1,10 +1,8 @@
"""Rule for running package.json scripts with Bun."""
load("//internal:bun_command.bzl", "append_shell_flag", "append_shell_flag_files", "append_shell_flag_value", "append_shell_flag_values", "append_shell_install_mode", "append_shell_raw_flags", "render_shell_array", "shell_quote")
load("//internal:workspace.bzl", "create_bun_workspace_info", "render_workspace_setup", "workspace_runfiles")
def _shell_quote(value):
return "'" + value.replace("'", "'\"'\"'") + "'"
def _bun_script_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"]
@@ -12,16 +10,39 @@ def _bun_script_impl(ctx):
package_json = ctx.file.package_json
workspace_info = create_bun_workspace_info(
ctx,
extra_files = ctx.files.data + [bun_bin],
extra_files = ctx.files.data + ctx.files.preload + ctx.files.env_files + [bun_bin],
package_dir_hint = package_json.dirname or ".",
package_json = package_json,
primary_file = package_json,
)
launcher_lines = [render_shell_array("bun_args", ["--bun", "run"])]
append_shell_install_mode(launcher_lines, "bun_args", ctx.attr.install_mode)
append_shell_flag_files(launcher_lines, "bun_args", "--preload", ctx.files.preload)
append_shell_flag_files(launcher_lines, "bun_args", "--env-file", ctx.files.env_files)
append_shell_flag(launcher_lines, "bun_args", "--no-env-file", ctx.attr.no_env_file)
append_shell_flag(launcher_lines, "bun_args", "--smol", ctx.attr.smol)
append_shell_flag_values(launcher_lines, "bun_args", "--conditions", ctx.attr.conditions)
append_shell_flag(launcher_lines, "bun_args", "--workspaces", ctx.attr.workspaces)
append_shell_flag_values(launcher_lines, "bun_args", "--filter", ctx.attr.filters)
if ctx.attr.execution_mode == "parallel":
append_shell_flag(launcher_lines, "bun_args", "--parallel", True)
elif ctx.attr.execution_mode == "sequential":
append_shell_flag(launcher_lines, "bun_args", "--sequential", True)
append_shell_flag(launcher_lines, "bun_args", "--no-exit-on-error", ctx.attr.no_exit_on_error)
append_shell_flag_value(launcher_lines, "bun_args", "--shell", ctx.attr.shell)
append_shell_flag(launcher_lines, "bun_args", "--silent", ctx.attr.silent)
append_shell_raw_flags(launcher_lines, "bun_args", ctx.attr.run_flags)
launcher_lines.append('bun_args+=(%s)' % shell_quote(ctx.attr.script))
for arg in ctx.attr.args:
launcher_lines.append("bun_args+=(%s)" % shell_quote(arg))
command = """
trap cleanup_runtime_workspace EXIT
cd "${runtime_exec_dir}"
exec "${bun_bin}" --bun run __SCRIPT__ "$@"
""".replace("__SCRIPT__", _shell_quote(ctx.attr.script))
__BUN_ARGS__
exec "${bun_bin}" "${bun_args[@]}" "$@"
""".replace("__BUN_ARGS__", "\n".join(launcher_lines))
launcher = ctx.actions.declare_file(ctx.label.name)
ctx.actions.write(
@@ -72,6 +93,58 @@ declared in `package.json` and expect to run from the package directory with
allow_files = True,
doc = "Additional runtime files required by the script.",
),
"preload": attr.label_list(
allow_files = True,
doc = "Modules to preload with `--preload` before running the script.",
),
"env_files": attr.label_list(
allow_files = True,
doc = "Additional environment files loaded with `--env-file`.",
),
"no_env_file": attr.bool(
default = False,
doc = "If true, disables Bun's automatic `.env` loading.",
),
"smol": attr.bool(
default = False,
doc = "If true, enables Bun's lower-memory runtime mode.",
),
"conditions": attr.string_list(
doc = "Custom package resolve conditions passed to Bun.",
),
"install_mode": attr.string(
default = "disable",
values = ["disable", "auto", "fallback", "force"],
doc = "Whether Bun may auto-install missing packages while running the script.",
),
"filters": attr.string_list(
doc = "Workspace package filters passed via repeated `--filter` flags.",
),
"workspaces": attr.bool(
default = False,
doc = "If true, runs the script in all workspace packages.",
),
"execution_mode": attr.string(
default = "single",
values = ["single", "parallel", "sequential"],
doc = "How Bun should execute matching workspace scripts.",
),
"no_exit_on_error": attr.bool(
default = False,
doc = "If true, Bun keeps running other workspace scripts when one fails.",
),
"shell": attr.string(
default = "",
values = ["", "bun", "system"],
doc = "Optional shell implementation for package scripts.",
),
"silent": attr.bool(
default = False,
doc = "If true, suppresses Bun's command echo for package scripts.",
),
"run_flags": attr.string_list(
doc = "Additional raw flags forwarded to `bun run` before the script name.",
),
"working_dir": attr.string(
default = "package",
values = ["workspace", "package"],

View File

@@ -1,13 +1,10 @@
"""Rule for running test suites with Bun."""
load("//internal:bun_command.bzl", "append_shell_flag", "append_shell_flag_files", "append_shell_flag_value", "append_shell_flag_values", "append_shell_install_mode", "append_shell_raw_flags", "render_shell_array", "shell_quote")
load("//internal:js_library.bzl", "collect_js_runfiles")
load("//internal:workspace.bzl", "create_bun_workspace_info", "render_workspace_setup", "workspace_runfiles")
def _shell_quote(value):
return "'" + value.replace("'", "'\"'\"'") + "'"
def _bun_test_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin
@@ -15,33 +12,68 @@ def _bun_test_impl(ctx):
dep_runfiles = [collect_js_runfiles(dep) for dep in ctx.attr.deps]
workspace_info = create_bun_workspace_info(
ctx,
extra_files = ctx.files.srcs + ctx.files.data + [bun_bin],
extra_files = ctx.files.srcs + ctx.files.data + ctx.files.preload + ctx.files.env_files + [bun_bin],
primary_file = primary_file,
)
src_args = " ".join([_shell_quote(src.short_path) for src in ctx.files.srcs])
launcher_lines = [render_shell_array("bun_args", ["--bun", "test"])]
append_shell_install_mode(launcher_lines, "bun_args", ctx.attr.install_mode)
append_shell_flag_files(launcher_lines, "bun_args", "--preload", ctx.files.preload)
append_shell_flag_files(launcher_lines, "bun_args", "--env-file", ctx.files.env_files)
append_shell_flag(launcher_lines, "bun_args", "--no-env-file", ctx.attr.no_env_file)
append_shell_flag(launcher_lines, "bun_args", "--smol", ctx.attr.smol)
append_shell_flag_value(launcher_lines, "bun_args", "--timeout", str(ctx.attr.timeout_ms) if ctx.attr.timeout_ms > 0 else None)
append_shell_flag(launcher_lines, "bun_args", "--update-snapshots", ctx.attr.update_snapshots)
append_shell_flag_value(launcher_lines, "bun_args", "--rerun-each", str(ctx.attr.rerun_each) if ctx.attr.rerun_each > 0 else None)
append_shell_flag_value(launcher_lines, "bun_args", "--retry", str(ctx.attr.retry) if ctx.attr.retry > 0 else None)
append_shell_flag(launcher_lines, "bun_args", "--todo", ctx.attr.todo)
append_shell_flag(launcher_lines, "bun_args", "--only", ctx.attr.only)
append_shell_flag(launcher_lines, "bun_args", "--pass-with-no-tests", ctx.attr.pass_with_no_tests)
append_shell_flag(launcher_lines, "bun_args", "--concurrent", ctx.attr.concurrent)
append_shell_flag(launcher_lines, "bun_args", "--randomize", ctx.attr.randomize)
append_shell_flag_value(launcher_lines, "bun_args", "--seed", str(ctx.attr.seed) if ctx.attr.seed > 0 else None)
append_shell_flag_value(launcher_lines, "bun_args", "--bail", str(ctx.attr.bail) if ctx.attr.bail > 0 else None)
append_shell_flag_value(launcher_lines, "bun_args", "--max-concurrency", str(ctx.attr.max_concurrency) if ctx.attr.max_concurrency > 0 else None)
append_shell_raw_flags(launcher_lines, "bun_args", ctx.attr.test_flags)
launcher_lines.append('coverage_requested="0"')
launcher_lines.append('coverage_dir=""')
launcher_lines.append('if [[ "${COVERAGE_DIR:-}" != "" ]]; then')
launcher_lines.append(' coverage_requested="1"')
launcher_lines.append(' coverage_dir="${COVERAGE_DIR}"')
launcher_lines.append('elif [[ "%s" == "1" ]]; then' % ("1" if ctx.attr.coverage else "0"))
launcher_lines.append(' coverage_requested="1"')
launcher_lines.append(' coverage_dir="${TEST_UNDECLARED_OUTPUTS_DIR:-${runtime_workspace}/coverage}"')
launcher_lines.append('fi')
launcher_lines.append('if [[ "${coverage_requested}" == "1" ]]; then')
launcher_lines.append(' bun_args+=("--coverage")')
launcher_lines.append(' bun_args+=("--coverage-dir" "${coverage_dir}")')
if ctx.attr.coverage_reporters:
for reporter in ctx.attr.coverage_reporters:
launcher_lines.append(' bun_args+=("--coverage-reporter" %s)' % shell_quote(reporter))
else:
launcher_lines.append(' if [[ "${COVERAGE_DIR:-}" != "" ]]; then')
launcher_lines.append(' bun_args+=("--coverage-reporter" "lcov")')
launcher_lines.append(' fi')
launcher_lines.append('fi')
launcher_lines.append('if [[ -n "${TESTBRIDGE_TEST_ONLY:-}" ]]; then')
launcher_lines.append(' bun_args+=("--test-name-pattern" "${TESTBRIDGE_TEST_ONLY}")')
launcher_lines.append('fi')
if ctx.attr.reporter == "junit":
launcher_lines.append('reporter_out="${XML_OUTPUT_FILE:-${runtime_workspace}/junit.xml}"')
launcher_lines.append('bun_args+=("--reporter" "junit" "--reporter-outfile" "${reporter_out}")')
elif ctx.attr.reporter == "dots":
launcher_lines.append('bun_args+=("--reporter" "dots")')
for src in ctx.files.srcs:
launcher_lines.append("bun_args+=(%s)" % shell_quote(src.short_path))
for arg in ctx.attr.args:
launcher_lines.append("bun_args+=(%s)" % shell_quote(arg))
command = """
trap cleanup_runtime_workspace EXIT
cd "${runtime_workspace}"
test_args=(__SRC_ARGS__)
if [[ -n "${TESTBRIDGE_TEST_ONLY:-}" && -n "${COVERAGE_DIR:-}" ]]; then
exec "${bun_bin}" --bun test "${test_args[@]}" --test-name-pattern "${TESTBRIDGE_TEST_ONLY}" --coverage "$@"
fi
if [[ -n "${TESTBRIDGE_TEST_ONLY:-}" ]]; then
exec "${bun_bin}" --bun test "${test_args[@]}" --test-name-pattern "${TESTBRIDGE_TEST_ONLY}" "$@"
fi
if [[ -n "${COVERAGE_DIR:-}" ]]; then
exec "${bun_bin}" --bun test "${test_args[@]}" --coverage "$@"
fi
exec "${bun_bin}" --bun test "${test_args[@]}" "$@"
""".replace("__SRC_ARGS__", src_args)
if ctx.attr.args:
default_args = "\n".join(['test_args+=({})'.format(_shell_quote(arg)) for arg in ctx.attr.args])
command = command.replace(
'test_args=(__SRC_ARGS__)',
'test_args=(__SRC_ARGS__)\n' + default_args,
)
__BUN_ARGS__
exec "${bun_bin}" "${bun_args[@]}" "$@"
""".replace("__BUN_ARGS__", "\n".join(launcher_lines))
launcher = ctx.actions.declare_file(ctx.label.name)
ctx.actions.write(
@@ -89,6 +121,90 @@ Supports Bazel test filtering (`--test_filter`) and coverage integration.
allow_files = True,
doc = "Additional runtime files needed by tests.",
),
"preload": attr.label_list(
allow_files = True,
doc = "Modules to preload with `--preload` before running tests.",
),
"env_files": attr.label_list(
allow_files = True,
doc = "Additional environment files loaded with `--env-file`.",
),
"no_env_file": attr.bool(
default = False,
doc = "If true, disables Bun's automatic `.env` loading.",
),
"smol": attr.bool(
default = False,
doc = "If true, enables Bun's lower-memory runtime mode.",
),
"install_mode": attr.string(
default = "disable",
values = ["disable", "auto", "fallback", "force"],
doc = "Whether Bun may auto-install missing packages while testing.",
),
"timeout_ms": attr.int(
default = 0,
doc = "Optional per-test timeout in milliseconds.",
),
"update_snapshots": attr.bool(
default = False,
doc = "If true, updates Bun snapshot files.",
),
"rerun_each": attr.int(
default = 0,
doc = "Optional number of times to rerun each test file.",
),
"retry": attr.int(
default = 0,
doc = "Optional default retry count for all tests.",
),
"todo": attr.bool(
default = False,
doc = "If true, includes tests marked with `test.todo()`.",
),
"only": attr.bool(
default = False,
doc = "If true, runs only tests marked with `test.only()` or `describe.only()`.",
),
"pass_with_no_tests": attr.bool(
default = False,
doc = "If true, exits successfully when no tests are found.",
),
"concurrent": attr.bool(
default = False,
doc = "If true, treats all tests as concurrent tests.",
),
"randomize": attr.bool(
default = False,
doc = "If true, runs tests in random order.",
),
"seed": attr.int(
default = 0,
doc = "Optional randomization seed.",
),
"bail": attr.int(
default = 0,
doc = "Optional failure count after which Bun exits the test run.",
),
"reporter": attr.string(
default = "console",
values = ["console", "dots", "junit"],
doc = "Test reporter format.",
),
"max_concurrency": attr.int(
default = 0,
doc = "Optional maximum number of concurrent tests.",
),
"coverage": attr.bool(
default = False,
doc = "If true, always enables Bun coverage output.",
),
"coverage_reporters": attr.string_list(
doc = "Repeated Bun coverage reporters such as `text` or `lcov`.",
),
"test_flags": attr.string_list(
doc = "Additional raw flags forwarded to `bun test` before the test source list.",
),
},
test = True,
toolchains = ["//bun:toolchain_type"],

View File

@@ -71,3 +71,25 @@ sh_test(
args = ["$(location :env_parent_cwd_bin)"],
data = [":env_parent_cwd_bin"],
)
bun_binary(
name = "runtime_flag_bin",
entry_point = "flag_probe.ts",
args = ["one", "two"],
preload = ["preload.ts"],
env_files = ["runtime.env"],
)
sh_test(
name = "bun_binary_runtime_flags_test",
srcs = ["run_flag_binary.sh"],
args = ["$(location :runtime_flag_bin)"],
data = [":runtime_flag_bin"],
)
sh_test(
name = "bun_binary_runtime_flags_shape_test",
srcs = ["verify_runtime_flags_shape.sh"],
args = ["$(location :runtime_flag_bin)"],
data = [":runtime_flag_bin"],
)

View File

@@ -0,0 +1,7 @@
const state = globalThis as typeof globalThis & { __rules_bun_preloaded?: string };
console.log(JSON.stringify({
preloaded: state.__rules_bun_preloaded ?? null,
env: process.env.RUNTIME_FLAG_TEST ?? null,
argv: process.argv.slice(2),
}));

View File

@@ -0,0 +1 @@
(globalThis as typeof globalThis & { __rules_bun_preloaded?: string }).__rules_bun_preloaded = "yes";

View File

@@ -5,7 +5,7 @@ binary="$1"
expected="$2"
output="$(${binary})"
if [[ "${output}" != "${expected}" ]]; then
if [[ ${output} != "${expected}" ]]; then
echo "Unexpected output from ${binary}: ${output}" >&2
exit 1
fi

View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
binary="$1"
output="$(${binary})"
expected='{"preloaded":"yes","env":"from-env-file","argv":["one","two"]}'
if [[ ${output} != "${expected}" ]]; then
echo "Unexpected output from ${binary}: ${output}" >&2
exit 1
fi

View File

@@ -0,0 +1 @@
RUNTIME_FLAG_TEST=from-env-file

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
binary="$1"
grep -Fq -- '--no-install' "${binary}"
grep -Fq -- '--preload' "${binary}"
grep -Fq -- '--env-file' "${binary}"

View File

@@ -11,6 +11,27 @@ bun_test(
srcs = ["failing.test.ts"],
)
bun_test(
name = "configured_suite",
srcs = ["passing.test.ts"],
preload = ["preload.ts"],
env_files = ["test.env"],
no_env_file = True,
timeout_ms = 250,
update_snapshots = True,
rerun_each = 2,
retry = 3,
concurrent = True,
randomize = True,
seed = 7,
bail = 1,
reporter = "junit",
max_concurrency = 4,
coverage = True,
coverage_reporters = ["lcov"],
test_flags = ["--only-failures"],
)
sh_test(
name = "bun_test_failing_suite_test",
srcs = ["failing_suite_shape.sh"],
@@ -38,3 +59,10 @@ sh_test(
args = ["$(location //internal:bun_test.bzl)"],
data = ["//internal:bun_test.bzl"],
)
sh_test(
name = "bun_test_configured_suite_shape_test",
srcs = ["configured_suite_shape.sh"],
args = ["$(location :configured_suite)"],
data = [":configured_suite"],
)

View File

@@ -3,6 +3,5 @@ set -euo pipefail
rule_file="$1"
grep -Fq 'set -euo pipefail' "${rule_file}"
grep -Fq 'src_args = " ".join([_shell_quote(src.short_path) for src in ctx.files.srcs])' "${rule_file}"
grep -Fq 'exec "${{bun_bin}}" --bun test {src_args} "$@"' "${rule_file}"
grep -Fq 'launcher_lines = [render_shell_array("bun_args", ["--bun", "test"])]' "${rule_file}"
grep -Fq 'exec "${bun_bin}" "${bun_args[@]}" "$@"' "${rule_file}"

View File

@@ -3,5 +3,6 @@ set -euo pipefail
rule_file="$1"
grep -Eq 'files = \[bun_bin\] \+ ctx\.files\.srcs \+ ctx\.files\.data' "${rule_file}"
grep -Fq 'extra_files = ctx.files.srcs + ctx.files.data + ctx.files.preload + ctx.files.env_files + [bun_bin]' "${rule_file}"
grep -Eq '"srcs": attr\.label_list\(' "${rule_file}"
grep -Eq '"coverage": attr\.bool\(' "${rule_file}"

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
launcher="$1"
grep -Fq -- '--no-install' "${launcher}"
grep -Fq -- '--preload' "${launcher}"
grep -Fq -- '--env-file' "${launcher}"
grep -Fq -- '--no-env-file' "${launcher}"
grep -Fq -- '--timeout' "${launcher}"
grep -Fq -- '--update-snapshots' "${launcher}"
grep -Fq -- '--rerun-each' "${launcher}"
grep -Fq -- '--retry' "${launcher}"
grep -Fq -- '--concurrent' "${launcher}"
grep -Fq -- '--randomize' "${launcher}"
grep -Fq -- '--seed' "${launcher}"
grep -Fq -- '--bail' "${launcher}"
grep -Fq -- '--max-concurrency' "${launcher}"
grep -Fq -- '--reporter' "${launcher}"
grep -Fq -- '--reporter-outfile' "${launcher}"
grep -Fq -- '--coverage' "${launcher}"
grep -Fq -- '--coverage-dir' "${launcher}"
grep -Fq -- '--coverage-reporter' "${launcher}"

View File

@@ -3,5 +3,5 @@ set -euo pipefail
rule_file="$1"
grep -Fq 'exec "${{bun_bin}}" --bun test {src_args} --test-name-pattern "${{TESTBRIDGE_TEST_ONLY}}" "$@"' "${rule_file}"
grep -Fq 'if [[ -n "${{TESTBRIDGE_TEST_ONLY:-}}" ]]' "${rule_file}"
grep -Fq 'reporter_out="${XML_OUTPUT_FILE:-${runtime_workspace}/junit.xml}"' "${rule_file}"
grep -Fq 'bun_args+=("--reporter" "junit" "--reporter-outfile" "${reporter_out}")' "${rule_file}"

View File

@@ -0,0 +1 @@
(globalThis as typeof globalThis & { __rules_bun_test_preloaded?: boolean }).__rules_bun_test_preloaded = true;

View File

@@ -0,0 +1 @@
TEST_FROM_ENV=1

View File

@@ -1,4 +1,4 @@
load("//bun:defs.bzl", "bun_bundle")
load("//bun:defs.bzl", "bun_build", "bun_bundle", "bun_compile")
load("@rules_shell//shell:sh_test.bzl", "sh_test")
bun_bundle(
@@ -18,6 +18,32 @@ bun_bundle(
external = ["left-pad"],
)
bun_build(
name = "site_build",
entry_points = ["site/index.html"],
data = [
"site/main.ts",
"site/styles.css",
],
splitting = True,
)
bun_build(
name = "site_build_with_meta",
entry_points = ["site/index.html"],
data = [
"site/main.ts",
"site/styles.css",
],
metafile = True,
metafile_md = True,
)
bun_compile(
name = "compiled_cli",
entry_point = "cli.ts",
)
sh_test(
name = "bundle_output_test",
srcs = ["verify_bundle.sh"],
@@ -57,3 +83,24 @@ sh_test(
"//tests/bundle_test:BUILD.bazel",
],
)
sh_test(
name = "bun_build_site_output_test",
srcs = ["verify_site_build.sh"],
args = ["$(location :site_build)"],
data = [":site_build"],
)
sh_test(
name = "bun_build_site_meta_test",
srcs = ["verify_site_build_meta.sh"],
args = ["$(locations :site_build_with_meta)"],
data = [":site_build_with_meta"],
)
sh_test(
name = "bun_compile_output_test",
srcs = ["run_compiled_binary.sh"],
args = ["$(location :compiled_cli)"],
data = [":compiled_cli"],
)

1
tests/bundle_test/cli.ts Normal file
View File

@@ -0,0 +1 @@
console.log("compiled-cli");

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
binary="$1"
output="$(${binary})"
if [[ ${output} != "compiled-cli" ]]; then
echo "Unexpected output from compiled binary ${binary}: ${output}" >&2
exit 1
fi

View File

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>rules_bun site build</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div id="app">rules_bun</div>
<script type="module" src="./main.ts"></script>
</body>
</html>

View File

@@ -0,0 +1 @@
document.getElementById("app")?.setAttribute("data-built", "yes");

View File

@@ -0,0 +1,4 @@
body {
background: #f5efe2;
color: #1f1b14;
}

View File

@@ -3,12 +3,12 @@ set -euo pipefail
bundle="$1"
if [[ ! -f "${bundle}" ]]; then
if [[ ! -f ${bundle} ]]; then
echo "Bundle output not found: ${bundle}" >&2
exit 1
fi
if [[ ! -s "${bundle}" ]]; then
if [[ ! -s ${bundle} ]]; then
echo "Bundle output is empty: ${bundle}" >&2
exit 1
fi

View File

@@ -4,10 +4,10 @@ set -euo pipefail
bundle="$1"
minified="$2"
bundle_size="$(wc -c < "${bundle}")"
minified_size="$(wc -c < "${minified}")"
bundle_size="$(wc -c <"${bundle}")"
minified_size="$(wc -c <"${minified}")"
if (( minified_size >= bundle_size )); then
if ((minified_size >= bundle_size)); then
echo "Expected minified bundle (${minified_size}) to be smaller than regular bundle (${bundle_size})" >&2
exit 1
fi

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
output_dir="$1"
if [[ ! -d ${output_dir} ]]; then
echo "Expected output directory: ${output_dir}" >&2
exit 1
fi
if ! find -L "${output_dir}" -type f \( -name '*.js' -o -name '*.css' \) | grep -q .; then
echo "Expected Bun build assets in ${output_dir}" >&2
exit 1
fi

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
output_dir=""
meta_json=""
meta_md=""
for path in "$@"; do
case "${path}" in
*.meta.json) meta_json="${path}" ;;
*.meta.md) meta_md="${path}" ;;
*) output_dir="${path}" ;;
esac
done
if [[ ! -d ${output_dir} ]]; then
echo "Expected directory output, got: ${output_dir}" >&2
exit 1
fi
if [[ ! -f ${meta_json} ]]; then
echo "Expected JSON metafile output" >&2
exit 1
fi
if [[ ! -f ${meta_md} ]]; then
echo "Expected markdown metafile output" >&2
exit 1
fi

View File

@@ -121,3 +121,10 @@ sh_test(
"//conditions:default": ["@bun_linux_x64//:bun"],
}),
)
sh_test(
name = "bun_install_install_flags_shape_test",
srcs = ["install_flags_shape.sh"],
args = ["$(location //internal:bun_install.bzl)"],
data = ["//internal:bun_install.bzl"],
)

View File

@@ -5,7 +5,7 @@ bun_path="$1"
workdir="$(mktemp -d)"
trap 'rm -rf "${workdir}"' EXIT
cat > "${workdir}/package.json" <<'JSON'
cat >"${workdir}/package.json" <<'JSON'
{
"name": "clean-install-test",
"version": "1.0.0"

View File

@@ -7,3 +7,4 @@ grep -Eq 'install_args = \[str\(bun_bin\), "--bun", "install", "--frozen-lockfil
grep -Eq 'if repository_ctx\.attr\.isolated_home:' "${rule_file}"
grep -Eq 'environment[[:space:]]*=[[:space:]]*\{"HOME":[[:space:]]*str\(repository_ctx\.path\("\."\)\)\}' "${rule_file}"
grep -Eq '"isolated_home": attr\.bool\(default = True\)' "${rule_file}"
grep -Eq '"install_flags": attr\.string_list\(\)' "${rule_file}"

View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
rule_file="$1"
grep -Fq 'repository_ctx.attr.production' "${rule_file}"
grep -Fq '"--production"' "${rule_file}"
grep -Fq 'for omit in repository_ctx.attr.omit' "${rule_file}"
grep -Fq '"--omit"' "${rule_file}"
grep -Fq 'repository_ctx.attr.linker' "${rule_file}"
grep -Fq '"--linker"' "${rule_file}"
grep -Fq 'repository_ctx.attr.backend' "${rule_file}"
grep -Fq '"--backend"' "${rule_file}"
grep -Fq 'repository_ctx.attr.ignore_scripts' "${rule_file}"
grep -Fq '"--ignore-scripts"' "${rule_file}"
grep -Fq 'repository_ctx.attr.install_flags' "${rule_file}"

View File

@@ -4,6 +4,6 @@ set -euo pipefail
build_file="$1"
readme_file="$2"
[[ -f "${build_file}" ]]
[[ -f "${readme_file}" ]]
[[ -f ${build_file} ]]
[[ -f ${readme_file} ]]
grep -Eq '^package\(default_visibility = \["//visibility:public"\]\)$' "${build_file}"

View File

@@ -3,7 +3,7 @@ set -euo pipefail
bundle="$1"
if [[ ! -s "${bundle}" ]]; then
if [[ ! -s ${bundle} ]]; then
echo "Expected bundled output to exist and be non-empty: ${bundle}" >&2
exit 1
fi

View File

@@ -143,3 +143,25 @@ sh_test(
":paraglide_monorepo_app_b_build",
],
)
bun_script(
name = "workspace_filtered_script",
script = "say",
package_json = "workspace_run/package.json",
data = [
"workspace_run/packages/pkg-a/package.json",
"workspace_run/packages/pkg-a/say.ts",
"workspace_run/packages/pkg-b/package.json",
"workspace_run/packages/pkg-b/say.ts",
],
filters = ["./packages/pkg-a"],
execution_mode = "sequential",
silent = True,
)
sh_test(
name = "bun_script_workspace_filter_test",
srcs = ["run_workspace_script.sh"],
args = ["$(location :workspace_filtered_script)"],
data = [":workspace_filtered_script"],
)

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
script_bin="$1"
output="$(${script_bin})"
if [[ ${output} != *"pkg-a"* ]]; then
echo "Expected workspace run output to include pkg-a: ${output}" >&2
exit 1
fi
if [[ ${output} == *"pkg-b"* ]]; then
echo "Workspace filter unexpectedly included pkg-b: ${output}" >&2
exit 1
fi

View File

@@ -0,0 +1,7 @@
{
"name": "workspace-run-root",
"private": true,
"workspaces": [
"packages/*"
]
}

View File

@@ -0,0 +1,6 @@
{
"name": "pkg-a",
"scripts": {
"say": "bun ./say.ts"
}
}

View File

@@ -0,0 +1 @@
console.log("pkg-a");

View File

@@ -0,0 +1,6 @@
{
"name": "pkg-b",
"scripts": {
"say": "bun ./say.ts"
}
}

View File

@@ -0,0 +1 @@
console.log("pkg-b");

View File

@@ -4,7 +4,7 @@ set -euo pipefail
bun_path="$1"
version="$(${bun_path} --version)"
if [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
if [[ ! ${version} =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
echo "Unexpected bun version output: ${version}" >&2
exit 1
fi