37 Commits

Author SHA1 Message Date
eric
54109136ab chore(release): v1.0.2
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 32s
Docs Pages / deploy (push) Failing after 36s
Copilot Setup Steps / copilot-setup-steps (push) Failing after 36s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-15 13:08:19 +01:00
eric
3e5ed611fe ci: something 2026-03-15 13:08:07 +01:00
eric
3085d3ce98 ci: something 2026-03-15 13:01:47 +01:00
eric
143db9c20e ci: remove redundant go dep 2026-03-15 12:45:59 +01:00
eric
4f9dff66c1 ci: remove redundant go dep 2026-03-15 12:17:25 +01:00
eric
fbe1eb3fc8 ci: pin bazel version 2026-03-15 12:15:40 +01:00
eric
08f2abc60e ci: print logs instead of paths 2026-03-15 12:06:28 +01:00
eric
65404a1883 chore(release): v1.0.1
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 59s
Docs Pages / deploy (push) Failing after 34s
Copilot Setup Steps / copilot-setup-steps (push) Failing after 37s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-15 11:57:45 +01:00
eric
f317a618b8 fix: context leak 2026-03-15 11:50:25 +01:00
eric
683de60603 fix: windows targets 2026-03-15 11:24:36 +01:00
eric
a58028d063 chore(release): v1.0.0
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 37s
Docs Pages / deploy (push) Failing after 39s
Copilot Setup Steps / copilot-setup-steps (push) Failing after 40s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-15 11:04:58 +01:00
eric
626a6640f8 feat: proper windows support 2026-03-15 11:04:44 +01:00
eric
4f8e27cd74 chore(release): v0.5.0
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 34s
Docs Pages / deploy (push) Failing after 44s
Copilot Setup Steps / copilot-setup-steps (push) Failing after 25s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-15 09:34:22 +01:00
eric
31c42a8638 fix: tests 2026-03-15 09:34:07 +01:00
eric
769b95d05b chore(release): v0.4.0
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 31s
Copilot Setup Steps / copilot-setup-steps (push) Failing after 36s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-15 01:20:57 +01:00
eric
2a25cfb91a fix: include .env files 2026-03-15 01:20:45 +01:00
eric
2a9bd09aa4 fix: include .env files 2026-03-15 01:13:52 +01:00
eric
4b7ebb1536 fix: include .env files 2026-03-15 01:07:36 +01:00
73d4625420 Merge pull request 'feature/add-build-compile-rules' (#4) from feature/add-build-compile-rules into main
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 37s
Docs Pages / deploy (push) Failing after 43s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
Reviewed-on: #4
2026-03-15 00:01:19 +00:00
eric
b35f03872c test: add more tests
Some checks failed
CI / test (ubuntu-latest, linux-x64) (pull_request) Failing after 32s
CI / test (macos-14, darwin-arm64) (pull_request) Has been cancelled
CI / test (windows-latest, windows) (pull_request) Has been cancelled
2026-03-15 00:59:58 +01:00
eric
a0bc998bd2 feat: new bun_build and bun_compile, extend bun_install 2026-03-15 00:11:55 +01:00
eric
c446f23a35 feat: improve rules_js parity 2026-03-14 23:50:26 +01:00
eric
d7a6d6b0ba fix: bun monorepo complex deps 2026-03-08 03:29:54 +01:00
eric
81e9b93914 fix: bun install symlinks 4
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 31s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-07 00:34:14 +01:00
eric
9cbd027e7e fix: bun install symlinks 4 2026-03-07 00:32:40 +01:00
eric
6b5343fdf3 fix: bun install symlinks 4 2026-03-07 00:30:13 +01:00
eric
9487fafe88 fix: bun install symlinks 3 2026-03-07 00:27:51 +01:00
eric
9e64fd1369 fix: bun install symlinks
Some checks failed
Copilot Setup Steps / copilot-setup-steps (push) Failing after 36s
2026-03-07 00:23:39 +01:00
eric
d04f489b0e fix: bun install symlinks
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 39s
Docs Pages / deploy (push) Failing after 33s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-07 00:00:00 +01:00
eric
40d621d1cf fix: bun install symlinks 2026-03-06 23:52:27 +01:00
eric
e567dad413 chore(release): v0.2.2
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 36s
Copilot Setup Steps / copilot-setup-steps (push) Failing after 37s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-06 21:44:56 +01:00
eric
7139aa3ba2 fix: bun_install adds node_modules to each directory
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 42s
2026-03-06 21:44:15 +01:00
eric
49a5054b02 chore(release): v0.2.1
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 31s
Copilot Setup Steps / copilot-setup-steps (push) Failing after 38s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-06 20:55:09 +01:00
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
eric
fb7afbb138 chore(release): v0.2.0
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 38s
Docs Pages / deploy (push) Failing after 44s
Copilot Setup Steps / copilot-setup-steps (push) Failing after 34s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-06 20:34:27 +01:00
eric
3a07d02c0d fix: tests pass 2026-03-06 20:34:11 +01:00
Eric
a3591b85a5 chore: update nix lib
Some checks failed
CI / test (ubuntu-latest, linux-x64) (push) Failing after 35s
CI / test (macos-14, darwin-arm64) (push) Has been cancelled
CI / test (windows-latest, windows) (push) Has been cancelled
2026-03-06 20:03:15 +01:00
208 changed files with 10264 additions and 3312 deletions

1
.bazelversion Normal file
View File

@@ -0,0 +1 @@
9.0.1

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/arl2vkxnjyw2zri2g2v6g4k6x165iidj-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/khk85hba90fc8fa8h8b920qqry6nz0qw-nix-shell-env

File diff suppressed because one or more lines are too long

View File

@@ -25,10 +25,10 @@ jobs:
phase8_target: windows phase8_target: windows
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
env: env:
USE_BAZEL_VERSION: 9.0.0 USE_BAZEL_VERSION: 9.0.1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: bazel-contrib/setup-bazel@0.15.0 - uses: bazel-contrib/setup-bazel@0.18.0
with: with:
bazelisk-cache: true bazelisk-cache: true
repository-cache: true repository-cache: true
@@ -36,6 +36,8 @@ jobs:
disk-cache: ci-${{ matrix.phase8_target }} disk-cache: ci-${{ matrix.phase8_target }}
cache-save: ${{ github.event_name != 'pull_request' }} cache-save: ${{ github.event_name != 'pull_request' }}
- name: Run tests (${{ matrix.phase8_target }}) - name: Run tests (${{ matrix.phase8_target }})
shell: bash
run: | run: |
echo "Phase 8 target: ${{ matrix.phase8_target }}" echo "Phase 8 target: ${{ matrix.phase8_target }}"
bazel test //tests/... targets="$(./tests/ci_test/phase8_ci_targets.sh "${{ matrix.phase8_target }}")"
bazel test --test_output=errors ${targets}

View File

@@ -23,14 +23,14 @@ jobs:
deploy: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
USE_BAZEL_VERSION: 9.0.0 USE_BAZEL_VERSION: 9.0.1
environment: environment:
name: github-pages name: github-pages
url: ${{ steps.deployment.outputs.page_url }} url: ${{ steps.deployment.outputs.page_url }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: bazel-contrib/setup-bazel@0.15.0 - uses: bazel-contrib/setup-bazel@0.18.0
with: with:
bazelisk-cache: true bazelisk-cache: true
repository-cache: true repository-cache: true

5
.gitignore vendored
View File

@@ -11,6 +11,7 @@
build/ build/
dist/ dist/
node_modules/ node_modules/
*/node_modules/
# Directories for the Bazel IntelliJ plugin containing the generated # Directories for the Bazel IntelliJ plugin containing the generated
# IntelliJ project files and plugin configuration. Seperate directories are # IntelliJ project files and plugin configuration. Seperate directories are
@@ -20,3 +21,7 @@ node_modules/
/.clwb/ /.clwb/
.env .env
!tests/.env
!tests/**/.env
!examples/.env
!examples/**/.env

3
.gitleaksignore Normal file
View File

@@ -0,0 +1,3 @@
tests/binary_test/.env:environment-file:1
tests/script_test/.env:environment-file:1
tests/binary_test/env_parent/.env:environment-file:1

View File

@@ -1 +0,0 @@
/nix/store/mgb6bn9dy5bpczkl81jp4r03bplwfd8w-pre-commit-config.json

View File

@@ -1 +1,9 @@
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
filegroup(
name = "repo_runtime_files",
srcs = [
"BUILD.bazel",
"MODULE.bazel",
],
)

View File

@@ -1,13 +1,16 @@
module( module(
name = "rules_bun", name = "rules_bun",
version = "0.1.0", version = "1.0.2",
) )
# Core ruleset dependencies.
bazel_dep(name = "platforms", version = "1.0.0") bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "rules_shell", version = "0.6.1") bazel_dep(name = "rules_shell", version = "0.6.1")
bazel_dep(name = "bazel_skylib", version = "1.8.2") bazel_dep(name = "bazel_skylib", version = "1.8.2")
bazel_dep(name = "stardoc", version = "0.7.2") bazel_dep(name = "stardoc", version = "0.7.2")
bazel_dep(name = "rules_multirun", version = "0.9.0", dev_dependency = True)
# Repository-local setup for this ruleset's own tests and examples.
bun_ext = use_extension("//bun:extensions.bzl", "bun") bun_ext = use_extension("//bun:extensions.bzl", "bun")
use_repo( use_repo(
bun_ext, bun_ext,
@@ -18,6 +21,37 @@ use_repo(
"bun_windows_x64", "bun_windows_x64",
) )
# Test fixture dependency installation used by //tests/script_test.
bun_install_ext = use_extension("//bun:extensions.bzl", "bun_install", dev_dependency = True)
bun_install_ext.install(
name = "script_test_vite_node_modules",
bun_lockfile = "//tests/script_test:vite_app/bun.lock",
package_json = "//tests/script_test:vite_app/package.json",
)
use_repo(bun_install_ext, "script_test_vite_node_modules")
bun_install_ext.install(
name = "script_test_vite_monorepo_node_modules",
bun_lockfile = "//tests/script_test:vite_monorepo/bun.lock",
package_json = "//tests/script_test:vite_monorepo/package.json",
)
use_repo(bun_install_ext, "script_test_vite_monorepo_node_modules")
bun_install_ext.install(
name = "script_test_paraglide_monorepo_node_modules",
bun_lockfile = "//tests/script_test:paraglide_monorepo/bun.lock",
package_json = "//tests/script_test:paraglide_monorepo/package.json",
)
use_repo(bun_install_ext, "script_test_paraglide_monorepo_node_modules")
bun_install_ext.install(
name = "examples_vite_monorepo_node_modules",
bun_lockfile = "//examples/vite_monorepo:bun.lock",
package_json = "//examples/vite_monorepo:package.json",
)
use_repo(bun_install_ext, node_modules = "examples_vite_monorepo_node_modules")
# Register the published Bun toolchains for this repository.
register_toolchains( register_toolchains(
"//bun:darwin_aarch64_toolchain", "//bun:darwin_aarch64_toolchain",
"//bun:darwin_x64_toolchain", "//bun:darwin_x64_toolchain",

123
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.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.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/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.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_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.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
"https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", "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.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/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.2/source.json": "34a3c8bcf233b835eb74be9d628899bb32999d3e0eadef1947a0a562a2b16ffb", "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.5.1/MODULE.bazel": "a35d9561b3fc5b18797c330793e99e3b834a473d5fbd3d7d7634aafc9bdb6f8f",
"https://bcr.bazel.build/modules/buildozer/8.2.1/source.json": "7c33f6a26ee0216f85544b4bca5e9044579e0219b6898dd653f5fb449cf2e484", "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/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.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", "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.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.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.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.17/MODULE.bazel": "1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84",
"https://bcr.bazel.build/modules/rules_cc/0.2.14/source.json": "55d0a4587c5592fad350f6e698530f4faf0e7dd15e69d43f8d87e220c78bea54", "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_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_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
@@ -141,6 +142,8 @@
"https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d",
"https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c",
"https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb",
"https://bcr.bazel.build/modules/rules_multirun/0.9.0/MODULE.bazel": "32d628ef586b5b23f67e55886b7bc38913ea4160420d66ae90521dda2ff37df0",
"https://bcr.bazel.build/modules/rules_multirun/0.9.0/source.json": "e882ba77962fa6c5fe68619e5c7d0374ec9a219fb8d03c42eadaf6d0243771bd",
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
"https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff",
"https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a",
@@ -153,6 +156,7 @@
"https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
"https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300",
"https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382",
"https://bcr.bazel.build/modules/rules_python/0.27.1/MODULE.bazel": "65dc875cc1a06c30d5bbdba7ab021fd9e551a6579e408a3943a61303e2228a53",
"https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed",
"https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58",
"https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937", "https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937",
@@ -189,8 +193,8 @@
"moduleExtensions": { "moduleExtensions": {
"//bun:extensions.bzl%bun": { "//bun:extensions.bzl%bun": {
"general": { "general": {
"bzlTransitiveDigest": "oLR98WtKDCc+zh7Tvu9jtakNg8q/T1IPE38QR1FEQtI=", "bzlTransitiveDigest": "314UOH4dQIGBHGpxCwA7yzI++E2J3bjIc20m5MZhM7U=",
"usagesDigest": "NfJgMuTjZXXRLr1/kxxFkS1IKV2UyehFyr3fMvAke/k=", "usagesDigest": "8lJhlTN0tALSLMIVpAoPHAUJ7DsvdI3M6FYRhgsDFtU=",
"recordedInputs": [ "recordedInputs": [
"REPO_MAPPING:,bazel_tools bazel_tools" "REPO_MAPPING:,bazel_tools bazel_tools"
], ],
@@ -215,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" "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": { "bun_darwin_x64": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": { "attributes": {
@@ -244,6 +268,91 @@
"sha256": "7a77b3e245e2e26965c93089a4a1332e8a326d3364c89fae1d1fd99cdd3cd73d", "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" "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"
}
}
}
}
},
"//bun:extensions.bzl%bun_install": {
"general": {
"bzlTransitiveDigest": "314UOH4dQIGBHGpxCwA7yzI++E2J3bjIc20m5MZhM7U=",
"usagesDigest": "x+qjsT8RcvKKj6+UXY1J8kq8wHRbimCNctw3IUTdYzY=",
"recordedInputs": [
"REPO_MAPPING:,bazel_tools bazel_tools"
],
"generatedRepoSpecs": {
"script_test_vite_node_modules": {
"repoRuleId": "@@//internal:bun_install.bzl%bun_install_repository",
"attributes": {
"package_json": "@@//tests/script_test:vite_app/package.json",
"bun_lockfile": "@@//tests/script_test:vite_app/bun.lock",
"install_inputs": [],
"isolated_home": true,
"production": false,
"omit": [],
"linker": "",
"backend": "",
"ignore_scripts": true,
"install_flags": [],
"visible_repo_name": "script_test_vite_node_modules"
}
},
"script_test_vite_monorepo_node_modules": {
"repoRuleId": "@@//internal:bun_install.bzl%bun_install_repository",
"attributes": {
"package_json": "@@//tests/script_test:vite_monorepo/package.json",
"bun_lockfile": "@@//tests/script_test:vite_monorepo/bun.lock",
"install_inputs": [],
"isolated_home": true,
"production": false,
"omit": [],
"linker": "",
"backend": "",
"ignore_scripts": true,
"install_flags": [],
"visible_repo_name": "script_test_vite_monorepo_node_modules"
}
},
"script_test_paraglide_monorepo_node_modules": {
"repoRuleId": "@@//internal:bun_install.bzl%bun_install_repository",
"attributes": {
"package_json": "@@//tests/script_test:paraglide_monorepo/package.json",
"bun_lockfile": "@@//tests/script_test:paraglide_monorepo/bun.lock",
"install_inputs": [],
"isolated_home": true,
"production": false,
"omit": [],
"linker": "",
"backend": "",
"ignore_scripts": true,
"install_flags": [],
"visible_repo_name": "script_test_paraglide_monorepo_node_modules"
}
},
"examples_vite_monorepo_node_modules": {
"repoRuleId": "@@//internal:bun_install.bzl%bun_install_repository",
"attributes": {
"package_json": "@@//examples/vite_monorepo:package.json",
"bun_lockfile": "@@//examples/vite_monorepo:bun.lock",
"install_inputs": [],
"isolated_home": true,
"production": false,
"omit": [],
"linker": "",
"backend": "",
"ignore_scripts": true,
"install_flags": [],
"visible_repo_name": "examples_vite_monorepo_node_modules"
}
} }
} }
} }

342
README.md
View File

@@ -1,191 +1,299 @@
# rules_bun # Bun rules for [Bazel](https://bazel.build)
Bazel rules for bun. `rules_bun` provides Bazel rules for running, testing, building, compiling,
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`.
Runtime launcher targets from `bun_binary`, `bun_script`, `bun_test`,
`bun_dev`, and `js_run_devserver` use native platform wrappers. Windows runtime
support is native and does not require Git Bash or MSYS.
## Public API
`rules_bun` exports these primary rules:
- `bun_binary`
- `bun_build`
- `bun_compile`
- `bun_bundle`
- `bun_dev`
- `bun_script`
- `bun_test`
- `js_binary`
- `js_test`
- `js_run_devserver`
- `js_library`
- `ts_library`
Reference documentation:
- Published docs site: https://eriyc.github.io/rules_bun/ - Published docs site: https://eriyc.github.io/rules_bun/
- Generated API docs: [docs/rules.md](docs/rules.md) - Generated build rule reference: [docs/rules.md](docs/rules.md)
- Regenerate: `bazel build //docs:rules_md && cp bazel-bin/docs/rules.md docs/rules.md` - `bun_install` extension docs: [docs/bun_install.md](docs/bun_install.md)
- Docs index: [docs/index.md](docs/index.md)
## Use ## Hermeticity
These steps show how to consume a tagged release of `rules_bun` in a separate Bazel workspace. `rules_bun` now draws a sharp line between hermetic rule surfaces and local
workflow helpers.
### 1) Add the module dependency - Hermetic build/test surfaces: `bun_build`, `bun_bundle`, `bun_compile`, `bun_test`
- Runfiles-only executable surface: `bun_binary`
- Reproducible but non-hermetic repository fetch surface: `bun_install`
- Local workflow helpers: `bun_script`, `bun_dev`, `js_run_devserver`
In your project's `MODULE.bazel`, add: Strict defaults are enabled by default:
```starlark - `bun_install` skips lifecycle scripts unless `ignore_scripts = False`
bazel_dep(name = "rules_bun", version = "0.1.0") - `bun_build`, `bun_bundle`, `bun_compile`, and `bun_test` require `install_mode = "disable"`
- Runtime launchers do not inherit the host `PATH` unless `inherit_host_path = True`
archive_override( To refresh generated rule docs:
module_name = "rules_bun",
urls = ["https://github.com/Eriyc/rules_bun/archiv0.0.5.tar.gz"], ```bash
strip_prefix = "rules_bun-v0.1.0", bazel build //docs:rules_md && cp bazel-bin/docs/rules.md docs/rules.md
)
``` ```
For channel/pre-release tags (for example `v0.1.0-rc.1`), use the matching folder prefix: ## Bzlmod usage
Release announcements should provide a copy-pasteable module snippet in the
standard ruleset form:
```starlark ```starlark
bazel_dep(name = "rules_bun", version = "0.1.0-rc.1") bazel_dep(name = "rules_bun", version = "1.0.2")
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.1.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`. Then add the Bun repositories and register the toolchains in `MODULE.bazel`:
### 2) Create Bun repositories with the extension
Still in `MODULE.bazel`, add:
```starlark ```starlark
bun_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun") bun_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun")
use_repo( use_repo(
bun_ext, bun_ext,
"bun_linux_x64", "bun_linux_x64",
"bun_linux_aarch64", "bun_linux_aarch64",
"bun_darwin_x64", "bun_linux_x64_musl",
"bun_darwin_aarch64", "bun_linux_aarch64_musl",
"bun_windows_x64", "bun_darwin_x64",
"bun_darwin_aarch64",
"bun_windows_x64",
"bun_windows_aarch64",
) )
```
### 3) Register toolchains
Also in `MODULE.bazel`, register:
```starlark
register_toolchains( register_toolchains(
"@rules_bun//bun:darwin_aarch64_toolchain", "@rules_bun//bun:darwin_aarch64_toolchain",
"@rules_bun//bun:darwin_x64_toolchain", "@rules_bun//bun:darwin_x64_toolchain",
"@rules_bun//bun:linux_aarch64_toolchain", "@rules_bun//bun:linux_aarch64_toolchain",
"@rules_bun//bun:linux_x64_toolchain", "@rules_bun//bun:linux_x64_toolchain",
"@rules_bun//bun:windows_x64_toolchain", "@rules_bun//bun:windows_x64_toolchain",
) )
``` ```
### 4) Load rules in `BUILD.bazel` If you want Bazel-managed dependency installation, also add the module
extension for `bun_install`:
```starlark `bun_install` runs `bun install`, not `npm install`. In the example below,
load( `bun_deps` is just the Bazel repository name for the generated
"@rules_bun//bun:defs.bzl", `node_modules` tree. See [docs/bun_install.md](docs/bun_install.md) for the
"bun_binary", full extension reference.
"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:
```starlark ```starlark
bun_install_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun_install") bun_install_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun_install")
bun_install_ext.install( bun_install_ext.install(
name = "npm", name = "bun_deps",
package_json = "//:package.json", package_json = "//:package.json",
bun_lockfile = "//:bun.lock", bun_lockfile = "//:bun.lock",
# Optional: include extra install-time files.
# install_inputs = ["//:.npmrc"],
# Optional non-hermetic opt-in:
# ignore_scripts = False,
# isolated_home = False,
) )
use_repo(bun_install_ext, "npm") use_repo(bun_install_ext, "bun_deps")
``` ```
### 6) Verify setup ## `rules_js` compatibility layer
Run one of your bun-backed targets, for example: `rules_bun` now exposes a Bun-backed compatibility layer for the most common
`rules_js` entrypoints:
```bash - `@rules_bun//js:defs.bzl` exports `js_binary`, `js_test`, `js_run_devserver`,
bazel test //path/to:your_bun_test `js_library`, `ts_library`, and `JsInfo`.
- `@rules_bun//npm:extensions.bzl` exports `npm_translate_lock`, which creates a
Bun-installed external repo and generates `@<repo>//:defs.bzl` with
`npm_link_all_packages()`.
Example:
```starlark
load("@rules_bun//js:defs.bzl", "js_binary")
load("@npm//:defs.bzl", "npm_link_all_packages")
npm_link_all_packages()
js_binary(
name = "app",
entry_point = "src/main.ts",
node_modules = ":node_modules",
)
``` ```
All `rules_bun` rule-driven Bun invocations pass `--bun`. This is a compatibility subset, not a full reimplementation of `rules_js`.
Package aliases created by `npm_link_all_packages()` use sanitized target names
such as `npm__vite` or `npm__at_types_node`.
## Package scripts (`bun_script`) ## Legacy WORKSPACE usage
Use `bun_script` to expose a `package.json` script as a Bazel executable target. For non-Bzlmod consumers, the repository exposes a legacy setup macro in
`@rules_bun//bun:repositories.bzl`:
```starlark
load("@rules_bun//bun:repositories.bzl", "bun_register_toolchains")
bun_register_toolchains()
```
## Loading rules in BUILD files
```starlark
load(
"@rules_bun//bun:defs.bzl",
"bun_binary",
"bun_build",
"bun_compile",
"bun_bundle",
"bun_dev",
"bun_script",
"bun_test",
"js_library",
"ts_library",
)
```
## 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 ```starlark
load("@rules_bun//bun:defs.bzl", "bun_script") load("@rules_bun//bun:defs.bzl", "bun_script")
bun_script( bun_script(
name = "web_dev", name = "web_dev",
script = "dev", script = "dev",
package_json = "package.json", package_json = "package.json",
node_modules = "@npm//:node_modules", node_modules = "@bun_deps//:node_modules",
data = glob([ data = glob([
"src/**", "src/**",
"static/**", "static/**",
"vite.config.*", "vite.config.*",
"svelte.config.*", "svelte.config.*",
"tsconfig*.json", "tsconfig*.json",
]), ]),
) )
``` ```
Run it with: When `node_modules` is provided, executables from `node_modules/.bin` are added
to the runtime `PATH`. The host `PATH` is not inherited unless
`inherit_host_path = True`. This label typically comes from `bun_install`,
which still produces a standard `node_modules/` directory.
```bash ### `bun_build` and `bun_compile`
bazel run //path/to:web_dev -- --host
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_script` defaults to running from the directory containing `package.json`, which matches the usual expectations for `vite`, `svelte-kit`, and similar package scripts. `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`. When `root` is omitted,
`bun_build` derives a stable default from the entry point parent directory so
HTML and asset output stays inside Bazel's declared output tree.
## Development mode (`bun_dev`) ### `bun_dev` for local development
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 ```starlark
load("@rules_bun//bun:defs.bzl", "bun_dev") load("@rules_bun//bun:defs.bzl", "bun_dev")
bun_dev( bun_dev(
name = "web_dev", name = "web_dev",
entry_point = "src/main.ts", entry_point = "src/main.ts",
# Optional: run from the entry point directory so Bun auto-loads colocated .env files. # Optional: run from the entry point directory so Bun auto-loads colocated .env files.
# working_dir = "entry_point", # working_dir = "entry_point",
) )
``` ```
Run it with: Supported development options include:
```bash - `watch_mode = "watch"`
bazel run //path/to:web_dev - `watch_mode = "hot"`
``` - `restart_on = [...]`
- `working_dir = "workspace" | "entry_point"`
`bun_dev` supports: ### Working directory behavior
- `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`)
`bun_binary` and `bun_dev` support `working_dir`: `bun_binary` and `bun_dev` support `working_dir`:
- `"workspace"` (default): runs from the Bazel runfiles workspace root. - `"workspace"`: run 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). - `"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`. - [examples/basic/README.md](examples/basic/README.md)
2. Put generated artifacts or bridge files in `restart_on` (for example generated JS/TS files from proto/go steps). - [examples/workspace/README.md](examples/workspace/README.md)
3. Rebuild Go/proto artifacts separately (for example with `ibazel build`) so their output files change. - [examples/vite_monorepo/README.md](examples/vite_monorepo/README.md)
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.
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

@@ -1,3 +1,3 @@
0.1.0 1.0.2
stable stable
0 0

View File

@@ -1,5 +1,24 @@
workspace(name = "rules_bun") workspace(name = "rules_bun")
load("//internal:bun_install.bzl", "bun_install")
load("//bun:repositories.bzl", "bun_register_toolchains") load("//bun:repositories.bzl", "bun_register_toolchains")
bun_register_toolchains() bun_register_toolchains()
bun_install(
name = "script_test_vite_node_modules",
package_json = "//tests/script_test:vite_app/package.json",
bun_lockfile = "//tests/script_test:vite_app/bun.lock",
)
bun_install(
name = "script_test_vite_monorepo_node_modules",
package_json = "//tests/script_test:vite_monorepo/package.json",
bun_lockfile = "//tests/script_test:vite_monorepo/bun.lock",
)
bun_install(
name = "examples_vite_monorepo_node_modules",
package_json = "//examples/vite_monorepo:package.json",
bun_lockfile = "//examples/vite_monorepo:bun.lock",
)

View File

@@ -5,25 +5,57 @@ load(":version.bzl", "BUN_VERSION")
exports_files([ exports_files([
"defs.bzl", "defs.bzl",
"extensions.bzl", "extensions.bzl",
"repositories.bzl",
"toolchain.bzl",
"version.bzl",
]) ])
filegroup(
name = "repo_runtime_files",
srcs = [
"BUILD.bazel",
"defs.bzl",
"extensions.bzl",
"repositories.bzl",
"toolchain.bzl",
"version.bzl",
],
visibility = ["//visibility:public"],
)
bzl_library( bzl_library(
name = "toolchain_bzl", name = "toolchain_bzl",
srcs = ["toolchain.bzl"], srcs = ["toolchain.bzl"],
visibility = ["//visibility:public"], 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( bzl_library(
name = "defs_bzl", name = "defs_bzl",
srcs = ["defs.bzl"], srcs = ["defs.bzl"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":toolchain_bzl", ":toolchain_bzl",
"//internal:bun_build_support_bzl",
"//internal:bun_binary_bzl", "//internal:bun_binary_bzl",
"//internal:bun_compile_bzl",
"//internal:bun_bundle_bzl", "//internal:bun_bundle_bzl",
"//internal:bun_dev_bzl", "//internal:bun_dev_bzl",
"//internal:bun_script_bzl", "//internal:bun_script_bzl",
"//internal:bun_test_bzl", "//internal:bun_test_bzl",
"//internal:js_compat_bzl",
"//internal:js_library_bzl", "//internal:js_library_bzl",
], ],
) )

View File

@@ -1,21 +1,29 @@
"""Public API surface for Bun Bazel rules.""" """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_binary.bzl", _bun_binary = "bun_binary")
load("//internal:bun_bundle.bzl", _bun_bundle = "bun_bundle") load("//internal:bun_bundle.bzl", _bun_bundle = "bun_bundle")
load("//internal:bun_dev.bzl", _bun_dev = "bun_dev") load("//internal:bun_dev.bzl", _bun_dev = "bun_dev")
load("//internal:bun_script.bzl", _bun_script = "bun_script") load("//internal:bun_script.bzl", _bun_script = "bun_script")
load("//internal:bun_test.bzl", _bun_test = "bun_test") load("//internal:bun_test.bzl", _bun_test = "bun_test")
load("//internal:js_compat.bzl", _JsInfo = "JsInfo", _js_binary = "js_binary", _js_run_devserver = "js_run_devserver", _js_test = "js_test")
load("//internal:js_library.bzl", _js_library = "js_library", _ts_library = "ts_library") load("//internal:js_library.bzl", _js_library = "js_library", _ts_library = "ts_library")
load(":toolchain.bzl", _BunToolchainInfo = "BunToolchainInfo", _bun_toolchain = "bun_toolchain") load(":toolchain.bzl", _BunToolchainInfo = "BunToolchainInfo", _bun_toolchain = "bun_toolchain")
visibility("public") visibility("public")
bun_binary = _bun_binary bun_binary = _bun_binary
bun_build = _bun_build
bun_compile = _bun_compile
bun_bundle = _bun_bundle bun_bundle = _bun_bundle
bun_dev = _bun_dev bun_dev = _bun_dev
bun_script = _bun_script bun_script = _bun_script
bun_test = _bun_test bun_test = _bun_test
js_binary = _js_binary
js_test = _js_test
js_run_devserver = _js_run_devserver
js_library = _js_library js_library = _js_library
ts_library = _ts_library ts_library = _ts_library
JsInfo = _JsInfo
BunToolchainInfo = _BunToolchainInfo BunToolchainInfo = _BunToolchainInfo
bun_toolchain = _bun_toolchain bun_toolchain = _bun_toolchain

View File

@@ -13,6 +13,16 @@ _BUN_ARCHIVES = {
"asset": "bun-linux-aarch64.zip", "asset": "bun-linux-aarch64.zip",
"binary": "bun-linux-aarch64/bun", "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": { "bun_darwin_x64": {
"sha256": "c1d90bf6140f20e572c473065dc6b37a4b036349b5e9e4133779cc642ad94323", "sha256": "c1d90bf6140f20e572c473065dc6b37a4b036349b5e9e4133779cc642ad94323",
"asset": "bun-darwin-x64.zip", "asset": "bun-darwin-x64.zip",
@@ -28,6 +38,11 @@ _BUN_ARCHIVES = {
"asset": "bun-windows-x64.zip", "asset": "bun-windows-x64.zip",
"binary": "bun-windows-x64/bun.exe", "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{}/{}" _BUN_GITHUB_RELEASE_URL_TEMPLATE = "https://github.com/oven-sh/bun/releases/download/bun-v{}/{}"
@@ -58,8 +73,16 @@ bun = module_extension(
_install = tag_class( _install = tag_class(
attrs = { attrs = {
"name": attr.string(mandatory = True), "name": attr.string(mandatory = True),
"package_json": attr.string(mandatory = True), "package_json": attr.label(mandatory = True),
"bun_lockfile": attr.string(mandatory = True), "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 = True),
"install_flags": attr.string_list(),
}, },
) )
@@ -71,6 +94,15 @@ def _bun_install_impl(ctx):
name = install.name, name = install.name,
package_json = install.package_json, package_json = install.package_json,
bun_lockfile = install.bun_lockfile, 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", "asset": "bun-linux-aarch64.zip",
"binary": "bun-linux-aarch64/bun", "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": { "bun_darwin_x64": {
"sha256": "c1d90bf6140f20e572c473065dc6b37a4b036349b5e9e4133779cc642ad94323", "sha256": "c1d90bf6140f20e572c473065dc6b37a4b036349b5e9e4133779cc642ad94323",
"asset": "bun-darwin-x64.zip", "asset": "bun-darwin-x64.zip",
@@ -27,6 +37,11 @@ _BUN_ARCHIVES = {
"asset": "bun-windows-x64.zip", "asset": "bun-windows-x64.zip",
"binary": "bun-windows-x64/bun.exe", "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{}/{}" _BUN_GITHUB_RELEASE_URL_TEMPLATE = "https://github.com/oven-sh/bun/releases/download/bun-v{}/{}"

View File

@@ -8,10 +8,15 @@ stardoc(
input = "//bun:defs.bzl", input = "//bun:defs.bzl",
symbol_names = [ symbol_names = [
"bun_binary", "bun_binary",
"bun_build",
"bun_compile",
"bun_bundle", "bun_bundle",
"bun_dev", "bun_dev",
"bun_script", "bun_script",
"bun_test", "bun_test",
"js_binary",
"js_run_devserver",
"js_test",
"js_library", "js_library",
"ts_library", "ts_library",
], ],

186
docs/bun_install.md Normal file
View File

@@ -0,0 +1,186 @@
# `bun_install`
`bun_install` is a Bzlmod module extension for creating an external repository
that contains a Bun-generated `node_modules/` tree.
Unlike the build rules in [rules.md](rules.md), `bun_install` is not loaded from
`@rules_bun//bun:defs.bzl`. It is loaded from
`@rules_bun//bun:extensions.bzl`, so it is documented separately.
## What it does
`bun_install`:
- runs `bun install --frozen-lockfile`
- uses your checked-in `package.json` and `bun.lock` or `bun.lockb`
- creates an external Bazel repository exposing `:node_modules`
- generates `:defs.bzl` with `npm_link_all_packages()` and `package_target_name()`
- keeps dependency installation under Bun rather than npm
The generated repository can then be passed to rules such as `bun_script`,
`bun_binary`, `bun_bundle`, and `bun_test`.
## Hermeticity
`bun_install` is a repository convenience rule, not a hermetic build action.
It is intended to be reproducible from a checked-in lockfile and pinned Bun
toolchain, but it still performs dependency fetching as part of repository
materialization.
Strict defaults now favor reproducibility:
- `isolated_home = True`
- `ignore_scripts = True`
Set `ignore_scripts = False` only when you explicitly want lifecycle scripts to
run during repository creation.
## Usage
```starlark
bun_install_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun_install")
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")
```
Then reference the installed dependencies from build targets:
```starlark
load("@rules_bun//bun:defs.bzl", "bun_script")
bun_script(
name = "web_dev",
script = "dev",
package_json = "package.json",
node_modules = "@bun_deps//:node_modules",
)
```
## `install(...)` attributes
### `name`
Repository name to create.
This becomes the external repository you reference later, for example
`@bun_deps//:node_modules`.
### `package_json`
Label string pointing to the source `package.json` file.
Example:
```starlark
package_json = "//:package.json"
```
### `bun_lockfile`
Label string pointing to the Bun lockfile.
Supported lockfile names are:
- `bun.lock`
- `bun.lockb`
Example:
```starlark
bun_lockfile = "//:bun.lock"
```
### `install_inputs`
Optional list of additional files under the same package root to copy into the
install repository before Bun runs.
Use this for install-time config or patch files that Bun needs to see, for
example `.npmrc`, `bunfig.toml`, or patch files referenced by your manifest.
Example:
```starlark
install_inputs = [
"//:.npmrc",
"//:patches/react.patch",
]
```
`bun_install` also copies these root-level files automatically when present:
- `.npmrc`
- `bunfig.json`
- `bunfig.toml`
### `isolated_home`
Optional boolean controlling whether Bun runs with `HOME` set to the generated
repository root.
- `True` (default): more isolated install environment
- `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.
- `True` (default): skips lifecycle scripts for stricter, more reproducible installs
- `False`: allows lifecycle scripts to run during repository creation
### `install_flags`
Optional list of additional raw flags forwarded to `bun install`.
## Notes
- `bun_install` runs Bun, not npm.
- The repository name is arbitrary. `bun_deps` is only an example.
- The generated repository exposes a standard `node_modules/` tree because that
is the dependency layout Bun installs.
- `--frozen-lockfile` is used, so the lockfile must already be in sync with
`package.json`.
- Additional `install_inputs` must be files under the same package root as the
selected `package_json`.
- `bun_install` does not make the install step remotely hermetic; it makes the
generated repository stricter and more reproducible by default.

View File

@@ -1,14 +1,104 @@
# rules_bun docs # 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 build rule reference
- [docs/bun_install.md](bun_install.md) for `bun_install` extension docs
## Hermeticity
- Hermetic rule surfaces: `bun_build`, `bun_bundle`, `bun_compile`, `bun_test`
- Runfiles-only executable surface: `bun_binary`
- Reproducible but non-hermetic repository surface: `bun_install`
- Local workflow helpers: `bun_script`, `bun_dev`, `js_run_devserver`
## Rule reference ## Rule reference
- [rules.md](rules.md) - [rules.md](rules.md)
## Bzlmod extensions
- [bun_install.md](bun_install.md)
## Typical Bzlmod setup
```starlark
bazel_dep(name = "rules_bun", version = "0.2.1")
bun_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun")
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(
"@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`.
The `node_modules` label below refers to dependencies installed by
`bun_install`.
```starlark
load("@rules_bun//bun:defs.bzl", "bun_script")
bun_script(
name = "web_dev",
script = "dev",
package_json = "package.json",
node_modules = "@my_workspace//: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`.
## 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 ## 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 ```bash
bazel build //docs:rules_md bazel build //docs:rules_md

View File

@@ -1,84 +1,499 @@
# 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.
## Hermeticity And Determinism
- Hermetic rule surfaces: `bun_build`, `bun_bundle`, `bun_compile`, `bun_test`
- Runfiles-only executable surface: `bun_binary`
- Reproducible but non-hermetic repository surface: `bun_install`
- Local workflow helpers: `bun_script`, `bun_dev`, `js_run_devserver`
Strict defaults:
- `bun_build`, `bun_bundle`, `bun_compile`, and `bun_test` require `install_mode = "disable"`
- Runtime launchers do not inherit the host `PATH` unless `inherit_host_path = True`
<a id="bun_binary"></a>
## bun_binary ## 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. Runs a JS/TS entry point with Bun as an executable target.
- `node_modules` (label, optional): Bun/npm package files in runfiles.
- `data` (label_list, optional): additional runtime files.
- `working_dir` (string, default: `"workspace"`, values: `"workspace" | "entry_point"`): runtime working directory.
## 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. | Name | Description | Type | Mandatory | Default |
- `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. | <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 | |
- `node_modules` (label, optional): Bun/npm package files in runfiles. | <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 | `[]` |
- `data` (label_list, optional): additional runtime files for dev process. | <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 | `[]` |
- `working_dir` (string, default: `"workspace"`, values: `"workspace" | "entry_point"`): runtime working directory. | <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. Non-`disable` values are runtime opt-ins and are not hermetic. | String | optional | `"disable"` |
| <a id="bun_binary-inherit_host_path"></a>inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| <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>
Attributes: ## bun_build
- `script` (string, required): package script name passed to `bun run <script>`. <pre>
- `package_json` (label, required): `package.json` file containing the named script. load("@rules_bun//bun:defs.bzl", "bun_build")
- `node_modules` (label, optional): Bun/npm package files in runfiles.
- `data` (label_list, optional): additional runtime files for the script. 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>,
- `working_dir` (string, default: `"package"`, values: `"workspace" | "package"`): runtime working directory. <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. Hermetic builds require `\"disable\"`, and other values are rejected. | 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. When omitted, `bun_build` derives one from the entry point parent directories to keep emitted files inside the declared output tree. | 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 ## 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. Bundles one or more JS/TS entry points using Bun build.
- `node_modules` (label, optional): Bun/npm package files for resolution.
- `deps` (label_list, optional): source/library dependencies for transitive inputs. Each entry point produces one output JavaScript artifact.
- `data` (label_list, optional): additional non-source files needed during bundling.
- `target` (string, default: `"browser"`, values: `"browser" | "node" | "bun"`): Bun build target. **ATTRIBUTES**
- `format` (string, default: `"esm"`, values: `"esm" | "cjs" | "iife"`): module format.
- `minify` (bool, default: `False`): minifies bundle output.
- `sourcemap` (bool, default: `False`): emits source maps. | Name | Description | Type | Mandatory | Default |
- `external` (string_list, optional): package names treated as external (not bundled). | :------------- | :------------- | :------------- | :------------- | :------------- |
| <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. Hermetic bundles require `\"disable\"`, and other values are rejected. | 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. Hermetic compile actions require `\"disable\"`, and other values are rejected. | 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. This is a local workflow helper, not a hermetic execution surface. | String | optional | `"disable"` |
| <a id="bun_dev-inherit_host_path"></a>inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| <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. This is a local workflow helper, not a hermetic execution surface. | String | optional | `"disable"` |
| <a id="bun_script-inherit_host_path"></a>inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| <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 ## 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`. Runs Bun tests as a Bazel test target.
- `node_modules` (label, optional): Bun/npm package files in runfiles.
- `deps` (label_list, optional): library dependencies required by tests. Supports Bazel test filtering (`--test_filter`) and coverage integration.
- `data` (label_list, optional): additional runtime files needed by tests.
**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. Hermetic tests require `\"disable\"`, and other values are rejected. | String | optional | `"disable"` |
| <a id="bun_test-inherit_host_path"></a>inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| <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 ## 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. Aggregates JavaScript sources and transitive Bun source dependencies.
Attributes: **ATTRIBUTES**
- `srcs` (label_list, optional): `.js`, `.jsx`, `.mjs`, `.cjs` files.
- `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-inherit_host_path"></a>inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| <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 ## 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. Aggregates TypeScript sources and transitive Bun source dependencies.
Attributes: **ATTRIBUTES**
- `srcs` (label_list, optional): `.ts`, `.tsx` files.
- `deps` (label_list, optional): dependent source libraries. | 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 |

View File

@@ -11,3 +11,11 @@ bun_dev(
name = "web_dev", name = "web_dev",
entry_point = "main.ts", entry_point = "main.ts",
) )
bun_dev(
name = "web_dev_hot_restart",
entry_point = "main.ts",
no_clear_screen = True,
restart_on = ["README.md"],
watch_mode = "hot",
)

View File

@@ -9,3 +9,12 @@ bazel run //examples/basic:web_dev
``` ```
This starts Bun in watch mode for `main.ts`. This starts Bun in watch mode for `main.ts`.
For the hot-reload launcher variant:
```bash
bazel run //examples/basic:web_dev_hot_restart
```
This starts Bun with `watch_mode = "hot"`, disables screen clearing, and wires
`README.md` through `restart_on` to exercise the custom restart launcher path.

1
examples/vite_monorepo/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
bazel-*

View File

@@ -0,0 +1,61 @@
load("@rules_bun//bun:defs.bzl", "bun_script")
# //:BUILD.bazel
load("@rules_multirun//:defs.bzl", "multirun")
load("@rules_shell//shell:sh_test.bzl", "sh_test")
package(default_visibility = ["//visibility:public"])
exports_files([
"README.md",
"package.json",
"bun.lock",
"apps/app-a/package.json",
"apps/app-b/package.json",
])
multirun(
name = "dev",
commands = [
":app_a_dev",
":app_b_dev",
],
jobs = 0,
)
bun_script(
name = "app_a_dev",
data = [
"apps/app-a/index.html",
"apps/app-a/main.js",
"apps/app-a/vite.config.js",
],
node_modules = "@node_modules//:node_modules",
package_json = "apps/app-a/package.json",
script = "dev",
)
bun_script(
name = "app_b_dev",
data = [
"apps/app-b/index.html",
"apps/app-b/main.js",
"apps/app-b/vite.config.js",
],
node_modules = "@node_modules//:node_modules",
package_json = "apps/app-b/package.json",
script = "dev",
)
sh_test(
name = "vite_monorepo_workspace_resolution_test",
srcs = ["run_vite_monorepo_apps.sh"],
args = [
"$(location :app_a_dev)",
"$(location :app_b_dev)",
],
data = [
":app_a_dev",
":app_b_dev",
],
)

View File

@@ -0,0 +1,39 @@
module(
name = "rules_bun_example_vite_monorepo",
version = "0.1.0",
)
bazel_dep(name = "rules_bun", version = "0.2.2")
bazel_dep(name = "rules_multirun", version = "0.9.0")
bazel_dep(name = "rules_shell", version = "0.6.1")
local_path_override(
module_name = "rules_bun",
path = "../..",
)
bun_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun")
use_repo(
bun_ext,
"bun_darwin_aarch64",
"bun_darwin_x64",
"bun_linux_aarch64",
"bun_linux_x64",
"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",
)
bun_install_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun_install")
bun_install_ext.install(
name = "npm",
bun_lockfile = "//:bun.lock",
package_json = "//:package.json",
)
use_repo(bun_install_ext, node_modules = "npm")

531
examples/vite_monorepo/MODULE.bazel.lock generated Normal file
View File

@@ -0,0 +1,531 @@
{
"lockFileVersion": 26,
"registryFileHashes": {
"https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
"https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2",
"https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589",
"https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0",
"https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb",
"https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16",
"https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915",
"https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed",
"https://bcr.bazel.build/modules/abseil-cpp/20240116.2/MODULE.bazel": "73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16",
"https://bcr.bazel.build/modules/abseil-cpp/20250127.1/MODULE.bazel": "c4a89e7ceb9bf1e25cf84a9f830ff6b817b72874088bf5141b314726e46a57c1",
"https://bcr.bazel.build/modules/abseil-cpp/20250512.1/MODULE.bazel": "d209fdb6f36ffaf61c509fcc81b19e81b411a999a934a032e10cd009a0226215",
"https://bcr.bazel.build/modules/abseil-cpp/20250814.1/MODULE.bazel": "51f2312901470cdab0dbdf3b88c40cd21c62a7ed58a3de45b365ddc5b11bcab2",
"https://bcr.bazel.build/modules/abseil-cpp/20250814.1/source.json": "cea3901d7e299da7320700abbaafe57a65d039f10d0d7ea601c4a66938ea4b0c",
"https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896",
"https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85",
"https://bcr.bazel.build/modules/apple_support/1.21.0/MODULE.bazel": "ac1824ed5edf17dee2fdd4927ada30c9f8c3b520be1b5fd02a5da15bc10bff3e",
"https://bcr.bazel.build/modules/apple_support/1.21.1/MODULE.bazel": "5809fa3efab15d1f3c3c635af6974044bac8a4919c62238cce06acee8a8c11f1",
"https://bcr.bazel.build/modules/apple_support/1.24.2/MODULE.bazel": "0e62471818affb9f0b26f128831d5c40b074d32e6dda5a0d3852847215a41ca4",
"https://bcr.bazel.build/modules/apple_support/1.24.2/source.json": "2c22c9827093250406c5568da6c54e6fdf0ef06238def3d99c71b12feb057a8d",
"https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd",
"https://bcr.bazel.build/modules/bazel_features/1.10.0/MODULE.bazel": "f75e8807570484a99be90abcd52b5e1f390362c258bcb73106f4544957a48101",
"https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
"https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d",
"https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d",
"https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a",
"https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58",
"https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b",
"https://bcr.bazel.build/modules/bazel_features/1.23.0/MODULE.bazel": "fd1ac84bc4e97a5a0816b7fd7d4d4f6d837b0047cf4cbd81652d616af3a6591a",
"https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65",
"https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d",
"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.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",
"https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686",
"https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
"https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
"https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d",
"https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651",
"https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138",
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
"https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d",
"https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
"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/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",
"https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
"https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108",
"https://bcr.bazel.build/modules/googletest/1.17.0/MODULE.bazel": "dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46",
"https://bcr.bazel.build/modules/googletest/1.17.0/source.json": "38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713",
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075",
"https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0",
"https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000",
"https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902",
"https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74",
"https://bcr.bazel.build/modules/nlohmann_json/3.6.1/source.json": "f448c6e8963fdfa7eb831457df83ad63d3d6355018f6574fb017e8169deb43a9",
"https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5",
"https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f",
"https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
"https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
"https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
"https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814",
"https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d",
"https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc",
"https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580",
"https://bcr.bazel.build/modules/platforms/1.0.0/source.json": "f4ff1fd412e0246fd38c82328eb209130ead81d62dcd5a9e40910f867f733d96",
"https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7",
"https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c",
"https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df",
"https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92",
"https://bcr.bazel.build/modules/protobuf/29.1/MODULE.bazel": "557c3457560ff49e122ed76c0bc3397a64af9574691cb8201b4e46d4ab2ecb95",
"https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
"https://bcr.bazel.build/modules/protobuf/32.1/MODULE.bazel": "89cd2866a9cb07fee9ff74c41ceace11554f32e0d849de4e23ac55515cfada4d",
"https://bcr.bazel.build/modules/protobuf/33.4/MODULE.bazel": "114775b816b38b6d0ca620450d6b02550c60ceedfdc8d9a229833b34a223dc42",
"https://bcr.bazel.build/modules/protobuf/33.4/source.json": "555f8686b4c7d6b5ba731fbea13bf656b4bfd9a7ff629c1d9d3f6e1d6155de79",
"https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e",
"https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34",
"https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/source.json": "6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680",
"https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206",
"https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/MODULE.bazel": "b4963dda9b31080be1905ef085ecd7dd6cd47c05c79b9cdf83ade83ab2ab271a",
"https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/source.json": "2ff292be6ef3340325ce8a045ecc326e92cbfab47c7cbab4bd85d28971b97ac4",
"https://bcr.bazel.build/modules/re2/2024-07-02/MODULE.bazel": "0eadc4395959969297cbcf31a249ff457f2f1d456228c67719480205aa306daa",
"https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8",
"https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e",
"https://bcr.bazel.build/modules/rules_apple/3.16.0/MODULE.bazel": "0d1caf0b8375942ce98ea944be754a18874041e4e0459401d925577624d3a54a",
"https://bcr.bazel.build/modules/rules_apple/4.1.0/MODULE.bazel": "76e10fd4a48038d3fc7c5dc6e63b7063bbf5304a2e3bd42edda6ec660eebea68",
"https://bcr.bazel.build/modules/rules_apple/4.1.0/source.json": "8ee81e1708756f81b343a5eb2b2f0b953f1d25c4ab3d4a68dc02754872e80715",
"https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647",
"https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002",
"https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191",
"https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc",
"https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87",
"https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a",
"https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c",
"https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f",
"https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
"https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
"https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513",
"https://bcr.bazel.build/modules/rules_cc/0.1.2/MODULE.bazel": "557ddc3a96858ec0d465a87c0a931054d7dcfd6583af2c7ed3baf494407fd8d0",
"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.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",
"https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
"https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86",
"https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31",
"https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a",
"https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6",
"https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab",
"https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe",
"https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017",
"https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939",
"https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2",
"https://bcr.bazel.build/modules/rules_java/9.0.3/MODULE.bazel": "1f98ed015f7e744a745e0df6e898a7c5e83562d6b759dfd475c76456dda5ccea",
"https://bcr.bazel.build/modules/rules_java/9.0.3/source.json": "b038c0c07e12e658135bbc32cc1a2ded6e33785105c9d41958014c592de4593e",
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
"https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909",
"https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036",
"https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0",
"https://bcr.bazel.build/modules/rules_jvm_external/6.7/MODULE.bazel": "e717beabc4d091ecb2c803c2d341b88590e9116b8bf7947915eeb33aab4f96dd",
"https://bcr.bazel.build/modules/rules_jvm_external/6.7/source.json": "5426f412d0a7fc6b611643376c7e4a82dec991491b9ce5cb1cfdd25fe2e92be4",
"https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3",
"https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5",
"https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0",
"https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d",
"https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c",
"https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb",
"https://bcr.bazel.build/modules/rules_multirun/0.9.0/MODULE.bazel": "32d628ef586b5b23f67e55886b7bc38913ea4160420d66ae90521dda2ff37df0",
"https://bcr.bazel.build/modules/rules_multirun/0.9.0/source.json": "e882ba77962fa6c5fe68619e5c7d0374ec9a219fb8d03c42eadaf6d0243771bd",
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
"https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff",
"https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a",
"https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06",
"https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7",
"https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483",
"https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73",
"https://bcr.bazel.build/modules/rules_proto/7.1.0/MODULE.bazel": "002d62d9108f75bb807cd56245d45648f38275cb3a99dcd45dfb864c5d74cb96",
"https://bcr.bazel.build/modules/rules_proto/7.1.0/source.json": "39f89066c12c24097854e8f57ab8558929f9c8d474d34b2c00ac04630ad8940e",
"https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
"https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300",
"https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382",
"https://bcr.bazel.build/modules/rules_python/0.27.1/MODULE.bazel": "65dc875cc1a06c30d5bbdba7ab021fd9e551a6579e408a3943a61303e2228a53",
"https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed",
"https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58",
"https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937",
"https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
"https://bcr.bazel.build/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13",
"https://bcr.bazel.build/modules/rules_python/1.4.1/MODULE.bazel": "8991ad45bdc25018301d6b7e1d3626afc3c8af8aaf4bc04f23d0b99c938b73a6",
"https://bcr.bazel.build/modules/rules_python/1.6.0/MODULE.bazel": "7e04ad8f8d5bea40451cf80b1bd8262552aa73f841415d20db96b7241bd027d8",
"https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8",
"https://bcr.bazel.build/modules/rules_python/1.7.0/source.json": "028a084b65dcf8f4dc4f82f8778dbe65df133f234b316828a82e060d81bdce32",
"https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c",
"https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b",
"https://bcr.bazel.build/modules/rules_shell/0.6.1/MODULE.bazel": "72e76b0eea4e81611ef5452aa82b3da34caca0c8b7b5c0c9584338aa93bae26b",
"https://bcr.bazel.build/modules/rules_shell/0.6.1/source.json": "20ec05cd5e592055e214b2da8ccb283c7f2a421ea0dc2acbf1aa792e11c03d0c",
"https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca",
"https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046",
"https://bcr.bazel.build/modules/rules_swift/2.4.0/MODULE.bazel": "1639617eb1ede28d774d967a738b4a68b0accb40650beadb57c21846beab5efd",
"https://bcr.bazel.build/modules/rules_swift/3.1.2/MODULE.bazel": "72c8f5cf9d26427cee6c76c8e3853eb46ce6b0412a081b2b6db6e8ad56267400",
"https://bcr.bazel.build/modules/rules_swift/3.1.2/source.json": "e85761f3098a6faf40b8187695e3de6d97944e98abd0d8ce579cb2daf6319a66",
"https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
"https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c",
"https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c",
"https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5",
"https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
"https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91",
"https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/MODULE.bazel": "75aab2373a4bbe2a1260b9bf2a1ebbdbf872d3bd36f80bff058dccd82e89422f",
"https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/source.json": "5fba48bbe0ba48761f9e9f75f92876cafb5d07c0ce059cc7a8027416de94a05b",
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca",
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806",
"https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198"
},
"selectedYankedVersions": {},
"moduleExtensions": {
"@@rules_bun+//bun:extensions.bzl%bun": {
"general": {
"bzlTransitiveDigest": "64B4fTkEHdAlieIOkE/Wi2M/R9lMNZhFxeI1eXEFHRs=",
"usagesDigest": "NKGlTDuQz8QyvtynGiqPQZ47pqfh7gwmp164c1kruoc=",
"recordedInputs": [
"REPO_MAPPING:rules_bun+,bazel_tools bazel_tools"
],
"generatedRepoSpecs": {
"bun_linux_x64": {
"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.zip"
],
"sha256": "f57bc0187e39623de716ba3a389fda5486b2d7be7131a980ba54dc7b733d2e08",
"build_file_content": "\nexports_files([\"bun-linux-x64/bun\"])\n\nfilegroup(\n name = \"bun\",\n srcs = [\"bun-linux-x64/bun\"],\n visibility = [\"//visibility:public\"],\n)\n"
}
},
"bun_linux_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-linux-aarch64.zip"
],
"sha256": "fa5ecb25cafa8e8f5c87a0f833719d46dd0af0a86c7837d806531212d55636d3",
"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_darwin_x64": {
"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-darwin-x64.zip"
],
"sha256": "c1d90bf6140f20e572c473065dc6b37a4b036349b5e9e4133779cc642ad94323",
"build_file_content": "\nexports_files([\"bun-darwin-x64/bun\"])\n\nfilegroup(\n name = \"bun\",\n srcs = [\"bun-darwin-x64/bun\"],\n visibility = [\"//visibility:public\"],\n)\n"
}
},
"bun_darwin_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-darwin-aarch64.zip"
],
"sha256": "82034e87c9d9b4398ea619aee2eed5d2a68c8157e9a6ae2d1052d84d533ccd8d",
"build_file_content": "\nexports_files([\"bun-darwin-aarch64/bun\"])\n\nfilegroup(\n name = \"bun\",\n srcs = [\"bun-darwin-aarch64/bun\"],\n visibility = [\"//visibility:public\"],\n)\n"
}
},
"bun_windows_x64": {
"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-x64.zip"
],
"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"
}
}
}
}
},
"@@rules_bun+//bun:extensions.bzl%bun_install": {
"general": {
"bzlTransitiveDigest": "64B4fTkEHdAlieIOkE/Wi2M/R9lMNZhFxeI1eXEFHRs=",
"usagesDigest": "7SehYeU297FzlGHTRg/G5aakC/abC14POtOr8Qy38vA=",
"recordedInputs": [
"REPO_MAPPING:rules_bun+,bazel_tools bazel_tools"
],
"generatedRepoSpecs": {
"npm": {
"repoRuleId": "@@rules_bun+//internal:bun_install.bzl%bun_install_repository",
"attributes": {
"package_json": "@@//:package.json",
"bun_lockfile": "@@//:bun.lock",
"install_inputs": [],
"isolated_home": true
}
}
}
}
},
"@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": {
"general": {
"bzlTransitiveDigest": "ABI1D/sbS1ovwaW/kHDoj8nnXjQ0oKU9fzmzEG4iT8o=",
"usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=",
"recordedInputs": [
"REPO_MAPPING:rules_kotlin+,bazel_tools bazel_tools"
],
"generatedRepoSpecs": {
"com_github_jetbrains_kotlin_git": {
"repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository",
"attributes": {
"urls": [
"https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip"
],
"sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88"
}
},
"com_github_jetbrains_kotlin": {
"repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository",
"attributes": {
"git_repository_name": "com_github_jetbrains_kotlin_git",
"compiler_version": "1.9.23"
}
},
"com_github_google_ksp": {
"repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository",
"attributes": {
"urls": [
"https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip"
],
"sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d",
"strip_version": "1.9.23-1.0.20"
}
},
"com_github_pinterest_ktlint": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file",
"attributes": {
"sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985",
"urls": [
"https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint"
],
"executable": true
}
},
"rules_android": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806",
"strip_prefix": "rules_android-0.1.1",
"urls": [
"https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip"
]
}
}
}
}
},
"@@rules_python+//python/extensions:config.bzl%config": {
"general": {
"bzlTransitiveDigest": "2hLgIvNVTLgxus0ZuXtleBe70intCfo0cHs8qvt6cdM=",
"usagesDigest": "ZVSXMAGpD+xzVNPuvF1IoLBkty7TROO0+akMapt1pAg=",
"recordedInputs": [
"REPO_MAPPING:rules_python+,bazel_tools bazel_tools",
"REPO_MAPPING:rules_python+,pypi__build rules_python++config+pypi__build",
"REPO_MAPPING:rules_python+,pypi__click rules_python++config+pypi__click",
"REPO_MAPPING:rules_python+,pypi__colorama rules_python++config+pypi__colorama",
"REPO_MAPPING:rules_python+,pypi__importlib_metadata rules_python++config+pypi__importlib_metadata",
"REPO_MAPPING:rules_python+,pypi__installer rules_python++config+pypi__installer",
"REPO_MAPPING:rules_python+,pypi__more_itertools rules_python++config+pypi__more_itertools",
"REPO_MAPPING:rules_python+,pypi__packaging rules_python++config+pypi__packaging",
"REPO_MAPPING:rules_python+,pypi__pep517 rules_python++config+pypi__pep517",
"REPO_MAPPING:rules_python+,pypi__pip rules_python++config+pypi__pip",
"REPO_MAPPING:rules_python+,pypi__pip_tools rules_python++config+pypi__pip_tools",
"REPO_MAPPING:rules_python+,pypi__pyproject_hooks rules_python++config+pypi__pyproject_hooks",
"REPO_MAPPING:rules_python+,pypi__setuptools rules_python++config+pypi__setuptools",
"REPO_MAPPING:rules_python+,pypi__tomli rules_python++config+pypi__tomli",
"REPO_MAPPING:rules_python+,pypi__wheel rules_python++config+pypi__wheel",
"REPO_MAPPING:rules_python+,pypi__zipp rules_python++config+pypi__zipp"
],
"generatedRepoSpecs": {
"rules_python_internal": {
"repoRuleId": "@@rules_python+//python/private:internal_config_repo.bzl%internal_config_repo",
"attributes": {
"transition_setting_generators": {},
"transition_settings": []
}
},
"pypi__build": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/e2/03/f3c8ba0a6b6e30d7d18c40faab90807c9bb5e9a1e3b2fe2008af624a9c97/build-1.2.1-py3-none-any.whl",
"sha256": "75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__click": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl",
"sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__colorama": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl",
"sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__importlib_metadata": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/2d/0a/679461c511447ffaf176567d5c496d1de27cbe34a87df6677d7171b2fbd4/importlib_metadata-7.1.0-py3-none-any.whl",
"sha256": "30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__installer": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl",
"sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__more_itertools": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/50/e2/8e10e465ee3987bb7c9ab69efb91d867d93959095f4807db102d07995d94/more_itertools-10.2.0-py3-none-any.whl",
"sha256": "686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__packaging": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl",
"sha256": "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__pep517": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/25/6e/ca4a5434eb0e502210f591b97537d322546e4833dcb4d470a48c375c5540/pep517-0.13.1-py3-none-any.whl",
"sha256": "31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__pip": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/8a/6a/19e9fe04fca059ccf770861c7d5721ab4c2aebc539889e97c7977528a53b/pip-24.0-py3-none-any.whl",
"sha256": "ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__pip_tools": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/0d/dc/38f4ce065e92c66f058ea7a368a9c5de4e702272b479c0992059f7693941/pip_tools-7.4.1-py3-none-any.whl",
"sha256": "4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__pyproject_hooks": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/ae/f3/431b9d5fe7d14af7a32340792ef43b8a714e7726f1d7b69cc4e8e7a3f1d7/pyproject_hooks-1.1.0-py3-none-any.whl",
"sha256": "7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__setuptools": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/90/99/158ad0609729111163fc1f674a5a42f2605371a4cf036d0441070e2f7455/setuptools-78.1.1-py3-none-any.whl",
"sha256": "c3a9c4211ff4c309edb8b8c4f1cbfa7ae324c4ba9f91ff254e3d305b9fd54561",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__tomli": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl",
"sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__wheel": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/7d/cd/d7460c9a869b16c3dd4e1e403cce337df165368c71d6af229a74699622ce/wheel-0.43.0-py3-none-any.whl",
"sha256": "55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
},
"pypi__zipp": {
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
"attributes": {
"url": "https://files.pythonhosted.org/packages/da/55/a03fd7240714916507e1fcf7ae355bd9d9ed2e6db492595f1a67f61681be/zipp-3.18.2-py3-none-any.whl",
"sha256": "dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e",
"type": "zip",
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
}
}
}
}
},
"@@rules_python+//python/uv:uv.bzl%uv": {
"general": {
"bzlTransitiveDigest": "ijW9KS7qsIY+yBVvJ+Nr1mzwQox09j13DnE3iIwaeTM=",
"usagesDigest": "H8dQoNZcoqP+Mu0tHZTi4KHATzvNkM5ePuEqoQdklIU=",
"recordedInputs": [
"REPO_MAPPING:rules_python+,bazel_tools bazel_tools",
"REPO_MAPPING:rules_python+,platforms platforms"
],
"generatedRepoSpecs": {
"uv": {
"repoRuleId": "@@rules_python+//python/uv/private:uv_toolchains_repo.bzl%uv_toolchains_repo",
"attributes": {
"toolchain_type": "'@@rules_python+//python/uv:uv_toolchain_type'",
"toolchain_names": [
"none"
],
"toolchain_implementations": {
"none": "'@@rules_python+//python:none'"
},
"toolchain_compatible_with": {
"none": [
"@platforms//:incompatible"
]
},
"toolchain_target_settings": {}
}
}
}
}
}
},
"facts": {}
}

View File

@@ -0,0 +1,28 @@
# Vite monorepo example
Bun workspace-style example with two Vite applications sharing one root
`bun_install` dependency installation.
Apps:
- `apps/app-a`
- `apps/app-b`
This example also exercises Bun's workspace catalog syntax:
- `workspaces.catalog` provides the default `vite` version referenced as `catalog:`
- `workspaces.catalogs.testing` provides a named catalog referenced as `catalog:testing`
Both apps run `vite` via their own `package.json` scripts while sharing the same
generated `node_modules/` tree.
Run either app with Bazel:
```bash
bazel run //examples/vite_monorepo:app_a_dev -- --host 127.0.0.1 --port 5173 --strictPort
bazel run //examples/vite_monorepo:app_b_dev -- --host 127.0.0.1 --port 5174 --strictPort
```
This example maps its `bun_install` output to the canonical `@node_modules`
repository name in `MODULE.bazel`, so `bun_script` targets don't need to hard-
code a generated repository name.

View File

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite monorepo app A</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,7 @@
const app = document.querySelector("#app");
if (app) {
app.textContent = "Hello from monorepo app A";
}
console.log("Hello from monorepo app A");

View File

@@ -0,0 +1,11 @@
{
"name": "vite-monorepo-app-a",
"private": true,
"type": "module",
"scripts": {
"dev": "vite"
},
"devDependencies": {
"vite": "catalog:"
}
}

View File

@@ -0,0 +1 @@
export default {};

View File

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite monorepo app B</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,9 @@
import { nanoid } from "nanoid";
const app = document.querySelector("#app");
if (app) {
const id = nanoid();
app.textContent = "Hello from monorepo app B " + id;
}
console.log("Hello from monorepo app B");

View File

@@ -0,0 +1,15 @@
{
"name": "vite-monorepo-app-b",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --port 5174"
},
"dependencies": {
"nanoid": "5.1.6"
},
"devDependencies": {
"vite": "catalog:",
"vitest": "catalog:testing"
}
}

View File

@@ -0,0 +1 @@
export default {};

View File

@@ -0,0 +1,234 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "vite-monorepo-test",
},
"apps/app-a": {
"name": "vite-monorepo-app-a",
"devDependencies": {
"vite": "catalog:",
},
},
"apps/app-b": {
"name": "vite-monorepo-app-b",
"dependencies": {
"nanoid": "5.1.6",
},
"devDependencies": {
"vite": "catalog:",
"vitest": "catalog:testing",
},
},
},
"catalog": {
"vite": "5.4.14",
},
"catalogs": {
"testing": {
"vitest": "3.2.4",
},
},
"packages": {
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="],
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="],
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="],
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="],
"@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="],
"@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="],
"@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="],
"@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="],
"@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="],
"@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="],
"@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="],
"@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="],
"assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
"cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
"chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="],
"check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
"es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
"esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
"expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
"loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="],
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="],
"rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="],
"siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
"std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
"strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
"tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
"tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="],
"tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="],
"tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="],
"vite": ["vite@5.4.14", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA=="],
"vite-monorepo-app-a": ["vite-monorepo-app-a@workspace:apps/app-a"],
"vite-monorepo-app-b": ["vite-monorepo-app-b@workspace:apps/app-b"],
"vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],
"vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="],
"why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],
"postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
}
}

View File

@@ -0,0 +1,17 @@
{
"name": "vite-monorepo-test",
"private": true,
"workspaces": {
"packages": [
"apps/*"
],
"catalog": {
"vite": "5.4.14"
},
"catalogs": {
"testing": {
"vitest": "3.2.4"
}
}
}
}

View File

@@ -0,0 +1,90 @@
#!/usr/bin/env bash
set -euo pipefail
app_a_binary="$1"
app_b_binary="$2"
workdir="$(mktemp -d)"
server_pid=""
log_file=""
cleanup() {
if [[ -n ${server_pid} ]] && kill -0 "${server_pid}" 2>/dev/null; then
kill "${server_pid}" 2>/dev/null || true
wait "${server_pid}" 2>/dev/null || true
fi
rm -rf "${workdir}"
}
trap cleanup EXIT
pick_port() {
python3 - <<'PY'
import socket
sock = socket.socket()
sock.bind(("127.0.0.1", 0))
print(sock.getsockname()[1])
sock.close()
PY
}
matches_expected_js() {
local content="$1"
local expected="$2"
if [[ ${expected} == *"*"* ]]; then
local regex
regex="$(printf '%s' "${expected}" | sed -e 's/[][(){}.+?^$|\\]/\\&/g' -e 's/\*/.*/g')"
printf '%s' "${content}" | grep -Eq "${regex}"
else
printf '%s' "${content}" | grep -Fq "${expected}"
fi
}
verify_vite_app() {
local binary="$1"
local expected_title="$2"
local expected_js="$3"
local log_name="$4"
local port
local main_js
port="$(pick_port)"
log_file="${workdir}/${log_name}.log"
"${binary}" --host 127.0.0.1 --port "${port}" --strictPort >"${log_file}" 2>&1 &
server_pid=$!
for _ in {1..60}; do
if ! kill -0 "${server_pid}" 2>/dev/null; then
cat "${log_file}" >&2
echo "Vite server exited unexpectedly for ${log_name}" >&2
exit 1
fi
if curl --fail --silent "http://127.0.0.1:${port}/" | grep -Fq "${expected_title}"; then
break
fi
sleep 0.5
done
if ! curl --fail --silent "http://127.0.0.1:${port}/" | grep -Fq "${expected_title}"; then
cat "${log_file}" >&2
echo "Timed out waiting for Vite index page for ${log_name}" >&2
exit 1
fi
main_js="$(curl --fail --silent "http://127.0.0.1:${port}/main.js")"
if ! matches_expected_js "${main_js}" "${expected_js}"; then
cat "${log_file}" >&2
echo "Expected Vite module output was not served for ${log_name}" >&2
exit 1
fi
kill "${server_pid}" 2>/dev/null || true
wait "${server_pid}" 2>/dev/null || true
server_pid=""
}
verify_vite_app "${app_a_binary}" "Vite monorepo app A" "Hello from monorepo app A" "app-a"
verify_vite_app "${app_b_binary}" "Vite monorepo app B" "Hello from monorepo app B *" "app-b"

80
flake.lock generated
View File

@@ -1,28 +1,5 @@
{ {
"nodes": { "nodes": {
"devshell-lib": {
"inputs": {
"git-hooks": "git-hooks",
"nixpkgs": [
"nixpkgs"
],
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1772613315,
"narHash": "sha256-RlPTOsyfVwuwEzvaMpwS+giOqQa6KQXMuSHyh1bctjk=",
"ref": "v1.0.5",
"rev": "e445e49baf8b44b385108cd4f26a14d8ccf9fd35",
"revCount": 35,
"type": "git",
"url": "https://git.dgren.dev/eric/nix-flake-lib"
},
"original": {
"ref": "v1.0.5",
"type": "git",
"url": "https://git.dgren.dev/eric/nix-flake-lib"
}
},
"flake-compat": { "flake-compat": {
"flake": false, "flake": false,
"locked": { "locked": {
@@ -43,7 +20,7 @@
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"gitignore": "gitignore", "gitignore": "gitignore",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1772024342, "lastModified": 1772024342,
@@ -62,7 +39,7 @@
"gitignore": { "gitignore": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"devshell-lib", "repo-lib",
"git-hooks", "git-hooks",
"nixpkgs" "nixpkgs"
] ]
@@ -82,6 +59,22 @@
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": {
"lastModified": 1772542754,
"narHash": "sha256-WGV2hy+VIeQsYXpsLjdr4GvHv5eECMISX1zKLTedhdg=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "8c809a146a140c5c8806f13399592dbcb1bb5dc4",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1770073757, "lastModified": 1770073757,
"narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=", "narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=",
@@ -97,7 +90,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_2": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1770107345, "lastModified": 1770107345,
"narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=", "narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=",
@@ -113,31 +106,38 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_3": { "repo-lib": {
"inputs": {
"git-hooks": "git-hooks",
"nixpkgs": [
"nixpkgs"
],
"treefmt-nix": "treefmt-nix"
},
"locked": { "locked": {
"lastModified": 1772542754, "lastModified": 1772866275,
"narHash": "sha256-WGV2hy+VIeQsYXpsLjdr4GvHv5eECMISX1zKLTedhdg=", "narHash": "sha256-lsJrFIbq6OO5wUC648VnvOmJm3qgJrlEugbdjeZsP34=",
"owner": "nixos", "ref": "refs/tags/v3.0.0",
"repo": "nixpkgs", "rev": "96d2d190466dddcb9e652c38b70152f09b9fcb05",
"rev": "8c809a146a140c5c8806f13399592dbcb1bb5dc4", "revCount": 50,
"type": "github" "type": "git",
"url": "https://git.dgren.dev/eric/nix-flake-lib"
}, },
"original": { "original": {
"owner": "nixos", "ref": "refs/tags/v3.0.0",
"ref": "nixos-unstable", "type": "git",
"repo": "nixpkgs", "url": "https://git.dgren.dev/eric/nix-flake-lib"
"type": "github"
} }
}, },
"root": { "root": {
"inputs": { "inputs": {
"devshell-lib": "devshell-lib", "nixpkgs": "nixpkgs",
"nixpkgs": "nixpkgs_3" "repo-lib": "repo-lib"
} }
}, },
"treefmt-nix": { "treefmt-nix": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_3"
}, },
"locked": { "locked": {
"lastModified": 1770228511, "lastModified": 1770228511,

194
flake.nix
View File

@@ -3,141 +3,50 @@
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
devshell-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=v1.0.5"; repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.0.0";
devshell-lib.inputs.nixpkgs.follows = "nixpkgs"; repo-lib.inputs.nixpkgs.follows = "nixpkgs";
}; };
outputs = outputs =
{ {
self, self,
nixpkgs, nixpkgs,
devshell-lib, repo-lib,
... ...
}: }:
let let
supportedSystems = [ bazelVersion = "9.0.1";
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
in in
{ repo-lib.lib.mkRepo {
devShells = forAllSystems ( inherit self nixpkgs;
system: src = ./.;
let
pkgs = import nixpkgs { inherit system; };
bazel9 = pkgs.writeShellScriptBin "bazel" ''
export USE_BAZEL_VERSION="''${USE_BAZEL_VERSION:-9.0.0}"
exec ${pkgs.bazelisk}/bin/bazelisk "$@"
'';
env = devshell-lib.lib.mkDevShell {
inherit system;
extraPackages = with pkgs; [ config = {
go shell.extraShellText = ''
gopls export USE_BAZEL_VERSION="''${USE_BAZEL_VERSION:-${bazelVersion}}"
gotools export BUN_INSTALL="''${BUN_INSTALL:-$HOME/.bun}"
bun export PATH="$BUN_INSTALL/bin:$PATH"
bazel9 '';
bazel-buildtools
self.packages.${system}.release
];
features = { formatting = {
oxfmt = true; programs.shfmt.enable = true;
}; settings.shfmt.options = [
"-i"
"2"
"-s"
"-w"
];
};
formatters = { release = {
shfmt.enable = true; steps = [
};
formatterSettings = {
shfmt.options = [
"-i"
"2"
"-s"
"-w"
];
};
additionalHooks = {
tests = {
enable = true;
entry = "echo 'No tests defined yet.'";
pass_filenames = false;
stages = [ "pre-push" ];
};
};
tools = [
{
name = "Bun";
bin = "${pkgs.bun}/bin/bun";
versionCmd = "--version";
color = "YELLOW";
}
{
name = "Go";
bin = "${pkgs.go}/bin/go";
versionCmd = "version";
color = "CYAN";
}
{
name = "Bazel";
bin = "${bazel9}/bin/bazel";
versionCmd = "--version";
color = "GREEN";
}
];
extraShellHook = ''
export USE_BAZEL_VERSION="''${USE_BAZEL_VERSION:-9.0.0}"
export BUN_INSTALL="''${BUN_INSTALL:-$HOME/.bun}"
export PATH="$BUN_INSTALL/bin:$PATH"
'';
};
in
{
default = env.shell;
}
);
checks = forAllSystems (
system:
let
env = devshell-lib.lib.mkDevShell { inherit system; };
in
{
inherit (env) pre-commit-check;
}
);
formatter = forAllSystems (system: (devshell-lib.lib.mkDevShell { inherit system; }).formatter);
# Optional: release command (`release`)
#
# The release script always updates VERSION first, then:
# 1) runs release steps in order (file writes and scripts)
# 2) runs postVersion hook
# 3) formats, stages, commits, tags, and pushes
#
# Runtime env vars available in release.run/postVersion:
# BASE_VERSION, CHANNEL, PRERELEASE_NUM, FULL_VERSION, FULL_TAG
#
packages = forAllSystems (system: {
release = devshell-lib.lib.mkRelease {
inherit system;
release = [
{ {
run = '' run.script = ''
sed -E -i 's#^([[:space:]]*version[[:space:]]*=[[:space:]]*")[^"]*(",)$#\1'"$FULL_VERSION"'\2#' "$ROOT_DIR/MODULE.bazel" sed -E -i 's#^([[:space:]]*version[[:space:]]*=[[:space:]]*")[^"]*(",)$#\1'"$FULL_VERSION"'\2#' "$ROOT_DIR/MODULE.bazel"
''; '';
} }
{ {
run = '' run.script = ''
README="$ROOT_DIR/README.md" README="$ROOT_DIR/README.md"
TMP="$README.tmp" TMP="$README.tmp"
@@ -166,14 +75,61 @@
' "$README" > "$TMP" && mv "$TMP" "$README" ' "$README" > "$TMP" && mv "$TMP" "$README"
''; '';
} }
{
run.script = ''
bazel cquery //tests/... >/dev/null
'';
}
]; ];
postVersion = '' postVersion = ''
echo "Released $FULL_TAG" echo "Released $FULL_TAG"
''; '';
}; };
}); };
perSystem =
{
pkgs,
system,
...
}:
let
bazel9 = pkgs.writeShellScriptBin "bazel" ''
export USE_BAZEL_VERSION="''${USE_BAZEL_VERSION:-${bazelVersion}}"
exec ${pkgs.bazelisk}/bin/bazelisk "$@"
'';
in
{
tools = [
(repo-lib.lib.tools.fromPackage {
name = "Bun";
package = pkgs.bun;
version.args = [ "--version" ];
banner.color = "YELLOW";
})
(repo-lib.lib.tools.fromPackage {
name = "Bazel";
package = bazel9;
version.args = [ "--version" ];
banner.color = "GREEN";
})
];
shell.packages = [
pkgs.bazel-buildtools
self.packages.${system}.release
];
checks.tests = {
command = "bazelisk test //tests/...";
stage = "pre-push";
passFilenames = false;
runtimeInputs = [
bazel9
pkgs.bun
];
};
};
}; };
} }

View File

@@ -1,280 +0,0 @@
Here's a comprehensive plan for implementing a Bazel-native `bun_rules` package:
---
## `bun_rules`: Bazel-Native Bun Implementation Plan
### What Is This?
A Bazel ruleset that integrates the [Bun](https://bun.sh) JavaScript runtime natively — similar to `rules_nodejs` but leveraging Bun's bundler, test runner, package manager, and runtime. The goal is hermetic, reproducible builds using Bun as the toolchain.
---
## Phase 1: Repository Skeleton & Toolchain
**Where to start.** Every Bazel ruleset begins with the toolchain — nothing else works without it.
### 1.1 Repo Structure
```
bun_rules/
├── MODULE.bazel # Bzlmod module definition
├── WORKSPACE # Legacy workspace support
├── BUILD.bazel
├── bun/
│ ├── repositories.bzl # Download bun binaries per platform
│ ├── toolchain.bzl # bun_toolchain rule
│ └── defs.bzl # Public API re-exports
├── internal/
│ ├── bun_binary.bzl
│ ├── bun_test.bzl
│ ├── bun_install.bzl
│ └── bun_bundle.bzl
├── examples/
│ └── basic/
└── tests/
├── toolchain_test/
├── install_test/
├── binary_test/
└── bundle_test/
```
### 1.2 Toolchain Rule (`toolchain.bzl`)
```python
BunToolchainInfo = provider(fields = ["bun_bin", "version"])
bun_toolchain = rule(
implementation = _bun_toolchain_impl,
attrs = {
"bun": attr.label(allow_single_file = True, executable = True, cfg = "exec"),
"version": attr.string(),
},
)
```
### 1.3 Binary Downloads (`repositories.bzl`)
Use `http_file` to fetch platform-specific Bun binaries:
- `bun-linux-x64`, `bun-linux-aarch64`
- `bun-darwin-x64`, `bun-darwin-aarch64`
- `bun-windows-x64.exe`
Use SHA256 checksums pinned per Bun release. Register via `register_toolchains()`.
**Tests needed:**
- `toolchain_resolution_test` — assert the correct binary is selected per `--platforms`
- `bun --version` smoke test via a `sh_test`
---
## Phase 2: `bun_install` (Package Manager)
Replaces `npm install` / `yarn`. This is the highest-leverage rule because every downstream rule depends on it.
### Rule Design
```python
bun_install(
name = "node_modules",
package_json = "//:package.json",
bun_lockfile = "//:bun.lockb",
)
```
- Runs `bun install --frozen-lockfile` in a sandboxed action
- Outputs a `node_modules/` directory as a `TreeArtifact`
- Must be hermetic: no network in actions (vendor or use a repository rule to pre-fetch)
### Key Challenges
- `bun.lockb` is binary — you need to commit it and treat it as a source file
- Network access during `bun install` breaks Bazel's sandbox; solve with either:
- A **repository rule** that runs install at analysis time (like `npm_install` in rules_nodejs)
- Or a **module extension** in Bzlmod
**Tests needed:**
- Install succeeds with a valid `package.json` + `bun.lockb`
- Build fails (with a clear error) when `bun.lockb` is out of date
- Determinism test: run install twice, assert identical output digest
- Test that `node_modules` is correctly provided to downstream rules
---
## Phase 3: `bun_binary` (Run JS/TS scripts)
```python
bun_binary(
name = "my_script",
entry_point = "src/main.ts",
node_modules = "//:node_modules",
data = glob(["src/**"]),
)
```
- Wraps `bun run <entry>` as a Bazel executable
- Provides `DefaultInfo` with a launcher script
- Handles both `.js` and `.ts` natively (no transpile step needed)
**Tests needed:**
- `bun_binary` produces a runnable target (`bazel run`)
- TypeScript entry points work without separate compilation
- `data` deps are available at runtime
- Environment variables pass through correctly
---
## Phase 4: `bun_test` (Test Runner)
```python
bun_test(
name = "my_test",
srcs = ["src/foo.test.ts"],
node_modules = "//:node_modules",
)
```
- Wraps `bun test` with Bazel's test runner protocol
- Must exit with code 0/non-0 correctly
- Outputs JUnit XML for `--test_output` compatibility (use `bun test --reporter junit`)
**Tests needed:**
- Passing test suite returns exit 0
- Failing test suite returns exit non-0 (Bazel marks as FAILED)
- Test filtering via `--test_filter` works
- Coverage via `bun test --coverage` integrates with `bazel coverage`
- Tests are re-run when source files change (input tracking)
- Tests are **not** re-run when unrelated files change (cache correctness)
---
## Phase 5: `bun_bundle` (Bundler)
```python
bun_bundle(
name = "app_bundle",
entry_points = ["src/index.ts"],
node_modules = "//:node_modules",
target = "browser", # or "node", "bun"
format = "esm", # or "cjs", "iife"
minify = True,
)
```
- Runs `bun build` as a Bazel action
- Outputs are declared files (JS, sourcemaps, assets)
- Supports splitting, external packages, define/env vars
**Tests needed:**
- Output file exists and has non-zero size
- `minify = True` produces smaller output than `minify = False`
- `external` packages are not bundled
- Sourcemaps are generated when requested
- Build is hermetic: same inputs → identical output digest (content hash)
- Invalid entry point produces a clear build error (not a cryptic Bazel failure)
---
## Phase 6: `js_library` / `ts_library` (Source Grouping)
Lightweight rules for grouping sources and propagating them through the dep graph:
```python
ts_library(
name = "utils",
srcs = glob(["src/**/*.ts"]),
deps = [":node_modules"],
)
```
**Tests needed:**
- `deps` correctly propagate transitive sources to `bun_bundle` and `bun_test`
- Circular dep detection (or at least graceful failure)
---
## Required Tests Summary
| Category | Test |
| ------------- | ----------------------------------------------------------- |
| Toolchain | Correct binary resolves per platform |
| Toolchain | `bun --version` executes successfully |
| `bun_install` | Clean install works |
| `bun_install` | Stale lockfile fails with clear error |
| `bun_install` | Output is deterministic |
| `bun_binary` | JS entry point runs |
| `bun_binary` | TS entry point runs without compile step |
| `bun_binary` | Data files available at runtime |
| `bun_test` | Passing tests → exit 0 |
| `bun_test` | Failing tests → exit non-0 |
| `bun_test` | Cache hit: unchanged test not re-run |
| `bun_test` | Cache miss: changed source triggers re-run |
| `bun_test` | JUnit XML output parseable |
| `bun_bundle` | Output file produced |
| `bun_bundle` | Minification reduces output size |
| `bun_bundle` | Hermetic: identical inputs → identical digest |
| `bun_bundle` | External packages excluded correctly |
| Integration | `examples/basic` builds end-to-end with `bazel build //...` |
| Integration | `bazel test //...` passes all tests |
### Gap-Closing Checklist (Concrete Targets)
Use this checklist to close the current coverage gaps with explicit test targets.
| Status | Gap | Proposed target | Location |
| ------- | ---------------------------------------------------------- | ---------------------------------- | ------------------------------------ |
| Partial | Toolchain resolves per platform is only host-select tested | `toolchain_resolution_matrix_test` | `tests/toolchain_test/BUILD.bazel` |
| Missing | `bun_install` deterministic output digest | `bun_install_determinism_test` | `tests/install_test/BUILD.bazel` |
| Missing | `bun_binary` runtime data files availability | `bun_binary_data_test` | `tests/binary_test/BUILD.bazel` |
| Partial | `bun_test` failing suite exists but is manual-only | `bun_test_failing_suite_test` | `tests/bun_test_test/BUILD.bazel` |
| Missing | `bun_test` cache hit (unchanged inputs) | `bun_test_cache_hit_test` | `tests/bun_test_test/BUILD.bazel` |
| Missing | `bun_test` cache miss (changed source) | `bun_test_cache_miss_test` | `tests/bun_test_test/BUILD.bazel` |
| Missing | `bun_test` JUnit XML parseability | `bun_test_junit_output_test` | `tests/bun_test_test/BUILD.bazel` |
| Missing | `bun_bundle` hermetic digest stability | `bundle_hermetic_digest_test` | `tests/bundle_test/BUILD.bazel` |
| Missing | `bun_bundle` external package exclusion | `bundle_external_exclusion_test` | `tests/bundle_test/BUILD.bazel` |
| Missing | `examples/basic` end-to-end build via Bazel | `examples_basic_e2e_build_test` | `tests/integration_test/BUILD.bazel` |
| Partial | CI currently runs `bazel test //tests/...` only | `repo_all_targets_test` | `tests/integration_test/BUILD.bazel` |
Recommended implementation order:
1. `bun_test_failing_suite_test` (remove/manual split) and `bun_binary_data_test`
2. `bun_install_determinism_test`, `bundle_hermetic_digest_test`
3. `bun_test_cache_hit_test`, `bun_test_cache_miss_test`, `bun_test_junit_output_test`
4. `bundle_external_exclusion_test`, `examples_basic_e2e_build_test`, `repo_all_targets_test`
---
## Development Sequence
```
1. Toolchain downloads + resolution ← start here
2. bun_install (repository rule approach)
3. bun_binary (simplest runtime rule)
4. bun_test
5. bun_bundle
6. js_library / ts_library
7. Bzlmod module extension for installs
8. CI matrix (linux-x64, darwin-arm64, windows)
9. Docs + examples
```
---
## Where to Start Right Now
**Day 1:** Copy the pattern from [`rules_go`](https://github.com/bazelbuild/rules_go) or [`aspect-build/rules_js`](https://github.com/aspect-build/rules_js) for toolchain registration. Write `repositories.bzl` that fetches the Bun binary for your current platform only. Write a `sh_test` that calls `bun --version` and asserts it exits 0. Get that green.
**Reference implementations to study:**
- `aspect-build/rules_js` — best modern reference for JS in Bazel
- `bazelbuild/rules_nodejs` — older but battle-tested patterns
- `bazelbuild/rules_python` — excellent toolchain download pattern to copy
The toolchain is the entire foundation. Nothing else is possible without it being solid.

View File

@@ -3,43 +3,155 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
exports_files([ exports_files([
"bun_build_support.bzl",
"bun_binary.bzl", "bun_binary.bzl",
"bun_command.bzl",
"bun_compile.bzl",
"bun_bundle.bzl", "bun_bundle.bzl",
"bun_dev.bzl", "bun_dev.bzl",
"bun_install.bzl", "bun_install.bzl",
"bun_script.bzl", "bun_script.bzl",
"bun_test.bzl", "bun_test.bzl",
"js_compat.bzl",
"js_library.bzl", "js_library.bzl",
"js_run_devserver.bzl",
"runtime_launcher.bzl",
"runtime_launcher.js",
"workspace.bzl",
]) ])
filegroup(
name = "repo_runtime_files",
srcs = [
"BUILD.bazel",
"bun_binary.bzl",
"bun_build_support.bzl",
"bun_bundle.bzl",
"bun_command.bzl",
"bun_compile.bzl",
"bun_dev.bzl",
"bun_install.bzl",
"bun_script.bzl",
"bun_test.bzl",
"js_compat.bzl",
"js_library.bzl",
"js_run_devserver.bzl",
"runtime_launcher.bzl",
"runtime_launcher.js",
"workspace.bzl",
],
visibility = ["//visibility:public"],
)
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( bzl_library(
name = "bun_binary_bzl", name = "bun_binary_bzl",
srcs = ["bun_binary.bzl"], srcs = ["bun_binary.bzl"],
deps = [
":bun_command_bzl",
":js_library_bzl",
":runtime_launcher_bzl",
":workspace_bzl",
],
)
bzl_library(
name = "bun_compile_bzl",
srcs = ["bun_compile.bzl"],
deps = [
":bun_build_support_bzl",
],
) )
bzl_library( bzl_library(
name = "bun_bundle_bzl", name = "bun_bundle_bzl",
srcs = ["bun_bundle.bzl"], srcs = ["bun_bundle.bzl"],
deps = [":js_library_bzl"], deps = [
":bun_build_support_bzl",
],
) )
bzl_library( bzl_library(
name = "bun_dev_bzl", name = "bun_dev_bzl",
srcs = ["bun_dev.bzl"], srcs = ["bun_dev.bzl"],
deps = [
":bun_command_bzl",
":runtime_launcher_bzl",
":workspace_bzl",
],
)
bzl_library(
name = "bun_install_bzl",
srcs = ["bun_install.bzl"],
) )
bzl_library( bzl_library(
name = "bun_script_bzl", name = "bun_script_bzl",
srcs = ["bun_script.bzl"], srcs = ["bun_script.bzl"],
deps = [
":bun_command_bzl",
":runtime_launcher_bzl",
":workspace_bzl",
],
) )
bzl_library( bzl_library(
name = "bun_test_bzl", name = "bun_test_bzl",
srcs = ["bun_test.bzl"], srcs = ["bun_test.bzl"],
deps = [":js_library_bzl"], deps = [
":bun_command_bzl",
":js_library_bzl",
":runtime_launcher_bzl",
":workspace_bzl",
],
)
bzl_library(
name = "js_compat_bzl",
srcs = ["js_compat.bzl"],
deps = [
":bun_binary_bzl",
":bun_test_bzl",
":js_library_bzl",
":js_run_devserver_bzl",
],
) )
bzl_library( bzl_library(
name = "js_library_bzl", name = "js_library_bzl",
srcs = ["js_library.bzl"], srcs = ["js_library.bzl"],
) )
bzl_library(
name = "js_run_devserver_bzl",
srcs = ["js_run_devserver.bzl"],
deps = [
":js_library_bzl",
":runtime_launcher_bzl",
":workspace_bzl",
],
)
bzl_library(
name = "runtime_launcher_bzl",
srcs = ["runtime_launcher.bzl"],
)
bzl_library(
name = "workspace_bzl",
srcs = ["workspace.bzl"],
)

View File

@@ -1,70 +1,122 @@
"""Rule for running JS/TS scripts with Bun.""" """Rule for running JS/TS scripts with Bun."""
load("//internal:bun_command.bzl", "append_flag", "append_flag_values", "append_install_mode", "append_raw_flags")
load("//internal:js_library.bzl", "collect_js_runfiles")
load("//internal:runtime_launcher.bzl", "declare_runtime_wrapper", "runfiles_path", "runtime_launcher_attrs", "write_launcher_spec")
load("//internal:workspace.bzl", "create_bun_workspace_info", "workspace_runfiles")
def _bun_binary_impl(ctx): def _bun_binary_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"] toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin bun_bin = toolchain.bun.bun_bin
entry_point = ctx.file.entry_point entry_point = ctx.file.entry_point
dep_runfiles = [collect_js_runfiles(dep) for dep in ctx.attr.deps]
launcher = ctx.actions.declare_file(ctx.label.name) workspace_info = create_bun_workspace_info(
ctx.actions.write( ctx,
output = launcher, extra_files = ctx.files.data + ctx.files.preload + ctx.files.env_files + [bun_bin],
is_executable = True, primary_file = entry_point,
content = """#!/usr/bin/env bash
set -euo pipefail
runfiles_dir="${{RUNFILES_DIR:-$0.runfiles}}"
workspace_root="${{runfiles_dir}}/_main"
bun_bin="${{runfiles_dir}}/_main/{bun_short_path}"
entry_point="${{runfiles_dir}}/_main/{entry_short_path}"
resolve_entrypoint_workdir() {{
local dir
dir="$(dirname "${{entry_point}}")"
while [[ "${{dir}}" == "${{workspace_root}}"* ]]; do
if [[ -f "${{dir}}/.env" || -f "${{dir}}/package.json" ]]; then
echo "${{dir}}"
return 0
fi
if [[ "${{dir}}" == "${{workspace_root}}" ]]; then
break
fi
dir="$(dirname "${{dir}}")"
done
echo "$(dirname "${{entry_point}}")"
}}
working_dir="{working_dir}"
if [[ "${{working_dir}}" == "entry_point" ]]; then
cd "$(resolve_entrypoint_workdir)"
else
cd "${{workspace_root}}"
fi
exec "${{bun_bin}}" --bun run "${{entry_point}}" "$@"
""".format(
bun_short_path = bun_bin.short_path,
entry_short_path = entry_point.short_path,
working_dir = ctx.attr.working_dir,
),
) )
transitive_files = [] argv = ["--bun", "run"]
if ctx.attr.node_modules: append_install_mode(argv, ctx.attr.install_mode)
transitive_files.append(ctx.attr.node_modules[DefaultInfo].files) append_flag(argv, "--no-env-file", ctx.attr.no_env_file)
append_flag(argv, "--smol", ctx.attr.smol)
append_flag_values(argv, "--conditions", ctx.attr.conditions)
append_raw_flags(argv, ctx.attr.run_flags)
runfiles = ctx.runfiles( spec_file = write_launcher_spec(ctx, {
files = [bun_bin, entry_point] + ctx.files.data, "version": 1,
transitive_files = depset(transitive = transitive_files), "kind": "bun_run",
) "bun_short_path": runfiles_path(bun_bin),
"primary_source_short_path": runfiles_path(entry_point),
"package_json_short_path": "",
"install_metadata_short_path": runfiles_path(workspace_info.install_metadata_file) if workspace_info.install_metadata_file else "",
"install_repo_runfiles_path": workspace_info.install_repo_runfiles_path,
"node_modules_roots": workspace_info.node_modules_roots,
"package_dir_hint": workspace_info.package_dir_hint,
"working_dir_mode": ctx.attr.working_dir,
"inherit_host_path": ctx.attr.inherit_host_path,
"argv": argv,
"args": ctx.attr.args,
"passthrough_args": True,
"tool_short_path": "",
"restart_on": [],
"watch_mode": "",
"reporter": "",
"coverage": False,
"coverage_reporters": [],
"preload_short_paths": [runfiles_path(file) for file in ctx.files.preload],
"env_file_short_paths": [runfiles_path(file) for file in ctx.files.env_files],
"test_short_paths": [],
})
launcher = declare_runtime_wrapper(ctx, bun_bin, spec_file)
return [ return [
workspace_info,
DefaultInfo( DefaultInfo(
executable = launcher, executable = launcher.executable,
runfiles = runfiles, runfiles = workspace_runfiles(
ctx,
workspace_info,
direct_files = [launcher.executable, launcher.runner, spec_file],
transitive_files = dep_runfiles,
),
), ),
] ]
_BUN_BINARY_ATTRS = runtime_launcher_attrs()
_BUN_BINARY_ATTRS.update({
"entry_point": attr.label(
mandatory = True,
allow_single_file = [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"],
doc = "Path to the main JS/TS file to execute.",
),
"node_modules": attr.label(
doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles.",
),
"data": attr.label_list(
allow_files = True,
doc = "Additional runtime files required by the program.",
),
"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"],
doc = "Working directory at runtime: `workspace` root or nearest `entry_point` ancestor containing `.env`/`package.json`.",
),
"inherit_host_path": attr.bool(
default = False,
doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
),
})
bun_binary = rule( bun_binary = rule(
implementation = _bun_binary_impl, implementation = _bun_binary_impl,
@@ -72,25 +124,7 @@ bun_binary = rule(
Use this rule for non-test scripts and CLIs that should run via `bazel run`. Use this rule for non-test scripts and CLIs that should run via `bazel run`.
""", """,
attrs = { attrs = _BUN_BINARY_ATTRS,
"entry_point": attr.label(
mandatory = True,
allow_single_file = [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"],
doc = "Path to the main JS/TS file to execute.",
),
"node_modules": attr.label(
doc = "Optional label providing Bun/npm package files in runfiles.",
),
"data": attr.label_list(
allow_files = True,
doc = "Additional runtime files required by the program.",
),
"working_dir": attr.string(
default = "workspace",
values = ["workspace", "entry_point"],
doc = "Working directory at runtime: `workspace` root or nearest `entry_point` ancestor containing `.env`/`package.json`.",
),
},
executable = True, executable = True,
toolchains = ["//bun:toolchain_type"], toolchains = ["//bun:toolchain_type"],
) )

View File

@@ -0,0 +1,208 @@
"""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")
_STAGED_BUILD_RUNNER = """import { spawnSync } from "node:child_process";
import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, resolve } from "node:path";
const [, , manifestPath, ...buildArgs] = process.argv;
const execroot = process.cwd();
const stageDir = mkdtempSync(resolve(tmpdir(), "rules_bun_build-"));
function rewriteArgPath(flag, value) {
return `${flag}=${resolve(execroot, value)}`;
}
try {
for (const relpath of readFileSync(manifestPath, "utf8").split(/\\r?\\n/)) {
if (!relpath) {
continue;
}
const src = resolve(execroot, relpath);
const dest = resolve(stageDir, relpath);
mkdirSync(dirname(dest), { recursive: true });
cpSync(src, dest, { dereference: true, force: true, recursive: true });
}
const forwardedArgs = [];
for (let index = 0; index < buildArgs.length; index += 1) {
const arg = buildArgs[index];
if ((arg === "--outdir" || arg === "--outfile") && index + 1 < buildArgs.length) {
forwardedArgs.push(arg, resolve(execroot, buildArgs[index + 1]));
index += 1;
continue;
}
if (arg.startsWith("--metafile=")) {
forwardedArgs.push(rewriteArgPath("--metafile", arg.slice("--metafile=".length)));
continue;
}
if (arg.startsWith("--metafile-md=")) {
forwardedArgs.push(rewriteArgPath("--metafile-md", arg.slice("--metafile-md=".length)));
continue;
}
forwardedArgs.push(arg);
}
const result = spawnSync(process.execPath, forwardedArgs, {
cwd: stageDir,
stdio: "inherit",
});
if (result.error) {
throw result.error;
}
process.exit(typeof result.status === "number" ? result.status : 1);
} finally {
rmSync(stageDir, { recursive: true, force: true });
}
"""
def sort_files_by_short_path(files):
files_by_path = {}
short_paths = []
for file in files:
files_by_path[file.short_path] = file
short_paths.append(file.short_path)
return [files_by_path[short_path] for short_path in sorted(short_paths)]
def validate_hermetic_install_mode(attr, rule_name):
if getattr(attr, "install_mode", "disable") != "disable":
fail("{} requires install_mode = \"disable\" for hermetic execution".format(rule_name))
def infer_entry_point_root(entries):
if not entries:
return None
common_segments = entries[0].path.split("/")[:-1]
for entry in entries[1:]:
entry_segments = entry.path.split("/")[:-1]
common_length = min(len(common_segments), len(entry_segments))
idx = common_length
for segment_idx in range(common_length):
if common_segments[segment_idx] != entry_segments[segment_idx]:
idx = segment_idx
break
common_segments = common_segments[:idx]
if not common_segments:
return "."
return "/".join(common_segments)
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, root = None):
build_root = root
if build_root == None:
build_root = getattr(attr, "root", 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", build_root)
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))
def declare_staged_bun_build_action(ctx, bun_bin, build_args, build_inputs, outputs, mnemonic, progress_message, name_suffix):
sorted_inputs = sort_files_by_short_path(build_inputs.to_list())
input_manifest = ctx.actions.declare_file(ctx.label.name + name_suffix + ".inputs")
runner = ctx.actions.declare_file(ctx.label.name + name_suffix + "_runner.js")
ctx.actions.write(
output = input_manifest,
content = "".join([file.path + "\n" for file in sorted_inputs]),
)
ctx.actions.write(
output = runner,
content = _STAGED_BUILD_RUNNER,
)
ctx.actions.run(
executable = bun_bin,
arguments = ["--bun", runner.path, input_manifest.path, build_args],
inputs = depset(
direct = [input_manifest, runner],
transitive = [build_inputs],
),
outputs = outputs,
mnemonic = mnemonic,
progress_message = progress_message,
)

View File

@@ -1,59 +1,53 @@
"""Rule for bundling JS/TS sources with Bun.""" """Rule for bundling JS/TS sources with Bun."""
load("//internal:js_library.bzl", "BunSourcesInfo") load("//internal:bun_build_support.bzl", "add_bun_build_common_flags", "bun_build_transitive_inputs", "declare_staged_bun_build_action", "sort_files_by_short_path", "validate_hermetic_install_mode")
def _output_name(target_name, entry): def _output_name(target_name, entry):
stem = entry.basename.rsplit(".", 1)[0] stem = entry.short_path.rsplit(".", 1)[0]
return "{}__{}.js".format(target_name, stem) sanitized = stem.replace("\\", "_").replace("/", "_").replace("-", "_").replace(".", "_").replace("@", "at_")
sanitized = sanitized.replace("__", "_").replace("__", "_").replace("__", "_")
sanitized = sanitized.strip("_")
if not sanitized:
sanitized = entry.basename.rsplit(".", 1)[0]
return "{}__{}.js".format(target_name, sanitized)
def _bun_bundle_impl(ctx): def _bun_bundle_impl(ctx):
validate_hermetic_install_mode(ctx.attr, "bun_bundle")
toolchain = ctx.toolchains["//bun:toolchain_type"] toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin bun_bin = toolchain.bun.bun_bin
entry_points = sort_files_by_short_path(ctx.files.entry_points)
data_files = sort_files_by_short_path(ctx.files.data)
transitive_inputs = [] transitive_inputs = bun_build_transitive_inputs(ctx)
if ctx.attr.node_modules:
transitive_inputs.append(ctx.attr.node_modules[DefaultInfo].files)
for dep in ctx.attr.deps:
if BunSourcesInfo in dep:
transitive_inputs.append(dep[BunSourcesInfo].transitive_sources)
else:
transitive_inputs.append(dep[DefaultInfo].files)
outputs = [] outputs = []
for entry in ctx.files.entry_points: for entry in entry_points:
output = ctx.actions.declare_file(_output_name(ctx.label.name, entry)) output = ctx.actions.declare_file(_output_name(ctx.label.name, entry))
outputs.append(output) outputs.append(output)
args = ctx.actions.args() args = ctx.actions.args()
args.add("--bun") args.add("--bun")
args.add("build") args.add("build")
args.add(entry.path) add_bun_build_common_flags(args, ctx.attr)
args.add("--outfile") args.add("--outfile")
args.add(output.path) args.add(output.path)
args.add("--target") args.add(entry.path)
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)
ctx.actions.run( declare_staged_bun_build_action(
executable = bun_bin, ctx,
arguments = [args], bun_bin,
inputs = depset( args,
direct = [entry] + ctx.files.data, depset(
direct = [entry] + data_files,
transitive = transitive_inputs, transitive = transitive_inputs,
), ),
outputs = [output], outputs = [output],
mnemonic = "BunBundle", mnemonic = "BunBundle",
progress_message = "Bundling {} with Bun".format(entry.short_path), progress_message = "Bundling {} with Bun".format(entry.short_path),
name_suffix = "_bundle_{}".format(output.basename.rsplit(".", 1)[0]),
) )
return [DefaultInfo(files = depset(outputs))] return [DefaultInfo(files = depset(outputs))]
@@ -72,7 +66,7 @@ Each entry point produces one output JavaScript artifact.
doc = "Entry files to bundle.", doc = "Entry files to bundle.",
), ),
"node_modules": attr.label( "node_modules": attr.label(
doc = "Optional label providing Bun/npm package files for resolution.", doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, for package resolution.",
), ),
"deps": attr.label_list( "deps": attr.label_list(
doc = "Source/library dependencies that provide transitive inputs.", doc = "Source/library dependencies that provide transitive inputs.",
@@ -81,6 +75,11 @@ Each entry point produces one output JavaScript artifact.
allow_files = True, allow_files = True,
doc = "Additional non-source files needed during bundling.", 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. Hermetic bundle actions require `disable`; other values are rejected.",
),
"target": attr.string( "target": attr.string(
default = "browser", default = "browser",
values = ["browser", "node", "bun"], values = ["browser", "node", "bun"],
@@ -102,6 +101,9 @@ Each entry point produces one output JavaScript artifact.
"external": attr.string_list( "external": attr.string_list(
doc = "Package names to treat as externals (not bundled).", 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"], toolchains = ["//bun:toolchain_type"],
) )

113
internal/bun_command.bzl Normal file
View File

@@ -0,0 +1,113 @@
"""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)
def append_arg(values, value):
values.append(str(value))
def append_flag(values, flag, enabled):
if enabled:
append_arg(values, flag)
def append_flag_value(values, flag, value):
if value == None:
return
if type(value) == type("") and not value:
return
append_arg(values, flag)
append_arg(values, value)
def append_flag_values(values, flag, items):
for item in items:
append_flag_value(values, flag, item)
def append_raw_flags(values, items):
for item in items:
append_arg(values, item)
def append_install_mode(values, install_mode):
if install_mode == "disable":
append_arg(values, "--no-install")
elif install_mode in ["fallback", "force"]:
append_flag_value(values, "--install", install_mode)

335
internal/bun_compile.bzl Normal file
View File

@@ -0,0 +1,335 @@
"""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", "declare_staged_bun_build_action", "infer_entry_point_root", "sort_files_by_short_path", "validate_hermetic_install_mode")
def _bun_build_impl(ctx):
validate_hermetic_install_mode(ctx.attr, "bun_build")
toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin
entry_points = sort_files_by_short_path(ctx.files.entry_points)
data_files = sort_files_by_short_path(ctx.files.data)
output_dir = ctx.actions.declare_directory(ctx.label.name)
metafile = None
if ctx.attr.metafile:
metafile = ctx.actions.declare_file(ctx.label.name + ".meta.json")
metafile_md = None
if ctx.attr.metafile_md:
metafile_md = ctx.actions.declare_file(ctx.label.name + ".meta.md")
build_root = ctx.attr.root
if not build_root:
build_root = infer_entry_point_root(entry_points)
transitive_inputs = bun_build_transitive_inputs(ctx)
build_inputs = depset(
direct = entry_points + data_files,
transitive = transitive_inputs,
)
build_args = ctx.actions.args()
build_args.add("--bun")
build_args.add("build")
add_bun_build_common_flags(build_args, ctx.attr, metafile = metafile, metafile_md = metafile_md, root = build_root)
build_args.add("--outdir")
build_args.add(output_dir.path)
build_args.add_all(entry_points)
outputs = [output_dir]
if metafile:
outputs.append(metafile)
if metafile_md:
outputs.append(metafile_md)
declare_staged_bun_build_action(
ctx,
bun_bin,
build_args,
build_inputs,
outputs = outputs,
mnemonic = "BunBuild",
progress_message = "Building {} with Bun".format(ctx.label.name),
name_suffix = "_build",
)
return [DefaultInfo(files = depset(outputs))]
def _bun_compile_impl(ctx):
validate_hermetic_install_mode(ctx.attr, "bun_compile")
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
data_files = sort_files_by_short_path(ctx.files.data)
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] + data_files
if compile_executable:
direct_inputs.append(compile_executable)
declare_staged_bun_build_action(
ctx,
bun_bin,
args,
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),
name_suffix = "_compile",
)
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. Hermetic build actions require `disable`; other values are rejected.",
),
"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,186 +1,140 @@
"""Rule for running JS/TS scripts with Bun in watch mode for development.""" """Rule for running JS/TS scripts with Bun in watch mode for development."""
load("//internal:bun_command.bzl", "append_flag", "append_flag_values", "append_install_mode", "append_raw_flags")
load("//internal:runtime_launcher.bzl", "declare_runtime_wrapper", "runfiles_path", "runtime_launcher_attrs", "write_launcher_spec")
load("//internal:workspace.bzl", "create_bun_workspace_info", "workspace_runfiles")
def _bun_dev_impl(ctx): def _bun_dev_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"] toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin bun_bin = toolchain.bun.bun_bin
entry_point = ctx.file.entry_point entry_point = ctx.file.entry_point
workspace_info = create_bun_workspace_info(
restart_watch_paths = "\n".join([path.short_path for path in ctx.files.restart_on]) ctx,
extra_files = ctx.files.data + ctx.files.restart_on + ctx.files.preload + ctx.files.env_files + [bun_bin],
launcher = ctx.actions.declare_file(ctx.label.name) primary_file = entry_point,
ctx.actions.write(
output = launcher,
is_executable = True,
content = """#!/usr/bin/env bash
set -euo pipefail
runfiles_dir="${{RUNFILES_DIR:-$0.runfiles}}"
workspace_root="${{runfiles_dir}}/_main"
bun_bin="${{runfiles_dir}}/_main/{bun_short_path}"
entry_point="${{runfiles_dir}}/_main/{entry_short_path}"
resolve_entrypoint_workdir() {{
local dir
dir="$(dirname "${{entry_point}}")"
while [[ "${{dir}}" == "${{workspace_root}}"* ]]; do
if [[ -f "${{dir}}/.env" || -f "${{dir}}/package.json" ]]; then
echo "${{dir}}"
return 0
fi
if [[ "${{dir}}" == "${{workspace_root}}" ]]; then
break
fi
dir="$(dirname "${{dir}}")"
done
echo "$(dirname "${{entry_point}}")"
}}
working_dir="{working_dir}"
if [[ "${{working_dir}}" == "entry_point" ]]; then
cd "$(resolve_entrypoint_workdir)"
else
cd "${{workspace_root}}"
fi
watch_mode="{watch_mode}"
if [[ "${{watch_mode}}" == "hot" ]]; then
dev_flag="--hot"
else
dev_flag="--watch"
fi
run_dev() {{
exec "${{bun_bin}}" --bun "${{dev_flag}}" run "${{entry_point}}" "$@"
}}
if [[ {restart_count} -eq 0 ]]; then
run_dev "$@"
fi
readarray -t restart_paths <<'EOF_RESTART_PATHS'
{restart_watch_paths}
EOF_RESTART_PATHS
file_mtime() {{
local p="$1"
if stat -f '%m' "${{p}}" >/dev/null 2>&1; then
stat -f '%m' "${{p}}"
return 0
fi
stat -c '%Y' "${{p}}"
}}
declare -A mtimes
for rel in "${{restart_paths[@]}}"; do
path="${{runfiles_dir}}/_main/${{rel}}"
if [[ -e "${{path}}" ]]; then
mtimes["${{rel}}"]="$(file_mtime "${{path}}")"
else
mtimes["${{rel}}"]="missing"
fi
done
child_pid=""
restart_child() {{
if [[ -n "${{child_pid}}" ]] && kill -0 "${{child_pid}}" 2>/dev/null; then
kill "${{child_pid}}"
wait "${{child_pid}}" || true
fi
"${{bun_bin}}" --bun "${{dev_flag}}" run "${{entry_point}}" "$@" &
child_pid=$!
}}
cleanup() {{
if [[ -n "${{child_pid}}" ]] && kill -0 "${{child_pid}}" 2>/dev/null; then
kill "${{child_pid}}"
wait "${{child_pid}}" || true
fi
}}
trap cleanup EXIT INT TERM
restart_child "$@"
while true; do
sleep 1
changed=0
for rel in "${{restart_paths[@]}}"; do
path="${{runfiles_dir}}/_main/${{rel}}"
if [[ -e "${{path}}" ]]; then
current="$(file_mtime "${{path}}")"
else
current="missing"
fi
if [[ "${{current}}" != "${{mtimes[${{rel}}]}}" ]]; then
mtimes["${{rel}}"]="${{current}}"
changed=1
fi
done
if [[ "${{changed}}" -eq 1 ]]; then
restart_child "$@"
fi
done
""".format(
bun_short_path = bun_bin.short_path,
entry_short_path = entry_point.short_path,
watch_mode = ctx.attr.watch_mode,
working_dir = ctx.attr.working_dir,
restart_count = len(ctx.files.restart_on),
restart_watch_paths = restart_watch_paths,
),
) )
transitive_files = [] argv = ["--bun", "run"]
if ctx.attr.node_modules: append_install_mode(argv, ctx.attr.install_mode)
transitive_files.append(ctx.attr.node_modules[DefaultInfo].files) append_flag(argv, "--no-env-file", ctx.attr.no_env_file)
append_flag(argv, "--smol", ctx.attr.smol)
append_flag_values(argv, "--conditions", ctx.attr.conditions)
append_flag(argv, "--no-clear-screen", ctx.attr.no_clear_screen)
append_raw_flags(argv, ctx.attr.run_flags)
runfiles = ctx.runfiles( spec_file = write_launcher_spec(ctx, {
files = [bun_bin, entry_point] + ctx.files.data + ctx.files.restart_on, "version": 1,
transitive_files = depset(transitive = transitive_files), "kind": "bun_run",
) "bun_short_path": runfiles_path(bun_bin),
"primary_source_short_path": runfiles_path(entry_point),
"package_json_short_path": "",
"install_metadata_short_path": runfiles_path(workspace_info.install_metadata_file) if workspace_info.install_metadata_file else "",
"install_repo_runfiles_path": workspace_info.install_repo_runfiles_path,
"node_modules_roots": workspace_info.node_modules_roots,
"package_dir_hint": workspace_info.package_dir_hint,
"working_dir_mode": ctx.attr.working_dir,
"inherit_host_path": ctx.attr.inherit_host_path,
"argv": argv,
"args": ctx.attr.args,
"passthrough_args": True,
"tool_short_path": "",
"restart_on": [runfiles_path(file) for file in ctx.files.restart_on],
"watch_mode": ctx.attr.watch_mode,
"reporter": "",
"coverage": False,
"coverage_reporters": [],
"preload_short_paths": [runfiles_path(file) for file in ctx.files.preload],
"env_file_short_paths": [runfiles_path(file) for file in ctx.files.env_files],
"test_short_paths": [],
})
launcher = declare_runtime_wrapper(ctx, bun_bin, spec_file)
return [ return [
workspace_info,
DefaultInfo( DefaultInfo(
executable = launcher, executable = launcher.executable,
runfiles = runfiles, runfiles = workspace_runfiles(
ctx,
workspace_info,
direct_files = [launcher.executable, launcher.runner, spec_file],
),
), ),
] ]
_BUN_DEV_ATTRS = runtime_launcher_attrs()
_BUN_DEV_ATTRS.update({
"entry_point": attr.label(
mandatory = True,
allow_single_file = [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"],
doc = "Path to the main JS/TS file to execute in dev mode.",
),
"watch_mode": attr.string(
default = "watch",
values = ["watch", "hot"],
doc = "Bun live-reload mode: `watch` (default) or `hot`.",
),
"restart_on": attr.label_list(
allow_files = True,
doc = "Files that trigger a full Bun process restart when they change.",
),
"node_modules": attr.label(
doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles.",
),
"data": attr.label_list(
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"],
doc = "Working directory at runtime: `workspace` root or nearest `entry_point` ancestor containing `.env`/`package.json`.",
),
"inherit_host_path": attr.bool(
default = False,
doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
),
})
bun_dev = rule( bun_dev = rule(
implementation = _bun_dev_impl, implementation = _bun_dev_impl,
doc = """Runs a JS/TS entry point in Bun development watch mode. doc = """Runs a JS/TS entry point in Bun development watch mode.
This rule is intended for local dev loops (`bazel run`) and supports Bun This rule is intended for local dev loops (`bazel run`) and supports Bun
watch/HMR plus optional full restarts on selected file changes. watch/HMR plus optional full restarts on selected file changes. It is a local
workflow helper rather than a hermetic build rule.
""", """,
attrs = { attrs = _BUN_DEV_ATTRS,
"entry_point": attr.label(
mandatory = True,
allow_single_file = [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"],
doc = "Path to the main JS/TS file to execute in dev mode.",
),
"watch_mode": attr.string(
default = "watch",
values = ["watch", "hot"],
doc = "Bun live-reload mode: `watch` (default) or `hot`.",
),
"restart_on": attr.label_list(
allow_files = True,
doc = "Files that trigger a full Bun process restart when they change.",
),
"node_modules": attr.label(
doc = "Optional label providing Bun/npm package files in runfiles.",
),
"data": attr.label_list(
allow_files = True,
doc = "Additional runtime files required by the dev process.",
),
"working_dir": attr.string(
default = "workspace",
values = ["workspace", "entry_point"],
doc = "Working directory at runtime: `workspace` root or nearest `entry_point` ancestor containing `.env`/`package.json`.",
),
},
executable = True, executable = True,
toolchains = ["//bun:toolchain_type"], toolchains = ["//bun:toolchain_type"],
) )

View File

@@ -1,5 +1,251 @@
"""Repository-rule based bun_install implementation.""" """Repository-rule based bun_install implementation."""
_DEFAULT_INSTALL_INPUTS = [
".npmrc",
"bunfig.json",
"bunfig.toml",
]
_MANIFEST_DEP_FIELDS = [
"dependencies",
"devDependencies",
"optionalDependencies",
"peerDependencies",
]
def _normalize_path(path):
normalized = path.replace("\\", "/")
if normalized.endswith("/") and normalized != "/":
normalized = normalized[:-1]
return normalized
def _relative_to_root(root, child):
normalized_root = _normalize_path(root)
normalized_child = _normalize_path(child)
if normalized_child == normalized_root:
return ""
prefix = normalized_root + "/"
if not normalized_child.startswith(prefix):
fail("bun_install: expected install input {} to be under {}".format(child, root))
return normalized_child[len(prefix):]
def _segment_matches(name, pattern):
if pattern == "*":
return True
if "*" not in pattern:
return name == pattern
parts = pattern.split("*")
if len(parts) == 1:
return name == pattern
pos = 0
anchored_start = not pattern.startswith("*")
anchored_end = not pattern.endswith("*")
for i, part in enumerate(parts):
if not part:
continue
match_index = name.find(part, pos)
if match_index < 0:
return False
if i == 0 and anchored_start and match_index != 0:
return False
pos = match_index + len(part)
if anchored_end and parts[-1] and not name.endswith(parts[-1]):
return False
return True
def _walk_workspace_dirs(root, segments):
matches = [root]
for segment in segments:
if segment == "**":
fail("bun_install: `**` is not supported in workspace patterns; use explicit segments or `*`")
next_matches = []
for parent in matches:
for child in parent.readdir():
if child.is_dir and _segment_matches(child.basename, segment):
next_matches.append(child)
matches = next_matches
return matches
def _workspace_patterns(repository_ctx, package_json):
manifest = json.decode(repository_ctx.read(package_json))
workspaces = manifest.get("workspaces", [])
if type(workspaces) == type({}):
workspaces = workspaces.get("packages", [])
if type(workspaces) != type([]):
fail("bun_install: `workspaces` must be a list or an object with a `packages` list")
patterns = []
for pattern in workspaces:
if type(pattern) != type(""):
fail("bun_install: workspace pattern must be a string, got {}".format(type(pattern)))
normalized = "/".join([segment for segment in pattern.split("/") if segment and segment != "."])
if normalized:
patterns.append(normalized)
return patterns
def _validate_catalog_shape(field, value):
if value == None:
return
if type(value) != type({}):
fail("bun_install: `{}` must be an object".format(field))
if field not in ["catalogs", "workspaces.catalogs"]:
return
for name, catalog in value.items():
if type(name) != type(""):
fail("bun_install: `catalogs` keys must be strings, got {}".format(type(name)))
if type(catalog) != type({}):
fail("bun_install: `catalogs.{}` must be an object".format(name))
def _copy_json_value(value):
return json.decode(json.encode(value))
def _package_target_name(package_name):
sanitized = package_name
sanitized = sanitized.replace("@", "at_")
sanitized = sanitized.replace("/", "_")
sanitized = sanitized.replace("-", "_")
sanitized = sanitized.replace(".", "_")
sanitized = sanitized.replace("__", "_").replace("__", "_").replace("__", "_")
sanitized = sanitized.strip("_")
if not sanitized:
sanitized = "package"
return "npm__" + sanitized
def _manifest_dependency_names(manifest):
names = {}
for field in _MANIFEST_DEP_FIELDS:
dependencies = manifest.get(field)
if dependencies == None:
continue
if type(dependencies) != type({}):
fail("bun_install: `{}` must be an object when present".format(field))
for name in dependencies.keys():
names[name] = True
return names
def _normalized_root_manifest(repository_ctx, package_json):
manifest = json.decode(repository_ctx.read(package_json))
workspaces = manifest.get("workspaces")
for field in ["catalog", "catalogs"]:
manifest_value = manifest.get(field)
_validate_catalog_shape(field, manifest_value)
if type(workspaces) != type({}):
continue
workspace_value = workspaces.get(field)
_validate_catalog_shape("workspaces.{}".format(field), workspace_value)
if workspace_value == None:
continue
if manifest_value == None:
manifest[field] = _copy_json_value(workspace_value)
continue
if manifest_value != workspace_value:
fail(
"bun_install: `{}` conflicts with `workspaces.{}`; use one source of truth or keep both values identical".format(field, field),
)
return json.encode(manifest)
def _materialize_workspace_packages(repository_ctx, package_json):
package_root = package_json.dirname
package_root_str = str(package_root)
written = {}
workspace_packages = {}
for pattern in _workspace_patterns(repository_ctx, package_json):
segments = pattern.split("/")
for workspace_dir in _walk_workspace_dirs(package_root, segments):
workspace_package_json = repository_ctx.path(str(workspace_dir) + "/package.json")
if not workspace_package_json.exists:
continue
workspace_dir_str = str(workspace_dir)
if workspace_dir_str == package_root_str:
continue
relative_dir = _relative_to_root(package_root_str, workspace_dir_str)
if relative_dir in written:
continue
repository_ctx.file(
relative_dir + "/package.json",
repository_ctx.read(workspace_package_json),
)
written[relative_dir] = True
manifest = json.decode(repository_ctx.read(workspace_package_json))
package_name = manifest.get("name")
workspace_packages[relative_dir] = package_name if type(package_name) == type("") else ""
package_dirs = sorted(workspace_packages.keys())
package_names_by_dir = {}
for package_dir in package_dirs:
package_name = workspace_packages[package_dir]
if package_name:
package_names_by_dir[package_dir] = package_name
return struct(
package_dirs = package_dirs,
package_names_by_dir = package_names_by_dir,
package_names = [workspace_packages[package_dir] for package_dir in package_dirs if workspace_packages[package_dir]],
)
def _materialize_install_inputs(repository_ctx, package_json):
package_root = package_json.dirname
package_root_str = str(package_root)
written = {}
for relative_path in _DEFAULT_INSTALL_INPUTS:
source_path = repository_ctx.path(str(package_root) + "/" + relative_path)
if source_path.exists and not source_path.is_dir:
repository_ctx.file(relative_path, repository_ctx.read(source_path))
written[relative_path] = True
for install_input in repository_ctx.attr.install_inputs:
source_path = repository_ctx.path(install_input)
if not source_path.exists:
fail("bun_install: install input not found: {}".format(install_input))
if source_path.is_dir:
fail("bun_install: install_inputs must be files under the package root: {}".format(install_input))
relative_path = _relative_to_root(package_root_str, str(source_path))
if not relative_path:
fail("bun_install: install input must be a file under the package root: {}".format(install_input))
if relative_path in written:
continue
repository_ctx.file(relative_path, repository_ctx.read(source_path))
written[relative_path] = True
def _select_bun_binary(repository_ctx): def _select_bun_binary(repository_ctx):
os_name = repository_ctx.os.name.lower() os_name = repository_ctx.os.name.lower()
arch = repository_ctx.os.arch.lower() arch = repository_ctx.os.arch.lower()
@@ -19,6 +265,68 @@ def _select_bun_binary(repository_ctx):
fail("Unsupported host platform: os={}, arch={}".format(repository_ctx.os.name, repository_ctx.os.arch)) fail("Unsupported host platform: os={}, arch={}".format(repository_ctx.os.name, repository_ctx.os.arch))
def _render_package_targets_file(package_names):
lines = ["NPM_PACKAGE_TARGETS = {"]
for package_name in package_names:
lines.append(' "{}": "{}",'.format(package_name, _package_target_name(package_name)))
lines.extend([
"}",
"",
])
return "\n".join(lines)
def _render_repo_defs_bzl(repo_name):
return """load(":packages.bzl", "NPM_PACKAGE_TARGETS")
def package_target_name(package_name):
return NPM_PACKAGE_TARGETS.get(package_name)
def npm_link_all_packages(name = "node_modules", imported_links = []):
if not native.existing_rule(name):
native.alias(
name = name,
actual = "@{repo_name}//:node_modules",
)
requested = {{}}
for package_name in imported_links:
requested[package_name] = True
for package_name, target_name in NPM_PACKAGE_TARGETS.items():
if imported_links and package_name not in requested:
continue
if native.existing_rule(target_name):
continue
native.alias(
name = target_name,
actual = "@{repo_name}//:%s" % target_name,
)
""".format(repo_name = repo_name)
def _render_repo_build(package_names):
lines = [
'exports_files(["defs.bzl", "packages.bzl"])',
"",
"filegroup(",
' name = "node_modules",',
' srcs = glob(["**/node_modules/**"], allow_empty = False),',
' visibility = ["//visibility:public"],',
")",
"",
]
for package_name in package_names:
lines.extend([
"filegroup(",
' name = "{}",'.format(_package_target_name(package_name)),
' srcs = glob(["node_modules/{}/**"], allow_empty = True),'.format(package_name),
' visibility = ["//visibility:public"],',
")",
"",
])
return "\n".join(lines)
def _bun_install_repository_impl(repository_ctx): def _bun_install_repository_impl(repository_ctx):
package_json = repository_ctx.path(repository_ctx.attr.package_json) package_json = repository_ctx.path(repository_ctx.attr.package_json)
bun_lockfile = repository_ctx.path(repository_ctx.attr.bun_lockfile) bun_lockfile = repository_ctx.path(repository_ctx.attr.bun_lockfile)
@@ -30,16 +338,42 @@ def _bun_install_repository_impl(repository_ctx):
fail("bun_install: bun_lockfile not found: {}".format(repository_ctx.attr.bun_lockfile)) fail("bun_install: bun_lockfile not found: {}".format(repository_ctx.attr.bun_lockfile))
bun_bin = _select_bun_binary(repository_ctx) bun_bin = _select_bun_binary(repository_ctx)
lockfile_name = bun_lockfile.basename
root_manifest = json.decode(repository_ctx.read(package_json))
repository_ctx.symlink(package_json, "package.json") if lockfile_name not in ["bun.lock", "bun.lockb"]:
repository_ctx.symlink(bun_lockfile, "bun.lockb") lockfile_name = "bun.lock"
result = repository_ctx.execute( repository_ctx.file("package.json", _normalized_root_manifest(repository_ctx, package_json))
[str(bun_bin), "--bun", "install", "--frozen-lockfile", "--no-progress"], repository_ctx.symlink(bun_lockfile, lockfile_name)
timeout = 600, _materialize_install_inputs(repository_ctx, package_json)
quiet = False, workspace_packages = _materialize_workspace_packages(repository_ctx, package_json)
environment = {"HOME": str(repository_ctx.path("."))},
) 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,
timeout = 600,
quiet = False,
environment = {"HOME": str(repository_ctx.path("."))},
)
else:
result = repository_ctx.execute(
install_args,
timeout = 600,
quiet = False,
)
if result.return_code: if result.return_code:
fail("""bun_install failed running `bun --bun install --frozen-lockfile`. fail("""bun_install failed running `bun --bun install --frozen-lockfile`.
@@ -50,35 +384,78 @@ stderr:
""".format(result.stdout, result.stderr)) """.format(result.stdout, result.stderr))
repository_ctx.file( repository_ctx.file(
"BUILD.bazel", "node_modules/.rules_bun/install.json",
"""filegroup( json.encode({
name = "node_modules", "bun_lockfile": lockfile_name,
srcs = glob(["node_modules/**"], allow_empty = False), "install_root_rel_dir": ".",
visibility = ["//visibility:public"], "package_json": "package.json",
) "workspace_package_dirs": workspace_packages.package_dirs,
""", "workspace_package_names_by_dir": workspace_packages.package_names_by_dir,
}) + "\n",
) )
package_names = {}
for package_name in _manifest_dependency_names(root_manifest).keys():
package_names[package_name] = True
for package_name in workspace_packages.package_names:
package_names[package_name] = True
sorted_package_names = sorted(package_names.keys())
visible_repo_name = repository_ctx.attr.visible_repo_name or repository_ctx.name
repository_ctx.file("packages.bzl", _render_package_targets_file(sorted_package_names))
repository_ctx.file("defs.bzl", _render_repo_defs_bzl(visible_repo_name))
repository_ctx.file("BUILD.bazel", _render_repo_build(sorted_package_names))
bun_install_repository = repository_rule( bun_install_repository = repository_rule(
implementation = _bun_install_repository_impl, implementation = _bun_install_repository_impl,
attrs = { attrs = {
"package_json": attr.label(mandatory = True, allow_single_file = True), "package_json": attr.label(mandatory = True, allow_single_file = True),
"bun_lockfile": attr.label(mandatory = True, allow_single_file = True), "bun_lockfile": attr.label(mandatory = True, allow_single_file = True),
"bun_linux_x64": attr.label(default = "@bun_linux_x64//:bun", allow_single_file = True), "install_inputs": attr.label_list(allow_files = True),
"bun_linux_aarch64": attr.label(default = "@bun_linux_aarch64//:bun", allow_single_file = True), "isolated_home": attr.bool(default = True),
"bun_darwin_x64": attr.label(default = "@bun_darwin_x64//:bun", allow_single_file = True), "production": attr.bool(default = False),
"bun_darwin_aarch64": attr.label(default = "@bun_darwin_aarch64//:bun", allow_single_file = True), "omit": attr.string_list(),
"bun_windows_x64": attr.label(default = "@bun_windows_x64//:bun", allow_single_file = True), "linker": attr.string(),
"backend": attr.string(),
"ignore_scripts": attr.bool(default = True),
"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),
"bun_darwin_x64": attr.label(default = "@bun_darwin_x64//:bun-darwin-x64/bun", allow_single_file = True),
"bun_darwin_aarch64": attr.label(default = "@bun_darwin_aarch64//:bun-darwin-aarch64/bun", allow_single_file = True),
"bun_windows_x64": attr.label(default = "@bun_windows_x64//:bun-windows-x64/bun.exe", allow_single_file = True),
}, },
) )
def bun_install(name, package_json, bun_lockfile): def bun_install(
name,
package_json,
bun_lockfile,
install_inputs = [],
isolated_home = True,
production = False,
omit = [],
linker = "",
backend = "",
ignore_scripts = True,
install_flags = []):
"""Create an external repository containing installed node_modules. """Create an external repository containing installed node_modules.
Args: Args:
name: Repository name to create. name: Repository name to create.
package_json: Label to a package.json file. package_json: Label to a package.json file.
bun_lockfile: Label to a bun.lockb file. bun_lockfile: Label to a bun.lockb file.
install_inputs: Optional additional files under the package root to copy
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): Usage (WORKSPACE):
bun_install( bun_install(
@@ -92,4 +469,13 @@ def bun_install(name, package_json, bun_lockfile):
name = name, name = name,
package_json = package_json, package_json = package_json,
bun_lockfile = bun_lockfile, 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,91 +1,168 @@
"""Rule for running package.json scripts with Bun.""" """Rule for running package.json scripts with Bun."""
load("//internal:bun_command.bzl", "append_flag", "append_flag_value", "append_flag_values", "append_install_mode", "append_raw_flags")
def _shell_quote(value): load("//internal:runtime_launcher.bzl", "declare_runtime_wrapper", "runfiles_path", "runtime_launcher_attrs", "write_launcher_spec")
return "'" + value.replace("'", "'\"'\"'") + "'" load("//internal:workspace.bzl", "create_bun_workspace_info", "workspace_runfiles")
def _bun_script_impl(ctx): def _bun_script_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"] toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin bun_bin = toolchain.bun.bun_bin
package_json = ctx.file.package_json package_json = ctx.file.package_json
workspace_info = create_bun_workspace_info(
launcher = ctx.actions.declare_file(ctx.label.name) ctx,
ctx.actions.write( extra_files = ctx.files.data + ctx.files.preload + ctx.files.env_files + [bun_bin],
output = launcher, package_dir_hint = package_json.dirname or ".",
is_executable = True, package_json = package_json,
content = """#!/usr/bin/env bash primary_file = package_json,
set -euo pipefail
runfiles_dir="${{RUNFILES_DIR:-$0.runfiles}}"
workspace_root="${{runfiles_dir}}/_main"
bun_bin="${{runfiles_dir}}/_main/{bun_short_path}"
package_json="${{runfiles_dir}}/_main/{package_json_short_path}"
package_dir="$(dirname "${{package_json}}")"
working_dir="{working_dir}"
if [[ "${{working_dir}}" == "package" ]]; then
cd "${{package_dir}}"
else
cd "${{workspace_root}}"
fi
exec "${{bun_bin}}" --bun run {script} "$@"
""".format(
bun_short_path = bun_bin.short_path,
package_json_short_path = package_json.short_path,
working_dir = ctx.attr.working_dir,
script = _shell_quote(ctx.attr.script),
),
) )
transitive_files = [] argv = ["--bun", "run"]
if ctx.attr.node_modules: append_install_mode(argv, ctx.attr.install_mode)
transitive_files.append(ctx.attr.node_modules[DefaultInfo].files) append_flag(argv, "--no-env-file", ctx.attr.no_env_file)
append_flag(argv, "--smol", ctx.attr.smol)
append_flag_values(argv, "--conditions", ctx.attr.conditions)
append_flag(argv, "--workspaces", ctx.attr.workspaces)
append_flag_values(argv, "--filter", ctx.attr.filters)
if ctx.attr.execution_mode == "parallel":
append_flag(argv, "--parallel", True)
elif ctx.attr.execution_mode == "sequential":
append_flag(argv, "--sequential", True)
append_flag(argv, "--no-exit-on-error", ctx.attr.no_exit_on_error)
append_flag_value(argv, "--shell", ctx.attr.shell)
append_flag(argv, "--silent", ctx.attr.silent)
append_raw_flags(argv, ctx.attr.run_flags)
runfiles = ctx.runfiles( spec_file = write_launcher_spec(ctx, {
files = [bun_bin, package_json] + ctx.files.data, "version": 1,
transitive_files = depset(transitive = transitive_files), "kind": "bun_run",
) "bun_short_path": runfiles_path(bun_bin),
"primary_source_short_path": "",
"package_json_short_path": runfiles_path(package_json),
"install_metadata_short_path": runfiles_path(workspace_info.install_metadata_file) if workspace_info.install_metadata_file else "",
"install_repo_runfiles_path": workspace_info.install_repo_runfiles_path,
"node_modules_roots": workspace_info.node_modules_roots,
"package_dir_hint": package_json.dirname or ".",
"working_dir_mode": ctx.attr.working_dir,
"inherit_host_path": ctx.attr.inherit_host_path,
"argv": argv,
"args": [ctx.attr.script] + ctx.attr.args,
"passthrough_args": True,
"tool_short_path": "",
"restart_on": [],
"watch_mode": "",
"reporter": "",
"coverage": False,
"coverage_reporters": [],
"preload_short_paths": [runfiles_path(file) for file in ctx.files.preload],
"env_file_short_paths": [runfiles_path(file) for file in ctx.files.env_files],
"test_short_paths": [],
})
launcher = declare_runtime_wrapper(ctx, bun_bin, spec_file)
return [ return [
workspace_info,
DefaultInfo( DefaultInfo(
executable = launcher, executable = launcher.executable,
runfiles = runfiles, runfiles = workspace_runfiles(
ctx,
workspace_info,
direct_files = [launcher.executable, launcher.runner, spec_file],
),
), ),
] ]
_BUN_SCRIPT_ATTRS = runtime_launcher_attrs()
_BUN_SCRIPT_ATTRS.update({
"script": attr.string(
mandatory = True,
doc = "Name of the `package.json` script to execute via `bun run <script>`.",
),
"package_json": attr.label(
mandatory = True,
allow_single_file = True,
doc = "Label of the `package.json` file containing the named script.",
),
"node_modules": attr.label(
doc = "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`.",
),
"data": attr.label_list(
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"],
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.",
),
"inherit_host_path": attr.bool(
default = False,
doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
),
})
bun_script = rule( bun_script = rule(
implementation = _bun_script_impl, implementation = _bun_script_impl,
doc = """Runs a named `package.json` script with Bun as an executable target. 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 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. This
is a local workflow helper rather than a hermetic build rule.
""", """,
attrs = { attrs = _BUN_SCRIPT_ATTRS,
"script": attr.string(
mandatory = True,
doc = "Name of the `package.json` script to execute via `bun run <script>`.",
),
"package_json": attr.label(
mandatory = True,
allow_single_file = True,
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.",
),
"data": attr.label_list(
allow_files = True,
doc = "Additional runtime files required by the script.",
),
"working_dir": attr.string(
default = "package",
values = ["workspace", "package"],
doc = "Working directory at runtime: Bazel runfiles `workspace` root or the directory containing `package.json`.",
),
},
executable = True, executable = True,
toolchains = ["//bun:toolchain_type"], toolchains = ["//bun:toolchain_type"],
) )

View File

@@ -1,89 +1,198 @@
"""Rule for running test suites with Bun.""" """Rule for running test suites with Bun."""
load("//internal:js_library.bzl", "BunSourcesInfo") load("//internal:bun_command.bzl", "append_flag", "append_flag_value", "append_install_mode", "append_raw_flags")
load("//internal:js_library.bzl", "collect_js_runfiles")
load("//internal:runtime_launcher.bzl", "declare_runtime_wrapper", "runfiles_path", "runtime_launcher_attrs", "write_launcher_spec")
def _shell_quote(value): load("//internal:workspace.bzl", "create_bun_workspace_info", "workspace_runfiles")
return "'" + value.replace("'", "'\"'\"'") + "'"
def _bun_test_impl(ctx): def _bun_test_impl(ctx):
if ctx.attr.install_mode != "disable":
fail("bun_test requires install_mode = \"disable\" for hermetic test execution")
toolchain = ctx.toolchains["//bun:toolchain_type"] toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin bun_bin = toolchain.bun.bun_bin
primary_file = ctx.files.srcs[0]
src_args = " ".join([_shell_quote(src.short_path) for src in ctx.files.srcs]) dep_runfiles = [collect_js_runfiles(dep) for dep in ctx.attr.deps]
launcher = ctx.actions.declare_file(ctx.label.name) workspace_info = create_bun_workspace_info(
ctx.actions.write( ctx,
output = launcher, extra_files = ctx.files.srcs + ctx.files.data + ctx.files.preload + ctx.files.env_files + [bun_bin],
is_executable = True, primary_file = primary_file,
content = """#!/usr/bin/env bash
set -euo pipefail
runfiles_dir="${{RUNFILES_DIR:-$0.runfiles}}"
bun_bin="${{runfiles_dir}}/_main/{bun_short_path}"
cd "${{runfiles_dir}}/_main"
if [[ -n "${{TESTBRIDGE_TEST_ONLY:-}}" && -n "${{COVERAGE_DIR:-}}" ]]; then
exec "${{bun_bin}}" --bun test {src_args} --test-name-pattern "${{TESTBRIDGE_TEST_ONLY}}" --coverage "$@"
fi
if [[ -n "${{TESTBRIDGE_TEST_ONLY:-}}" ]]; then
exec "${{bun_bin}}" --bun test {src_args} --test-name-pattern "${{TESTBRIDGE_TEST_ONLY}}" "$@"
fi
if [[ -n "${{COVERAGE_DIR:-}}" ]]; then
exec "${{bun_bin}}" --bun test {src_args} --coverage "$@"
fi
exec "${{bun_bin}}" --bun test {src_args} "$@"
""".format(
bun_short_path = bun_bin.short_path,
src_args = src_args,
),
) )
transitive_files = [] argv = ["--bun", "test"]
if ctx.attr.node_modules: append_install_mode(argv, ctx.attr.install_mode)
transitive_files.append(ctx.attr.node_modules[DefaultInfo].files) append_flag(argv, "--no-env-file", ctx.attr.no_env_file)
for dep in ctx.attr.deps: append_flag(argv, "--smol", ctx.attr.smol)
if BunSourcesInfo in dep: append_flag_value(argv, "--timeout", str(ctx.attr.timeout_ms) if ctx.attr.timeout_ms > 0 else None)
transitive_files.append(dep[BunSourcesInfo].transitive_sources) append_flag(argv, "--update-snapshots", ctx.attr.update_snapshots)
else: append_flag_value(argv, "--rerun-each", str(ctx.attr.rerun_each) if ctx.attr.rerun_each > 0 else None)
transitive_files.append(dep[DefaultInfo].files) append_flag_value(argv, "--retry", str(ctx.attr.retry) if ctx.attr.retry > 0 else None)
append_flag(argv, "--todo", ctx.attr.todo)
append_flag(argv, "--only", ctx.attr.only)
append_flag(argv, "--pass-with-no-tests", ctx.attr.pass_with_no_tests)
append_flag(argv, "--concurrent", ctx.attr.concurrent)
append_flag(argv, "--randomize", ctx.attr.randomize)
append_flag_value(argv, "--seed", str(ctx.attr.seed) if ctx.attr.seed > 0 else None)
append_flag_value(argv, "--bail", str(ctx.attr.bail) if ctx.attr.bail > 0 else None)
append_flag_value(argv, "--max-concurrency", str(ctx.attr.max_concurrency) if ctx.attr.max_concurrency > 0 else None)
append_raw_flags(argv, ctx.attr.test_flags)
runfiles = ctx.runfiles( spec_file = write_launcher_spec(ctx, {
files = [bun_bin] + ctx.files.srcs + ctx.files.data, "version": 1,
transitive_files = depset(transitive = transitive_files), "kind": "bun_test",
) "bun_short_path": runfiles_path(bun_bin),
"primary_source_short_path": runfiles_path(primary_file),
"package_json_short_path": "",
"install_metadata_short_path": runfiles_path(workspace_info.install_metadata_file) if workspace_info.install_metadata_file else "",
"install_repo_runfiles_path": workspace_info.install_repo_runfiles_path,
"node_modules_roots": workspace_info.node_modules_roots,
"package_dir_hint": workspace_info.package_dir_hint,
"working_dir_mode": "workspace",
"inherit_host_path": ctx.attr.inherit_host_path,
"argv": argv,
"args": ctx.attr.args,
"passthrough_args": True,
"tool_short_path": "",
"restart_on": [],
"watch_mode": "",
"reporter": ctx.attr.reporter,
"coverage": ctx.attr.coverage,
"coverage_reporters": ctx.attr.coverage_reporters,
"preload_short_paths": [runfiles_path(file) for file in ctx.files.preload],
"env_file_short_paths": [runfiles_path(file) for file in ctx.files.env_files],
"test_short_paths": [runfiles_path(file) for file in ctx.files.srcs],
})
launcher = declare_runtime_wrapper(ctx, bun_bin, spec_file)
return [ return [
workspace_info,
DefaultInfo( DefaultInfo(
executable = launcher, executable = launcher.executable,
runfiles = runfiles, runfiles = workspace_runfiles(
ctx,
workspace_info,
direct_files = [launcher.executable, launcher.runner, spec_file],
transitive_files = dep_runfiles,
),
), ),
] ]
_BUN_TEST_ATTRS = runtime_launcher_attrs()
_BUN_TEST_ATTRS.update({
"srcs": attr.label_list(
mandatory = True,
allow_files = [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"],
doc = "Test source files passed to `bun test`.",
),
"node_modules": attr.label(
doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles.",
),
"deps": attr.label_list(
doc = "Library dependencies required by test sources.",
),
"data": attr.label_list(
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.",
),
"inherit_host_path": attr.bool(
default = False,
doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
),
})
bun_test = rule( bun_test = rule(
implementation = _bun_test_impl, implementation = _bun_test_impl,
doc = """Runs Bun tests as a Bazel test target. doc = """Runs Bun tests as a Bazel test target.
Supports Bazel test filtering (`--test_filter`) and coverage integration. Supports Bazel test filtering (`--test_filter`) and coverage integration. Tests
run with strict install-mode semantics and do not inherit the host PATH unless
explicitly requested.
""", """,
attrs = { attrs = _BUN_TEST_ATTRS,
"srcs": attr.label_list(
mandatory = True,
allow_files = [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"],
doc = "Test source files passed to `bun test`.",
),
"node_modules": attr.label(
doc = "Optional label providing Bun/npm package files in runfiles.",
),
"deps": attr.label_list(
doc = "Library dependencies required by test sources.",
),
"data": attr.label_list(
allow_files = True,
doc = "Additional runtime files needed by tests.",
),
},
test = True, test = True,
toolchains = ["//bun:toolchain_type"], toolchains = ["//bun:toolchain_type"],
) )

29
internal/js_compat.bzl Normal file
View File

@@ -0,0 +1,29 @@
"""rules_js-style compatibility exports backed by Bun."""
load("//internal:bun_binary.bzl", _bun_binary = "bun_binary")
load("//internal:bun_test.bzl", _bun_test = "bun_test")
load("//internal:js_library.bzl", _JsInfo = "JsInfo", _js_library = "js_library", _ts_library = "ts_library")
load("//internal:js_run_devserver.bzl", _js_run_devserver = "js_run_devserver")
JsInfo = _JsInfo
js_library = _js_library
ts_library = _ts_library
js_run_devserver = _js_run_devserver
def js_binary(name, **kwargs):
_bun_binary(name = name, **kwargs)
def js_test(name, entry_point = None, srcs = None, **kwargs):
if entry_point != None:
if srcs != None:
fail("js_test accepts either `entry_point` or `srcs`, but not both")
srcs = [entry_point]
if srcs == None:
fail("js_test requires `entry_point` or `srcs`")
_bun_test(
name = name,
srcs = srcs,
**kwargs
)

View File

@@ -1,23 +1,74 @@
"""Lightweight JS/TS source grouping rules.""" """Lightweight JS/TS source grouping rules."""
JsInfo = provider(
doc = "Provides transitive JavaScript/TypeScript metadata for Bun and JS compatibility rules.",
fields = {
"sources": "Direct source files owned by this target.",
"transitive_sources": "Transitive source files from this target and its deps.",
"types": "Direct type files owned by this target.",
"transitive_types": "Transitive type files from this target and its deps.",
"data_files": "Direct runtime data files owned by this target.",
"transitive_runfiles": "Transitive runtime files from this target and its deps.",
},
)
BunSourcesInfo = provider( BunSourcesInfo = provider(
"Provides transitive sources for Bun libraries.", "Provides transitive sources for Bun libraries.",
fields = ["transitive_sources"], fields = ["transitive_sources"],
) )
def collect_js_sources(dep):
if JsInfo in dep:
return dep[JsInfo].transitive_sources
if BunSourcesInfo in dep:
return dep[BunSourcesInfo].transitive_sources
return dep[DefaultInfo].files
def collect_js_runfiles(dep):
if JsInfo in dep:
return dep[JsInfo].transitive_runfiles
if BunSourcesInfo in dep:
return dep[BunSourcesInfo].transitive_sources
return dep[DefaultInfo].files
def _bun_library_impl(ctx): def _bun_library_impl(ctx):
transitive_sources = [ transitive_sources = [collect_js_sources(dep) for dep in ctx.attr.deps]
dep[BunSourcesInfo].transitive_sources transitive_types = [
dep[JsInfo].transitive_types
for dep in ctx.attr.deps for dep in ctx.attr.deps
if BunSourcesInfo in dep if JsInfo in dep
] ]
transitive_runfiles = [collect_js_runfiles(dep) for dep in ctx.attr.deps]
all_sources = depset( all_sources = depset(
direct = ctx.files.srcs, direct = ctx.files.srcs,
transitive = transitive_sources, transitive = transitive_sources,
) )
all_types = depset(
direct = ctx.files.types,
transitive = transitive_types,
)
all_runfiles = depset(
direct = ctx.files.srcs + ctx.files.types + ctx.files.data,
transitive = transitive_runfiles,
)
default_files = depset(
direct = ctx.files.srcs + ctx.files.types + ctx.files.data,
transitive = transitive_sources + transitive_types + transitive_runfiles,
)
js_info = JsInfo(
sources = depset(ctx.files.srcs),
transitive_sources = all_sources,
types = depset(ctx.files.types),
transitive_types = all_types,
data_files = depset(ctx.files.data),
transitive_runfiles = all_runfiles,
)
return [ return [
js_info,
BunSourcesInfo(transitive_sources = all_sources), BunSourcesInfo(transitive_sources = all_sources),
DefaultInfo(files = all_sources), DefaultInfo(files = default_files),
] ]
js_library = rule( js_library = rule(
@@ -28,6 +79,14 @@ js_library = rule(
allow_files = [".js", ".jsx", ".mjs", ".cjs"], allow_files = [".js", ".jsx", ".mjs", ".cjs"],
doc = "JavaScript source files in this library.", doc = "JavaScript source files in this library.",
), ),
"types": attr.label_list(
allow_files = [".d.ts"],
doc = "Optional declaration files associated with this library.",
),
"data": attr.label_list(
allow_files = True,
doc = "Optional runtime files propagated to dependents.",
),
"deps": attr.label_list( "deps": attr.label_list(
doc = "Other Bun source libraries to include transitively.", doc = "Other Bun source libraries to include transitively.",
), ),
@@ -42,6 +101,14 @@ ts_library = rule(
allow_files = [".ts", ".tsx"], allow_files = [".ts", ".tsx"],
doc = "TypeScript source files in this library.", doc = "TypeScript source files in this library.",
), ),
"types": attr.label_list(
allow_files = [".d.ts"],
doc = "Optional declaration files associated with this library.",
),
"data": attr.label_list(
allow_files = True,
doc = "Optional runtime files propagated to dependents.",
),
"deps": attr.label_list( "deps": attr.label_list(
doc = "Other Bun source libraries to include transitively.", doc = "Other Bun source libraries to include transitively.",
), ),

View File

@@ -0,0 +1,111 @@
"""Compatibility rule for running an executable target as a dev server."""
load("//internal:js_library.bzl", "collect_js_runfiles")
load("//internal:runtime_launcher.bzl", "declare_runtime_wrapper", "runfiles_path", "runtime_launcher_attrs", "write_launcher_spec")
load("//internal:workspace.bzl", "create_bun_workspace_info", "workspace_runfiles")
def _js_run_devserver_impl(ctx):
toolchain = ctx.toolchains["//bun:toolchain_type"]
bun_bin = toolchain.bun.bun_bin
package_json = ctx.file.package_json
dep_runfiles = [collect_js_runfiles(dep) for dep in ctx.attr.deps]
tool_default_info = ctx.attr.tool[DefaultInfo]
workspace_info = create_bun_workspace_info(
ctx,
primary_file = package_json or tool_default_info.files_to_run.executable,
package_json = package_json,
package_dir_hint = ctx.attr.package_dir_hint,
extra_files = ctx.files.data + [bun_bin, tool_default_info.files_to_run.executable],
)
spec_file = write_launcher_spec(ctx, {
"version": 1,
"kind": "tool_exec",
"bun_short_path": runfiles_path(bun_bin),
"primary_source_short_path": runfiles_path(package_json) if package_json else runfiles_path(tool_default_info.files_to_run.executable),
"package_json_short_path": runfiles_path(package_json) if package_json else "",
"install_metadata_short_path": runfiles_path(workspace_info.install_metadata_file) if workspace_info.install_metadata_file else "",
"install_repo_runfiles_path": workspace_info.install_repo_runfiles_path,
"node_modules_roots": workspace_info.node_modules_roots,
"package_dir_hint": ctx.attr.package_dir_hint,
"working_dir_mode": ctx.attr.working_dir,
"inherit_host_path": ctx.attr.inherit_host_path,
"argv": [],
"args": ctx.attr.args,
"passthrough_args": True,
"tool_short_path": runfiles_path(tool_default_info.files_to_run.executable),
"restart_on": [],
"watch_mode": "",
"reporter": "",
"coverage": False,
"coverage_reporters": [],
"preload_short_paths": [],
"env_file_short_paths": [],
"test_short_paths": [],
})
launcher = declare_runtime_wrapper(ctx, bun_bin, spec_file)
return [
workspace_info,
DefaultInfo(
executable = launcher.executable,
runfiles = workspace_runfiles(
ctx,
workspace_info,
direct_files = [launcher.executable, launcher.runner, spec_file, tool_default_info.files_to_run.executable],
transitive_files = dep_runfiles,
).merge(tool_default_info.default_runfiles),
),
]
_JS_RUN_DEVSERVER_ATTRS = runtime_launcher_attrs()
_JS_RUN_DEVSERVER_ATTRS.update({
"tool": attr.label(
mandatory = True,
executable = True,
cfg = "target",
doc = "Executable target to launch as the dev server.",
),
"package_json": attr.label(
allow_single_file = True,
doc = "Optional package.json used to resolve the package working directory.",
),
"package_dir_hint": attr.string(
default = ".",
doc = "Optional package-relative directory hint when package_json is not supplied.",
),
"node_modules": attr.label(
doc = "Optional label providing package files from a node_modules tree, typically produced by bun_install or npm_translate_lock, in runfiles.",
),
"deps": attr.label_list(
doc = "Library dependencies required by the dev server.",
),
"data": attr.label_list(
allow_files = True,
doc = "Additional runtime files required by the dev server.",
),
"working_dir": attr.string(
default = "workspace",
values = ["workspace", "package"],
doc = "Working directory at runtime: Bazel runfiles workspace root or the resolved package directory.",
),
"inherit_host_path": attr.bool(
default = False,
doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
),
})
js_run_devserver = rule(
implementation = _js_run_devserver_impl,
doc = """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. It is intended for local
development workflows rather than hermetic build execution.
""",
attrs = _JS_RUN_DEVSERVER_ATTRS,
executable = True,
toolchains = ["//bun:toolchain_type"],
)

View File

@@ -0,0 +1,173 @@
"""Shared launcher spec and OS-native wrapper helpers for runtime rules."""
_RUNTIME_LAUNCHER = Label("//internal:runtime_launcher.js")
_WINDOWS_CONSTRAINT = Label("@platforms//os:windows")
_POSIX_WRAPPER_TEMPLATE = """#!/bin/sh
set -eu
self="$0"
runfiles_dir="${RUNFILES_DIR:-}"
manifest="${RUNFILES_MANIFEST_FILE:-}"
if [ -n "${runfiles_dir}" ] && [ -d "${runfiles_dir}" ]; then
:
elif [ -n "${manifest}" ] && [ -f "${manifest}" ]; then
:
elif [ -d "${self}.runfiles" ]; then
runfiles_dir="${self}.runfiles"
elif [ -f "${self}.runfiles_manifest" ]; then
manifest="${self}.runfiles_manifest"
elif [ -f "${self}.exe.runfiles_manifest" ]; then
manifest="${self}.exe.runfiles_manifest"
else
echo "rules_bun: unable to locate runfiles for ${self}" >&2
exit 1
fi
rlocation() {
path="$1"
if [ -n "${runfiles_dir}" ]; then
printf '%s\\n' "${runfiles_dir}/${path}"
return 0
fi
result=""
while IFS= read -r line; do
case "${line}" in
"${path} "*)
result="${line#${path} }"
break
;;
esac
done < "${manifest}"
if [ -z "${result}" ]; then
echo "rules_bun: missing runfile ${path}" >&2
exit 1
fi
printf '%s\\n' "${result}"
}
bun_bin="$(rlocation "__BUN_RUNFILES_PATH__")"
runner="$(rlocation "__RUNNER_RUNFILES_PATH__")"
spec="$(rlocation "__SPEC_RUNFILES_PATH__")"
export RULES_BUN_LAUNCHER_PATH="${self}"
if [ -n "${runfiles_dir}" ]; then
export RULES_BUN_RUNFILES_DIR="${runfiles_dir}"
fi
if [ -n "${manifest}" ]; then
export RULES_BUN_RUNFILES_MANIFEST="${manifest}"
fi
exec "${bun_bin}" --bun "${runner}" "${spec}" "$@"
"""
_CMD_WRAPPER_TEMPLATE = """@echo off
setlocal
set "SELF=%~f0"
set "RUNFILES_DIR_VALUE=%RUNFILES_DIR%"
set "RUNFILES_MANIFEST_VALUE=%RUNFILES_MANIFEST_FILE%"
if defined RUNFILES_DIR_VALUE if exist "%RUNFILES_DIR_VALUE%" goto have_runfiles
if defined RUNFILES_MANIFEST_VALUE if exist "%RUNFILES_MANIFEST_VALUE%" goto have_runfiles
if exist "%SELF%.runfiles" (
set "RUNFILES_DIR_VALUE=%SELF%.runfiles"
goto have_runfiles
)
if exist "%SELF%.runfiles_manifest" (
set "RUNFILES_MANIFEST_VALUE=%SELF%.runfiles_manifest"
goto have_runfiles
)
if exist "%~dpn0.runfiles_manifest" (
set "RUNFILES_MANIFEST_VALUE=%~dpn0.runfiles_manifest"
goto have_runfiles
)
echo rules_bun: unable to locate runfiles for "%SELF%" 1>&2
exit /b 1
:have_runfiles
call :rlocation "__BUN_RUNFILES_PATH__" BUN_BIN || exit /b 1
call :rlocation "__RUNNER_RUNFILES_PATH__" RUNNER || exit /b 1
call :rlocation "__SPEC_RUNFILES_PATH__" SPEC || exit /b 1
set "RULES_BUN_LAUNCHER_PATH=%SELF%"
if defined RUNFILES_DIR_VALUE (
set "RULES_BUN_RUNFILES_DIR=%RUNFILES_DIR_VALUE%"
) else (
set "RULES_BUN_RUNFILES_DIR="
)
if defined RUNFILES_MANIFEST_VALUE (
set "RULES_BUN_RUNFILES_MANIFEST=%RUNFILES_MANIFEST_VALUE%"
) else (
set "RULES_BUN_RUNFILES_MANIFEST="
)
"%BUN_BIN%" --bun "%RUNNER%" "%SPEC%" %*
exit /b %ERRORLEVEL%
:rlocation
set "LOOKUP=%~1"
set "OUTPUT_VAR=%~2"
if defined RUNFILES_DIR_VALUE (
set "%OUTPUT_VAR%=%RUNFILES_DIR_VALUE%\\%LOOKUP:/=\\%"
exit /b 0
)
for /f "tokens=1,* delims= " %%A in ('findstr /b /c:"%LOOKUP% " "%RUNFILES_MANIFEST_VALUE%"') do (
set "%OUTPUT_VAR%=%%B"
exit /b 0
)
echo rules_bun: missing runfile %LOOKUP% 1>&2
exit /b 1
"""
def runfiles_path(file):
workspace_name = file.owner.workspace_name
if workspace_name:
return "{}/{}".format(workspace_name, file.short_path)
return "_main/{}".format(file.short_path)
def runtime_launcher_attrs():
return {
"_runtime_launcher": attr.label(
default = _RUNTIME_LAUNCHER,
allow_single_file = True,
),
"_windows_constraint": attr.label(
default = _WINDOWS_CONSTRAINT,
),
}
def is_windows_target(ctx):
return ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo])
def write_launcher_spec(ctx, spec):
spec_file = ctx.actions.declare_file(ctx.label.name + ".launcher.json")
ctx.actions.write(
output = spec_file,
content = json.encode(spec) + "\n",
)
return spec_file
def declare_runtime_wrapper(ctx, bun_bin, spec_file):
runner = ctx.file._runtime_launcher
wrapper = ctx.actions.declare_file(ctx.label.name + (".cmd" if is_windows_target(ctx) else ""))
content = _CMD_WRAPPER_TEMPLATE if is_windows_target(ctx) else _POSIX_WRAPPER_TEMPLATE
content = content.replace("__BUN_RUNFILES_PATH__", runfiles_path(bun_bin)).replace(
"__RUNNER_RUNFILES_PATH__",
runfiles_path(runner),
).replace(
"__SPEC_RUNFILES_PATH__",
runfiles_path(spec_file),
)
ctx.actions.write(
output = wrapper,
content = content,
is_executable = True,
)
return struct(
executable = wrapper,
runner = runner,
)

1199
internal/runtime_launcher.js Normal file

File diff suppressed because it is too large Load Diff

113
internal/workspace.bzl Normal file
View File

@@ -0,0 +1,113 @@
"""Shared Bun workspace metadata helpers."""
BunWorkspaceInfo = provider(
doc = "Workspace/runtime metadata shared by Bun rules and adapters.",
fields = {
"install_metadata_file": "Optional install metadata file from bun_install.",
"install_repo_runfiles_path": "Runfiles root for the node_modules repository when present.",
"metadata_file": "Rule-local metadata file describing the staged workspace inputs.",
"node_modules_files": "Depset of node_modules files from bun_install.",
"node_modules_roots": "Sorted repo-relative node_modules roots available in runfiles.",
"package_dir_hint": "Package-relative directory when known at analysis time.",
"package_json": "Package manifest file when explicitly provided.",
"primary_file": "Primary source file used to resolve the runtime package context.",
"runtime_files": "Depset of runtime files required to stage the workspace.",
},
)
def find_install_metadata_file(files):
for file in files:
if file.short_path.endswith("node_modules/.rules_bun/install.json"):
return file
return None
def _runfiles_workspace(file):
workspace_name = file.owner.workspace_name
if workspace_name:
return workspace_name
return "_main"
def _repo_relative_short_path(file):
short_path = file.short_path.replace("\\", "/")
workspace_name = _runfiles_workspace(file)
external_prefix = "../{}/".format(workspace_name)
if short_path.startswith(external_prefix):
return short_path[len(external_prefix):]
if short_path == "../{}".format(workspace_name):
return "."
return short_path
def resolve_node_modules_roots(files):
roots = {}
marker = "/node_modules/"
for file in files:
short_path = _repo_relative_short_path(file)
if short_path == "node_modules" or short_path.startswith("node_modules/"):
roots["node_modules"] = True
marker_index = short_path.find(marker)
if marker_index >= 0:
roots[short_path[:marker_index + len("/node_modules")]] = True
return sorted(roots.keys())
def create_bun_workspace_info(ctx, primary_file = None, package_json = None, package_dir_hint = ".", extra_files = None):
direct_runtime_files = []
if primary_file:
direct_runtime_files.append(primary_file)
if package_json and package_json != primary_file:
direct_runtime_files.append(package_json)
direct_runtime_files.extend(extra_files or [])
node_modules_files = depset()
install_metadata_file = None
install_repo_runfiles_path = ""
node_modules_roots = []
if getattr(ctx.attr, "node_modules", None):
node_modules_files = ctx.attr.node_modules[DefaultInfo].files
node_modules_file_list = node_modules_files.to_list()
install_metadata_file = find_install_metadata_file(node_modules_file_list)
node_modules_roots = resolve_node_modules_roots(node_modules_file_list)
if install_metadata_file:
install_repo_runfiles_path = _runfiles_workspace(install_metadata_file)
elif node_modules_file_list:
install_repo_runfiles_path = _runfiles_workspace(node_modules_file_list[0])
metadata_file = ctx.actions.declare_file(ctx.label.name + ".bun_workspace.json")
ctx.actions.write(
output = metadata_file,
content = json.encode({
"install_metadata": install_metadata_file.short_path if install_metadata_file else "",
"install_repo_runfiles_path": install_repo_runfiles_path,
"node_modules_roots": node_modules_roots,
"package_dir_hint": package_dir_hint or ".",
"package_json": package_json.short_path if package_json else "",
"primary_file": primary_file.short_path if primary_file else "",
}) + "\n",
)
direct_runtime_files.append(metadata_file)
runtime_files = depset(
direct = direct_runtime_files,
transitive = [node_modules_files],
)
return BunWorkspaceInfo(
install_metadata_file = install_metadata_file,
install_repo_runfiles_path = install_repo_runfiles_path,
metadata_file = metadata_file,
node_modules_files = node_modules_files,
node_modules_roots = node_modules_roots,
package_dir_hint = package_dir_hint or ".",
package_json = package_json,
primary_file = primary_file,
runtime_files = runtime_files,
)
def workspace_runfiles(ctx, workspace_info, direct_files = None, transitive_files = None):
return ctx.runfiles(
files = direct_files or [],
transitive_files = depset(
transitive = [workspace_info.runtime_files] + (transitive_files or []),
),
)

21
js/BUILD.bazel Normal file
View File

@@ -0,0 +1,21 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
package(default_visibility = ["//visibility:public"])
exports_files(["defs.bzl"])
filegroup(
name = "repo_runtime_files",
srcs = [
"BUILD.bazel",
"defs.bzl",
],
visibility = ["//visibility:public"],
)
bzl_library(
name = "defs_bzl",
srcs = ["defs.bzl"],
visibility = ["//visibility:public"],
deps = ["//internal:js_compat_bzl"],
)

12
js/defs.bzl Normal file
View File

@@ -0,0 +1,12 @@
"""rules_js-style public API backed by Bun."""
load("//internal:js_compat.bzl", _JsInfo = "JsInfo", _js_binary = "js_binary", _js_library = "js_library", _js_run_devserver = "js_run_devserver", _js_test = "js_test", _ts_library = "ts_library")
visibility("public")
JsInfo = _JsInfo
js_binary = _js_binary
js_test = _js_test
js_run_devserver = _js_run_devserver
js_library = _js_library
ts_library = _ts_library

32
npm/BUILD.bazel Normal file
View File

@@ -0,0 +1,32 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
package(default_visibility = ["//visibility:public"])
exports_files([
"extensions.bzl",
"repositories.bzl",
])
filegroup(
name = "repo_runtime_files",
srcs = [
"BUILD.bazel",
"extensions.bzl",
"repositories.bzl",
],
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"],
deps = ["//internal:bun_install_bzl"],
)

28
npm/extensions.bzl Normal file
View File

@@ -0,0 +1,28 @@
load("//internal:bun_install.bzl", "bun_install_repository")
_translate = tag_class(
attrs = {
"name": attr.string(mandatory = True),
"package_json": attr.label(mandatory = True),
"lockfile": attr.label(mandatory = True),
"install_inputs": attr.label_list(allow_files = True),
"isolated_home": attr.bool(default = True),
},
)
def _npm_translate_lock_impl(ctx):
for mod in ctx.modules:
for install in mod.tags.translate:
bun_install_repository(
name = install.name,
package_json = install.package_json,
bun_lockfile = install.lockfile,
install_inputs = install.install_inputs,
isolated_home = install.isolated_home,
visible_repo_name = install.name,
)
npm_translate_lock = module_extension(
implementation = _npm_translate_lock_impl,
tag_classes = {"translate": _translate},
)

11
npm/repositories.bzl Normal file
View File

@@ -0,0 +1,11 @@
load("//internal:bun_install.bzl", "bun_install_repository")
def npm_translate_lock(name, package_json, lockfile, install_inputs = [], isolated_home = True):
bun_install_repository(
name = name,
package_json = package_json,
bun_lockfile = lockfile,
install_inputs = install_inputs,
isolated_home = isolated_home,
visible_repo_name = name,
)

1
result
View File

@@ -1 +0,0 @@
/nix/store/742k6q4hns9h1wj61y90glqwfmn2y7pa-release

View File

@@ -1 +1,3 @@
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
exports_files(["nested_bazel_test.sh"])

1
tests/binary_test/.env Normal file
View File

@@ -0,0 +1 @@
BUN_ENV_CWD_TEST=from-dotenv

View File

@@ -1,5 +1,5 @@
load("//bun:defs.bzl", "bun_binary")
load("@rules_shell//shell:sh_test.bzl", "sh_test") load("@rules_shell//shell:sh_test.bzl", "sh_test")
load("//bun:defs.bzl", "bun_binary")
bun_binary( bun_binary(
name = "hello_js_bin", name = "hello_js_bin",
@@ -8,8 +8,12 @@ bun_binary(
sh_test( sh_test(
name = "bun_binary_js_test", name = "bun_binary_js_test",
size = "small",
srcs = ["run_binary.sh"], srcs = ["run_binary.sh"],
args = ["$(location :hello_js_bin)", "hello-js"], args = [
"$(location :hello_js_bin)",
"hello-js",
],
data = [":hello_js_bin"], data = [":hello_js_bin"],
) )
@@ -20,19 +24,24 @@ bun_binary(
sh_test( sh_test(
name = "bun_binary_ts_test", name = "bun_binary_ts_test",
size = "small",
srcs = ["run_binary.sh"], srcs = ["run_binary.sh"],
args = ["$(location :hello_ts_bin)", "hello-ts"], args = [
"$(location :hello_ts_bin)",
"hello-ts",
],
data = [":hello_ts_bin"], data = [":hello_ts_bin"],
) )
bun_binary( bun_binary(
name = "hello_js_with_data_bin", name = "hello_js_with_data_bin",
entry_point = "hello.js",
data = ["payload.txt"], data = ["payload.txt"],
entry_point = "hello.js",
) )
sh_test( sh_test(
name = "bun_binary_data_test", name = "bun_binary_data_test",
size = "small",
srcs = ["verify_data_shape.sh"], srcs = ["verify_data_shape.sh"],
args = [ args = [
"$(location //internal:bun_binary.bzl)", "$(location //internal:bun_binary.bzl)",
@@ -46,13 +55,14 @@ sh_test(
bun_binary( bun_binary(
name = "env_cwd_bin", name = "env_cwd_bin",
entry_point = "env.ts",
data = [".env"], data = [".env"],
entry_point = "env.ts",
working_dir = "entry_point", working_dir = "entry_point",
) )
sh_test( sh_test(
name = "bun_binary_env_cwd_test", name = "bun_binary_env_cwd_test",
size = "small",
srcs = ["run_env_binary.sh"], srcs = ["run_env_binary.sh"],
args = ["$(location :env_cwd_bin)"], args = ["$(location :env_cwd_bin)"],
data = [":env_cwd_bin"], data = [":env_cwd_bin"],
@@ -60,14 +70,94 @@ sh_test(
bun_binary( bun_binary(
name = "env_parent_cwd_bin", name = "env_parent_cwd_bin",
entry_point = "env_parent/src/main.ts",
data = ["env_parent/.env"], data = ["env_parent/.env"],
entry_point = "env_parent/src/main.ts",
working_dir = "entry_point", working_dir = "entry_point",
) )
sh_test( sh_test(
name = "bun_binary_env_parent_cwd_test", name = "bun_binary_env_parent_cwd_test",
size = "small",
srcs = ["run_parent_env_binary.sh"], srcs = ["run_parent_env_binary.sh"],
args = ["$(location :env_parent_cwd_bin)"], args = ["$(location :env_parent_cwd_bin)"],
data = [":env_parent_cwd_bin"], data = [":env_parent_cwd_bin"],
) )
bun_binary(
name = "runtime_flag_bin",
args = [
"one",
"two",
],
entry_point = "flag_probe.ts",
env_files = ["runtime.env"],
preload = ["preload.ts"],
)
sh_test(
name = "bun_binary_runtime_flags_test",
size = "small",
srcs = ["run_flag_binary.sh"],
args = ["$(location :runtime_flag_bin)"],
data = [":runtime_flag_bin"],
)
sh_test(
name = "bun_binary_runtime_flags_shape_test",
size = "small",
srcs = ["verify_runtime_flags_shape.sh"],
args = ["$(location :runtime_flag_bin)"],
data = [":runtime_flag_bin"],
)
bun_binary(
name = "configured_launcher_bin",
conditions = [
"browser",
"development",
],
entry_point = "hello.ts",
inherit_host_path = True,
install_mode = "force",
node_modules = "@script_test_vite_node_modules//:node_modules",
run_flags = [
"--hot",
"--console-depth",
"4",
],
smol = True,
visibility = ["//tests/ci_test:__pkg__"],
)
sh_test(
name = "bun_binary_configured_launcher_shape_test",
size = "small",
srcs = ["verify_configured_launcher_shape.sh"],
args = ["$(location :configured_launcher_bin)"],
data = [":configured_launcher_bin"],
)
bun_binary(
name = "path_default_bin",
entry_point = "path_probe.ts",
)
bun_binary(
name = "path_inherit_bin",
entry_point = "path_probe.ts",
inherit_host_path = True,
)
sh_test(
name = "bun_binary_host_path_test",
size = "small",
srcs = ["run_path_binary.sh"],
args = [
"$(location :path_default_bin)",
"$(location :path_inherit_bin)",
],
data = [
":path_default_bin",
":path_inherit_bin",
],
)

View File

@@ -0,0 +1 @@
BUN_ENV_PARENT_TEST=from-parent-dotenv

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,5 @@
const pathValue = process.env.PATH ?? "";
console.log(JSON.stringify({
hasHostSentinel: pathValue.includes("rules_bun_host_path_sentinel"),
}));

View File

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

View File

@@ -3,9 +3,25 @@ set -euo pipefail
binary="$1" binary="$1"
expected="$2" expected="$2"
output="$(${binary})"
if [[ "${output}" != "${expected}" ]]; then run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
local command
printf -v command '"%s"' "${launcher}"
for arg in "$@"; do
printf -v command '%s "%s"' "${command}" "${arg}"
done
cmd.exe /c "${command}" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
}
output="$(run_launcher "${binary}")"
if [[ ${output} != "${expected}" ]]; then
echo "Unexpected output from ${binary}: ${output}" >&2 echo "Unexpected output from ${binary}: ${output}" >&2
exit 1 exit 1
fi fi

View File

@@ -2,7 +2,23 @@
set -euo pipefail set -euo pipefail
binary="$1" binary="$1"
output="$(${binary})"
run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
local command
printf -v command '"%s"' "${launcher}"
for arg in "$@"; do
printf -v command '%s "%s"' "${command}" "${arg}"
done
cmd.exe /c "${command}" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
}
output="$(run_launcher "${binary}")"
if [[ ${output} != "from-dotenv" ]]; then if [[ ${output} != "from-dotenv" ]]; then
echo "Expected .env value from entry-point directory, got: ${output}" >&2 echo "Expected .env value from entry-point directory, got: ${output}" >&2

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
binary="$1"
run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
local command
printf -v command '"%s"' "${launcher}"
for arg in "$@"; do
printf -v command '%s "%s"' "${command}" "${arg}"
done
cmd.exe /c "${command}" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
}
output="$(run_launcher "${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

@@ -2,7 +2,23 @@
set -euo pipefail set -euo pipefail
binary="$1" binary="$1"
output="$(${binary})"
run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
local command
printf -v command '"%s"' "${launcher}"
for arg in "$@"; do
printf -v command '%s "%s"' "${command}" "${arg}"
done
cmd.exe /c "${command}" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
}
output="$(run_launcher "${binary}")"
if [[ ${output} != "from-parent-dotenv" ]]; then if [[ ${output} != "from-parent-dotenv" ]]; then
echo "Expected .env value from parent directory, got: ${output}" >&2 echo "Expected .env value from parent directory, got: ${output}" >&2

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
default_binary="$1"
inherit_binary="$2"
run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
local command
printf -v command '"%s"' "${launcher}"
for arg in "$@"; do
printf -v command '%s "%s"' "${command}" "${arg}"
done
env PATH="rules_bun_host_path_sentinel:${PATH:-}" cmd.exe /c "${command}" | tr -d '\r'
return 0
fi
env PATH="rules_bun_host_path_sentinel:${PATH:-}" "${launcher}" "$@"
}
default_output="$(run_launcher "${default_binary}")"
inherit_output="$(run_launcher "${inherit_binary}")"
if [[ ${default_output} != '{"hasHostSentinel":false}' ]]; then
echo "Expected default launcher to hide host PATH, got: ${default_output}" >&2
exit 1
fi
if [[ ${inherit_output} != '{"hasHostSentinel":true}' ]]; then
echo "Expected inherit_host_path launcher to preserve host PATH, got: ${inherit_output}" >&2
exit 1
fi

View File

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

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
launcher="$1"
python3 - "${launcher}" <<'PY'
import json
import pathlib
import sys
path = pathlib.Path(sys.argv[1])
if path.suffix.lower() == ".cmd":
path = pathlib.Path(str(path)[:-4])
spec = json.loads(pathlib.Path(f"{path}.launcher.json").read_text())
argv = spec["argv"]
assert spec["install_metadata_short_path"].endswith("node_modules/.rules_bun/install.json"), spec
assert spec["inherit_host_path"] is True, spec
assert spec["node_modules_roots"], spec
assert all(not root.startswith("../") for root in spec["node_modules_roots"]), spec
for value in ["--smol", "--conditions", "browser", "development", "--install", "force", "--hot", "--console-depth", "4"]:
assert value in argv, (value, spec)
PY

View File

@@ -4,6 +4,6 @@ set -euo pipefail
rule_file="$1" rule_file="$1"
build_file="$2" build_file="$2"
grep -Eq 'files = \[bun_bin, entry_point\] \+ ctx\.files\.data' "${rule_file}" grep -Eq 'extra_files = ctx\.files\.data \+ ctx\.files\.preload \+ ctx\.files\.env_files \+ \[bun_bin\]' "${rule_file}"
grep -Eq 'name = "hello_js_with_data_bin"' "${build_file}" grep -Eq 'name = "hello_js_with_data_bin"' "${build_file}"
grep -Eq 'data = \["payload\.txt"\]' "${build_file}" grep -Eq 'data = \["payload\.txt"\]' "${build_file}"

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
launcher="$1"
python3 - "${launcher}" <<'PY'
import json
import pathlib
import sys
path = pathlib.Path(sys.argv[1])
if path.suffix.lower() == ".cmd":
path = pathlib.Path(str(path)[:-4])
spec = json.loads(pathlib.Path(f"{path}.launcher.json").read_text())
assert "--no-install" in spec["argv"], spec
assert spec["inherit_host_path"] is False, spec
assert spec["preload_short_paths"] and spec["preload_short_paths"][0].endswith("tests/binary_test/preload.ts"), spec
assert spec["env_file_short_paths"] and spec["env_file_short_paths"][0].endswith("tests/binary_test/runtime.env"), spec
PY

View File

@@ -3,16 +3,62 @@ load("//bun:defs.bzl", "bun_test")
bun_test( bun_test(
name = "passing_suite", name = "passing_suite",
size = "small",
srcs = ["passing.test.ts"], srcs = ["passing.test.ts"],
) )
bun_test( bun_test(
name = "failing_suite", name = "failing_suite",
size = "small",
srcs = ["failing.test.ts"], srcs = ["failing.test.ts"],
) )
bun_test(
name = "configured_suite",
size = "small",
srcs = ["passing.test.ts"],
bail = 1,
concurrent = True,
coverage = True,
coverage_reporters = ["lcov"],
env_files = ["test.env"],
max_concurrency = 4,
no_env_file = True,
preload = ["preload.ts"],
randomize = True,
reporter = "junit",
rerun_each = 2,
seed = 7,
test_flags = ["--only-failures"],
timeout_ms = 250,
update_snapshots = True,
visibility = ["//tests/ci_test:__pkg__"],
)
bun_test(
name = "configured_retry_suite",
size = "small",
srcs = ["passing.test.ts"],
retry = 3,
)
sh_test(
name = "bun_test_configured_suite_shape_test",
size = "small",
srcs = ["configured_suite_shape.sh"],
args = [
"$(location :configured_suite)",
"$(location :configured_retry_suite)",
],
data = [
":configured_retry_suite",
":configured_suite",
],
)
sh_test( sh_test(
name = "bun_test_failing_suite_test", name = "bun_test_failing_suite_test",
size = "small",
srcs = ["failing_suite_shape.sh"], srcs = ["failing_suite_shape.sh"],
args = ["$(location //tests/bun_test_test:BUILD.bazel)"], args = ["$(location //tests/bun_test_test:BUILD.bazel)"],
data = ["//tests/bun_test_test:BUILD.bazel"], data = ["//tests/bun_test_test:BUILD.bazel"],
@@ -20,21 +66,24 @@ sh_test(
sh_test( sh_test(
name = "bun_test_cache_hit_test", name = "bun_test_cache_hit_test",
size = "small",
srcs = ["cache_hit_shape.sh"], srcs = ["cache_hit_shape.sh"],
args = ["$(location //internal:bun_test.bzl)"], args = ["$(location :passing_suite)"],
data = ["//internal:bun_test.bzl"], data = [":passing_suite"],
) )
sh_test( sh_test(
name = "bun_test_cache_miss_test", name = "bun_test_cache_miss_test",
size = "small",
srcs = ["cache_miss_shape.sh"], srcs = ["cache_miss_shape.sh"],
args = ["$(location //internal:bun_test.bzl)"], args = ["$(location :configured_suite)"],
data = ["//internal:bun_test.bzl"], data = [":configured_suite"],
) )
sh_test( sh_test(
name = "bun_test_junit_output_test", name = "bun_test_junit_output_test",
size = "small",
srcs = ["junit_shape.sh"], srcs = ["junit_shape.sh"],
args = ["$(location //internal:bun_test.bzl)"], args = ["$(location :configured_suite)"],
data = ["//internal:bun_test.bzl"], data = [":configured_suite"],
) )

View File

@@ -1,8 +1,19 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
rule_file="$1" launcher="$1"
grep -Fq 'set -euo pipefail' "${rule_file}" python3 - "${launcher}" <<'PY'
grep -Fq 'src_args = " ".join([_shell_quote(src.short_path) for src in ctx.files.srcs])' "${rule_file}" import json
grep -Fq 'exec "${{bun_bin}}" test {src_args} "$@"' "${rule_file}" import pathlib
import sys
path = pathlib.Path(sys.argv[1])
if path.suffix.lower() == ".cmd":
path = pathlib.Path(str(path)[:-4])
spec = json.loads(pathlib.Path(f"{path}.launcher.json").read_text())
assert spec["kind"] == "bun_test", spec
assert spec["argv"][:2] == ["--bun", "test"], spec
assert spec["test_short_paths"], spec
PY

View File

@@ -1,7 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
rule_file="$1" launcher="$1"
grep -Eq 'files = \[bun_bin\] \+ ctx\.files\.srcs \+ ctx\.files\.data' "${rule_file}" python3 - "${launcher}" <<'PY'
grep -Eq '"srcs": attr\.label_list\(' "${rule_file}" import json
import pathlib
import sys
path = pathlib.Path(sys.argv[1])
if path.suffix.lower() == ".cmd":
path = pathlib.Path(str(path)[:-4])
spec = json.loads(pathlib.Path(f"{path}.launcher.json").read_text())
assert spec["coverage"] is True, spec
assert spec["preload_short_paths"], spec
assert spec["env_file_short_paths"], spec
assert spec["test_short_paths"], spec
PY

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env bash
set -euo pipefail
launcher="$1"
retry_launcher="$2"
python3 - "${launcher}" "${retry_launcher}" <<'PY'
import json
import pathlib
import sys
def read_spec(launcher: str):
path = pathlib.Path(launcher)
if path.suffix.lower() == ".cmd":
path = pathlib.Path(str(path)[:-4])
return json.loads(pathlib.Path(f"{path}.launcher.json").read_text())
launcher_spec = read_spec(sys.argv[1])
retry_spec = read_spec(sys.argv[2])
for value in [
"--no-install",
"--no-env-file",
"--timeout",
"--update-snapshots",
"--rerun-each",
"--concurrent",
"--randomize",
"--seed",
"--bail",
"--max-concurrency",
]:
assert value in launcher_spec["argv"], (value, launcher_spec)
assert launcher_spec["preload_short_paths"], launcher_spec
assert launcher_spec["env_file_short_paths"], launcher_spec
assert launcher_spec["reporter"] == "junit", launcher_spec
assert launcher_spec["coverage"] is True, launcher_spec
assert launcher_spec["coverage_reporters"] == ["lcov"], launcher_spec
assert "--retry" in retry_spec["argv"], retry_spec
assert "3" in retry_spec["argv"], retry_spec
PY

View File

@@ -1,7 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
rule_file="$1" launcher="$1"
grep -Fq 'exec "${{bun_bin}}" test {src_args} --test-name-pattern "${{TESTBRIDGE_TEST_ONLY}}" "$@"' "${rule_file}" python3 - "${launcher}" <<'PY'
grep -Fq 'if [[ -n "${{TESTBRIDGE_TEST_ONLY:-}}" ]]' "${rule_file}" import json
import pathlib
import sys
path = pathlib.Path(sys.argv[1])
if path.suffix.lower() == ".cmd":
path = pathlib.Path(str(path)[:-4])
spec = json.loads(pathlib.Path(f"{path}.launcher.json").read_text())
assert spec["reporter"] == "junit", spec
PY

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,5 +1,5 @@
load("//bun:defs.bzl", "bun_bundle")
load("@rules_shell//shell:sh_test.bzl", "sh_test") load("@rules_shell//shell:sh_test.bzl", "sh_test")
load("//bun:defs.bzl", "bun_build", "bun_bundle", "bun_compile")
bun_bundle( bun_bundle(
name = "simple_bundle", name = "simple_bundle",
@@ -18,8 +18,132 @@ bun_bundle(
external = ["left-pad"], external = ["left-pad"],
) )
bun_bundle(
name = "collision_bundle",
entry_points = [
"collision_case/a/main.ts",
"collision_case/b/main.ts",
],
)
bun_build(
name = "site_build",
data = [
"site/main.ts",
"site/styles.css",
],
entry_points = ["site/index.html"],
splitting = True,
)
bun_build(
name = "site_build_with_meta",
data = [
"site/main.ts",
"site/styles.css",
],
entry_points = ["site/index.html"],
metafile = True,
metafile_md = True,
)
bun_build(
name = "advanced_site_build",
asset_naming = "assets/[name]-[hash].[ext]",
banner = "/* bundle banner */",
build_flags = [
"--app",
"--server-components",
],
chunk_naming = "chunks/[name]-[hash].[ext]",
conditions = [
"browser",
"custom",
],
css_chunking = True,
data = [
"site/main.ts",
"site/styles.css",
],
define = [
"process.env.NODE_ENV:\"production\"",
"__DEV__:false",
],
drop = [
"console",
"debugger",
],
emit_dce_annotations = True,
entry_naming = "entries/[name]-[hash].[ext]",
entry_points = ["site/index.html"],
env = "PUBLIC_*",
external = [
"left-pad",
"react",
],
feature = [
"react_fast_refresh",
"server_components",
],
footer = "// bundle footer",
format = "cjs",
jsx_factory = "h",
jsx_fragment = "Fragment",
jsx_import_source = "preact",
jsx_runtime = "automatic",
jsx_side_effects = True,
keep_names = True,
loader = [
".svg:file",
".txt:text",
],
minify = True,
minify_identifiers = True,
minify_syntax = True,
minify_whitespace = True,
no_bundle = True,
packages = "external",
production = True,
public_path = "/static/",
react_fast_refresh = True,
root = "tests/bundle_test/site",
sourcemap = "linked",
splitting = True,
tags = ["manual"],
target = "node",
)
bun_compile(
name = "compiled_cli",
entry_point = "cli.ts",
)
bun_compile(
name = "compiled_cli_with_flags",
bytecode = True,
compile_autoload_bunfig = False,
compile_autoload_dotenv = False,
compile_autoload_package_json = True,
compile_autoload_tsconfig = True,
compile_exec_argv = [
"--smol",
"--inspect-wait",
],
compile_executable = "fake_cross_bun.bin",
entry_point = "cli.ts",
tags = ["manual"],
windows_copyright = "(c) rules_bun",
windows_description = "compile flag coverage",
windows_hide_console = True,
windows_icon = "branding/icon.ico",
windows_publisher = "rules_bun",
windows_title = "Rules Bun Test App",
windows_version = "1.2.3.4",
)
sh_test( sh_test(
name = "bundle_output_test", name = "bundle_output_test",
size = "small",
srcs = ["verify_bundle.sh"], srcs = ["verify_bundle.sh"],
args = ["$(location :simple_bundle)"], args = ["$(location :simple_bundle)"],
data = [":simple_bundle"], data = [":simple_bundle"],
@@ -27,19 +151,21 @@ sh_test(
sh_test( sh_test(
name = "bundle_minify_test", name = "bundle_minify_test",
size = "small",
srcs = ["verify_minify.sh"], srcs = ["verify_minify.sh"],
args = [ args = [
"$(location :simple_bundle)", "$(location :simple_bundle)",
"$(location :minified_bundle)", "$(location :minified_bundle)",
], ],
data = [ data = [
":simple_bundle",
":minified_bundle", ":minified_bundle",
":simple_bundle",
], ],
) )
sh_test( sh_test(
name = "bundle_hermetic_digest_test", name = "bundle_hermetic_digest_test",
size = "small",
srcs = ["verify_hermetic_shape.sh"], srcs = ["verify_hermetic_shape.sh"],
args = ["$(location //internal:bun_bundle.bzl)"], args = ["$(location //internal:bun_bundle.bzl)"],
data = ["//internal:bun_bundle.bzl"], data = ["//internal:bun_bundle.bzl"],
@@ -47,6 +173,7 @@ sh_test(
sh_test( sh_test(
name = "bundle_external_exclusion_test", name = "bundle_external_exclusion_test",
size = "small",
srcs = ["verify_external_shape.sh"], srcs = ["verify_external_shape.sh"],
args = [ args = [
"$(location //internal:bun_bundle.bzl)", "$(location //internal:bun_bundle.bzl)",
@@ -57,3 +184,78 @@ sh_test(
"//tests/bundle_test:BUILD.bazel", "//tests/bundle_test:BUILD.bazel",
], ],
) )
sh_test(
name = "bundle_collision_output_test",
size = "small",
srcs = ["verify_collision_outputs.sh"],
args = ["$(locations :collision_bundle)"],
data = [":collision_bundle"],
)
sh_test(
name = "bundle_sourcemap_shape_test",
size = "small",
srcs = ["verify_sourcemap_shape.sh"],
tags = [
"exclusive",
"no-sandbox",
],
data = [
"BUILD.bazel",
"//:repo_runtime_files",
"//bun:repo_runtime_files",
"//internal:repo_runtime_files",
"//tests:nested_bazel_test.sh",
"//tests/bundle_test/sourcemap_case:BUILD.bazel",
"//tests/bundle_test/sourcemap_case:entry.ts",
],
env_inherit = ["PATH"],
)
sh_test(
name = "bun_build_site_output_test",
size = "small",
srcs = ["verify_site_build.sh"],
args = ["$(location :site_build)"],
data = [":site_build"],
)
sh_test(
name = "bun_build_site_meta_test",
size = "small",
srcs = ["verify_site_build_meta.sh"],
args = ["$(locations :site_build_with_meta)"],
data = [":site_build_with_meta"],
)
sh_test(
name = "bun_compile_output_test",
size = "small",
srcs = ["run_compiled_binary.sh"],
args = ["$(location :compiled_cli)"],
data = [":compiled_cli"],
)
sh_test(
name = "bun_build_compile_flag_shape_test",
size = "small",
srcs = ["verify_flag_aquery.sh"],
tags = [
"exclusive",
"no-sandbox",
],
data = [
"BUILD.bazel",
"cli.ts",
"fake_cross_bun.bin",
"site/index.html",
"site/main.ts",
"site/styles.css",
"//:repo_runtime_files",
"//bun:repo_runtime_files",
"//internal:repo_runtime_files",
"//tests:nested_bazel_test.sh",
],
env_inherit = ["PATH"],
)

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

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

View File

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

Some files were not shown because too many files have changed in this diff Show More