1 Commits

Author SHA1 Message Date
eric
10758aa20a docs: Refactor code structure for improved readability
Some checks failed
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
CI / test (ubuntu-latest, linux-x64) (push) Has been cancelled
Docs Pages / deploy (push) Failing after 33s
2026-03-06 20:54:28 +01:00
19 changed files with 232 additions and 2341 deletions

View File

@@ -1,19 +0,0 @@
#!/usr/bin/env bash
set -e
if [[ ! -d "/Users/eric/Projects/rules_bun" ]]; then
echo "Cannot find source directory; Did you move it?"
echo "(Looking for "/Users/eric/Projects/rules_bun")"
echo 'Cannot force reload with this script - use "direnv reload" manually and then try again'
exit 1
fi
# rebuild the cache forcefully
_nix_direnv_force_reload=1 direnv exec "/Users/eric/Projects/rules_bun" true
# Update the mtime for .envrc.
# This will cause direnv to reload again - but without re-building.
touch "/Users/eric/Projects/rules_bun/.envrc"
# Also update the timestamp of whatever profile_rc we have.
# This makes sure that we know we are up to date.
touch -r "/Users/eric/Projects/rules_bun/.envrc" "/Users/eric/Projects/rules_bun/.direnv"/*.rc

View File

@@ -1 +0,0 @@
/nix/store/7f0478ddr51i3r708dpkljnvmzwc2fhn-source

View File

@@ -1 +0,0 @@
/nix/store/affmc6lhad8f6q3iaa3iydcdjwr8lwgp-source

View File

@@ -1 +0,0 @@
/nix/store/g5v3sgqy6a0fsmas7mnapc196flrplix-source

View File

@@ -1 +0,0 @@
/nix/store/jzfmmjnq1cip816awnliw7ir69pcyg00-source

View File

@@ -1 +0,0 @@
/nix/store/kx00h535s3jzb9803vnylxllij3zhix5-source

View File

@@ -1 +0,0 @@
/nix/store/ngdfag0pfs1h54pbjs9ywah4zhqsphf1-source

View File

@@ -1 +0,0 @@
/nix/store/nk13680f34w3q01a1q69c48my6fi7cxz-source

View File

@@ -1 +0,0 @@
/nix/store/k647bkhh6fv8rw9pnxgzyyv3r4y8fsin-nix-shell-env

File diff suppressed because one or more lines are too long

1
.gitignore vendored
View File

@@ -23,3 +23,4 @@ node_modules/
.env
!tests/.env
!examples/.env
.direnv

View File

@@ -3,11 +3,13 @@ module(
version = "0.2.0",
)
# Core ruleset dependencies.
bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "rules_shell", version = "0.6.1")
bazel_dep(name = "bazel_skylib", version = "1.8.2")
bazel_dep(name = "stardoc", version = "0.7.2")
# Repository-local setup for this ruleset's own tests and examples.
bun_ext = use_extension("//bun:extensions.bzl", "bun")
use_repo(
bun_ext,
@@ -18,6 +20,7 @@ use_repo(
"bun_windows_x64",
)
# Test fixture dependency installation used by //tests/script_test.
bun_install_ext = use_extension("//bun:extensions.bzl", "bun_install")
bun_install_ext.install(
name = "script_test_vite_node_modules",
@@ -26,6 +29,7 @@ bun_install_ext.install(
)
use_repo(bun_install_ext, "script_test_vite_node_modules")
# Register the published Bun toolchains for this repository.
register_toolchains(
"//bun:darwin_aarch64_toolchain",
"//bun:darwin_x64_toolchain",

4
MODULE.bazel.lock generated
View File

@@ -190,7 +190,7 @@
"//bun:extensions.bzl%bun": {
"general": {
"bzlTransitiveDigest": "83P5DLnVhSu3AwYrHPGqYVY/L6twnM4Jnlhc8uAOOls=",
"usagesDigest": "qk1PDh3WICa0VONYKXJLsmWCesNJxz3Jkb/aH/voIeI=",
"usagesDigest": "SXT282ETYzRFxBNaQrX/Ym1rZzueKzjlll/D0arFoYs=",
"recordedInputs": [
"REPO_MAPPING:,bazel_tools bazel_tools"
],
@@ -251,7 +251,7 @@
"//bun:extensions.bzl%bun_install": {
"general": {
"bzlTransitiveDigest": "83P5DLnVhSu3AwYrHPGqYVY/L6twnM4Jnlhc8uAOOls=",
"usagesDigest": "r8Bik2FdMIUMCNUMdEfwvoy+Yaru70lPjHGWflG1wIc=",
"usagesDigest": "BSZJHRsUZpMHTxqlUZZaq4MH8kfqrzFfF+50EqSPx/Q=",
"recordedInputs": [
"REPO_MAPPING:,bazel_tools bazel_tools"
],

252
README.md
View File

@@ -1,191 +1,197 @@
# rules_bun
# Bun rules for [Bazel](https://bazel.build)
Bazel rules for bun.
`rules_bun` provides Bazel rules for running, testing, bundling, and developing
JavaScript and TypeScript code with Bun.
## Rule reference
## Repository layout
This repository follows the standard Bazel ruleset layout:
```text
/
MODULE.bazel
README.md
bun/
BUILD.bazel
defs.bzl
extensions.bzl
repositories.bzl
toolchain.bzl
docs/
examples/
tests/
```
The public entrypoint for rule authors and users is `@rules_bun//bun:defs.bzl`.
## Public API
`rules_bun` exports these primary rules:
- `bun_binary`
- `bun_bundle`
- `bun_dev`
- `bun_script`
- `bun_test`
- `js_library`
- `ts_library`
Reference documentation:
- Published docs site: https://eriyc.github.io/rules_bun/
- Generated API docs: [docs/rules.md](docs/rules.md)
- Regenerate: `bazel build //docs:rules_md && cp bazel-bin/docs/rules.md docs/rules.md`
- Generated rule reference: [docs/rules.md](docs/rules.md)
- Docs index: [docs/index.md](docs/index.md)
## Use
To refresh generated rule docs:
These steps show how to consume a tagged release of `rules_bun` in a separate Bazel workspace.
```bash
bazel build //docs:rules_md && cp bazel-bin/docs/rules.md docs/rules.md
```
### 1) Add the module dependency
## Bzlmod usage
In your project's `MODULE.bazel`, add:
Release announcements should provide a copy-pasteable module snippet in the
standard ruleset form:
```starlark
bazel_dep(name = "rules_bun", version = "0.2.0")
archive_override(
module_name = "rules_bun",
urls = ["https://github.com/Eriyc/rules_bun/archiv0.0.5.tar.gz"],
strip_prefix = "rules_bun-v0.2.0",
)
```
For channel/pre-release tags (for example `v0.2.0-rc.1`), use the matching folder prefix:
```starlark
bazel_dep(name = "rules_bun", version = "0.2.0-rc.1")
archive_override(
module_name = "rules_bun",
urls = ["https://github.com/Eriyc/rules_bun/archiv0.0.5-rc.1.tar.gz"],
strip_prefix = "rules_bun-v0.2.0-rc.1",
)
```
Note: keep the `v` prefix in the Git tag URL and `strip_prefix`; for `bazel_dep(..., version = ...)`, use the module version string without the leading `v`.
### 2) Create Bun repositories with the extension
Still in `MODULE.bazel`, add:
Then add the Bun repositories and register the toolchains in `MODULE.bazel`:
```starlark
bun_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun")
use_repo(
bun_ext,
"bun_linux_x64",
"bun_linux_aarch64",
"bun_darwin_x64",
"bun_darwin_aarch64",
"bun_windows_x64",
bun_ext,
"bun_linux_x64",
"bun_linux_aarch64",
"bun_darwin_x64",
"bun_darwin_aarch64",
"bun_windows_x64",
)
```
### 3) Register toolchains
Also in `MODULE.bazel`, register:
```starlark
register_toolchains(
"@rules_bun//bun:darwin_aarch64_toolchain",
"@rules_bun//bun:darwin_x64_toolchain",
"@rules_bun//bun:linux_aarch64_toolchain",
"@rules_bun//bun:linux_x64_toolchain",
"@rules_bun//bun:windows_x64_toolchain",
"@rules_bun//bun:darwin_aarch64_toolchain",
"@rules_bun//bun:darwin_x64_toolchain",
"@rules_bun//bun:linux_aarch64_toolchain",
"@rules_bun//bun:linux_x64_toolchain",
"@rules_bun//bun:windows_x64_toolchain",
)
```
### 4) Load rules in `BUILD.bazel`
```starlark
load(
"@rules_bun//bun:defs.bzl",
"bun_binary",
"bun_bundle",
"bun_dev",
"bun_script",
"bun_test",
"js_library",
"ts_library",
)
```
### 5) (Optional) Use `bun_install` module extension
If you want Bazel-managed install repositories, add:
If you want Bazel-managed dependency installation, also add the module
extension for `bun_install`:
```starlark
bun_install_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun_install")
bun_install_ext.install(
name = "npm",
package_json = "//:package.json",
bun_lockfile = "//:bun.lock",
name = "npm",
package_json = "//:package.json",
bun_lockfile = "//:bun.lock",
)
use_repo(bun_install_ext, "npm")
```
### 6) Verify setup
## Legacy WORKSPACE usage
Run one of your bun-backed targets, for example:
For non-Bzlmod consumers, the repository exposes a legacy setup macro in
`@rules_bun//bun:repositories.bzl`:
```bash
bazel test //path/to:your_bun_test
```starlark
load("@rules_bun//bun:repositories.bzl", "bun_register_toolchains")
bun_register_toolchains()
```
All `rules_bun` rule-driven Bun invocations pass `--bun`.
## Loading rules in BUILD files
## Package scripts (`bun_script`)
```starlark
load(
"@rules_bun//bun:defs.bzl",
"bun_binary",
"bun_bundle",
"bun_dev",
"bun_script",
"bun_test",
"js_library",
"ts_library",
)
```
Use `bun_script` to expose a `package.json` script as a Bazel executable target.
## Common workflows
### `bun_script` for package scripts
Use `bun_script` to expose a `package.json` script as a Bazel executable.
This is the recommended way to run Vite-style `dev`, `build`, and `preview`
scripts.
```starlark
load("@rules_bun//bun:defs.bzl", "bun_script")
bun_script(
name = "web_dev",
script = "dev",
package_json = "package.json",
node_modules = "@npm//:node_modules",
data = glob([
"src/**",
"static/**",
"vite.config.*",
"svelte.config.*",
"tsconfig*.json",
]),
name = "web_dev",
script = "dev",
package_json = "package.json",
node_modules = "@npm//:node_modules",
data = glob([
"src/**",
"static/**",
"vite.config.*",
"svelte.config.*",
"tsconfig*.json",
]),
)
```
Run it with:
When `node_modules` is provided, executables from `node_modules/.bin` are added
to `PATH`.
```bash
bazel run //path/to:web_dev -- --host
```
### `bun_dev` for local development
`bun_script` defaults to running from the directory containing `package.json`, which matches the usual expectations for `vite`, `svelte-kit`, and similar package scripts.
## Development mode (`bun_dev`)
Use `bun_dev` for long-running local development with Bun watch mode.
Use `bun_dev` for long-running watch or hot-reload development targets.
```starlark
load("@rules_bun//bun:defs.bzl", "bun_dev")
bun_dev(
name = "web_dev",
entry_point = "src/main.ts",
# Optional: run from the entry point directory so Bun auto-loads colocated .env files.
# working_dir = "entry_point",
name = "web_dev",
entry_point = "src/main.ts",
# Optional: run from the entry point directory so Bun auto-loads colocated .env files.
# working_dir = "entry_point",
)
```
Run it with:
Supported development options include:
```bash
bazel run //path/to:web_dev
```
- `watch_mode = "watch"`
- `watch_mode = "hot"`
- `restart_on = [...]`
- `working_dir = "workspace" | "entry_point"`
`bun_dev` supports:
- `watch_mode = "watch"` (default) for `bun --watch`
- `watch_mode = "hot"` for `bun --hot`
- `restart_on = [...]` to force full process restarts when specific files change
- `working_dir = "workspace" | "entry_point"` (default: `workspace`)
## Runtime working directory (`bun_binary`, `bun_dev`)
### Working directory behavior
`bun_binary` and `bun_dev` support `working_dir`:
- `"workspace"` (default): runs from the Bazel runfiles workspace root.
- `"entry_point"`: runs from the nearest ancestor of the entry point that contains `.env` or `package.json` (falls back to the entry point directory).
- `"workspace"`: run from the Bazel runfiles workspace root.
- `"entry_point"`: run from the nearest ancestor of the entry point that
contains `.env` or `package.json`.
Use `"entry_point"` when Bun should resolve local files such as colocated `.env` files relative to the program directory.
## Tests and examples
### Hybrid Go + Bun + protobuf workflow
The repository keeps conformance and integration coverage in [tests/](tests/) and
usage samples in [examples/](examples/).
For monorepos that mix Go and Bun (including FFI):
Representative example docs:
1. Run Bun app with native watch/HMR via `bun_dev`.
2. Put generated artifacts or bridge files in `restart_on` (for example generated JS/TS files from proto/go steps).
3. Rebuild Go/proto artifacts separately (for example with `ibazel build`) so their output files change.
4. `bun_dev` detects those `restart_on` changes and restarts Bun, while ordinary JS edits continue to use Bun watch/HMR without full Bazel restarts.
- [examples/basic/README.md](examples/basic/README.md)
- [examples/workspace/README.md](examples/workspace/README.md)
This keeps the fast Bun JS loop while still supporting full restarts when non-JS dependencies change.
To validate the ruleset locally:
```bash
bazel test //tests/...
```

View File

@@ -5,6 +5,9 @@ load(":version.bzl", "BUN_VERSION")
exports_files([
"defs.bzl",
"extensions.bzl",
"repositories.bzl",
"toolchain.bzl",
"version.bzl",
])
bzl_library(
@@ -13,6 +16,19 @@ bzl_library(
visibility = ["//visibility:public"],
)
bzl_library(
name = "extensions_bzl",
srcs = ["extensions.bzl"],
visibility = ["//visibility:public"],
deps = ["//internal:bun_install_bzl"],
)
bzl_library(
name = "repositories_bzl",
srcs = ["repositories.bzl"],
visibility = ["//visibility:public"],
)
bzl_library(
name = "defs_bzl",
srcs = ["defs.bzl"],

View File

@@ -1,14 +1,80 @@
# rules_bun docs
Documentation site for `rules_bun`.
Documentation for `rules_bun`, a Bazel ruleset for Bun.
## Ruleset layout
The repository exposes its public Bazel API from the [bun/](../bun/) package:
- `@rules_bun//bun:defs.bzl` for build rules
- `@rules_bun//bun:extensions.bzl` for Bzlmod extensions
- `@rules_bun//bun:repositories.bzl` for legacy WORKSPACE setup
Supporting material lives in:
- [examples/](../examples/) for usage samples
- [tests/](../tests/) for repository conformance and integration tests
- [docs/rules.md](rules.md) for generated rule reference
## Rule reference
- [rules.md](rules.md)
## Typical Bzlmod setup
```starlark
bazel_dep(name = "rules_bun", version = "0.2.0")
bun_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun")
use_repo(
bun_ext,
"bun_linux_x64",
"bun_linux_aarch64",
"bun_darwin_x64",
"bun_darwin_aarch64",
"bun_windows_x64",
)
register_toolchains(
"@rules_bun//bun:darwin_aarch64_toolchain",
"@rules_bun//bun:darwin_x64_toolchain",
"@rules_bun//bun:linux_aarch64_toolchain",
"@rules_bun//bun:linux_x64_toolchain",
"@rules_bun//bun:windows_x64_toolchain",
)
```
## Vite package scripts
Use `bun_script` for package-script driven workflows such as `dev`, `build`,
and `preview`.
```starlark
load("@rules_bun//bun:defs.bzl", "bun_script")
bun_script(
name = "web_dev",
script = "dev",
package_json = "package.json",
node_modules = "@npm//:node_modules",
data = glob([
"src/**",
"public/**",
"index.html",
"vite.config.*",
"tsconfig*.json",
]),
)
```
`bun_script` runs from the package directory by default and adds
`node_modules/.bin` to `PATH`.
## Regeneration
The rule reference is generated from Starlark rule docstrings:
The rule reference is generated from the public Starlark symbols in
`@rules_bun//bun:defs.bzl`:
```bash
bazel build //docs:rules_md

View File

@@ -30,13 +30,17 @@ Attributes:
Runs a named `package.json` script with Bun as an executable target (`bazel run`).
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.
Attributes:
- `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): Bun/npm package files in runfiles.
- `data` (label_list, optional): additional runtime files for the script.
- `working_dir` (string, default: `"package"`, values: `"workspace" | "package"`): runtime working directory.
- `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_bundle

View File

@@ -28,17 +28,9 @@
system:
let
pkgs = import nixpkgs { inherit system; };
bazelDefaultArgs =
if pkgs.stdenv.hostPlatform.isDarwin then
[
"--macos_minimum_os=10.12"
"--host_macos_minimum_os=10.12"
]
else
[ ];
bazel9 = pkgs.writeShellScriptBin "bazel" ''
export USE_BAZEL_VERSION="''${USE_BAZEL_VERSION:-9.0.0}"
exec ${pkgs.bazelisk}/bin/bazelisk ${pkgs.lib.escapeShellArgs bazelDefaultArgs} "$@"
exec ${pkgs.bazelisk}/bin/bazelisk "$@"
'';
env = devshell-lib.lib.mkDevShell {
inherit system;

View File

@@ -70,7 +70,10 @@ bun_script = rule(
doc = """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.
`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`.
""",
attrs = {
"script": attr.string(
@@ -83,7 +86,7 @@ Use this rule to expose existing package scripts such as `dev`, `build`, or
doc = "Label of the `package.json` file containing the named script.",
),
"node_modules": attr.label(
doc = "Optional label providing Bun/npm package files in runfiles.",
doc = "Optional label providing Bun/npm package files in runfiles. Executables from `node_modules/.bin` are added to `PATH`, which is useful for scripts such as `vite`.",
),
"data": attr.label_list(
allow_files = True,
@@ -92,7 +95,7 @@ Use this rule to expose existing package scripts such as `dev`, `build`, or
"working_dir": attr.string(
default = "package",
values = ["workspace", "package"],
doc = "Working directory at runtime: Bazel runfiles `workspace` root or the directory containing `package.json`.",
doc = "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.",
),
},
executable = True,