From f03598407bede84a9d24f015f5235e2b273daf0d Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 4 Mar 2026 03:30:07 +0000 Subject: [PATCH] feat: implement phase 5 bun_bundle bootstrap --- README.md | 6 +++ bun/defs.bzl | 2 + internal/bun_bundle.bzl | 78 +++++++++++++++++++++++++++++- tests/bundle_test/BUILD.bazel | 48 ++++++++++++++++++ tests/bundle_test/main.ts | 5 ++ tests/bundle_test/verify_bundle.sh | 14 ++++++ tests/bundle_test/verify_minify.sh | 13 +++++ 7 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 tests/bundle_test/BUILD.bazel create mode 100644 tests/bundle_test/main.ts create mode 100755 tests/bundle_test/verify_bundle.sh create mode 100755 tests/bundle_test/verify_minify.sh diff --git a/README.md b/README.md index e81d03f..4b178e5 100644 --- a/README.md +++ b/README.md @@ -28,3 +28,9 @@ Phase 4 bootstrap is in place: - Test rule `bun_test` (`/internal/bun_test.bzl`) - Public export via `bun/defs.bzl` - Focused passing/failing test targets (`//tests/bun_test_test:all`) + +Phase 5 bootstrap is in place: + +- Bundle rule `bun_bundle` (`/internal/bun_bundle.bzl`) +- Public export via `bun/defs.bzl` +- Focused output/minify tests (`//tests/bundle_test:all`) diff --git a/bun/defs.bzl b/bun/defs.bzl index 0664176..b19a324 100644 --- a/bun/defs.bzl +++ b/bun/defs.bzl @@ -1,4 +1,5 @@ load("//internal:bun_binary.bzl", "bun_binary") +load("//internal:bun_bundle.bzl", "bun_bundle") load("//internal:bun_install.bzl", "bun_install") load("//internal:bun_test.bzl", "bun_test") load(":repositories.bzl", "bun_register_toolchains", "bun_repositories") @@ -7,6 +8,7 @@ load(":toolchain.bzl", "BunToolchainInfo", "bun_toolchain") __all__ = [ "BunToolchainInfo", "bun_binary", + "bun_bundle", "bun_install", "bun_test", "bun_register_toolchains", diff --git a/internal/bun_bundle.bzl b/internal/bun_bundle.bzl index b430850..13af4bc 100644 --- a/internal/bun_bundle.bzl +++ b/internal/bun_bundle.bzl @@ -1,2 +1,76 @@ -def bun_bundle(**_kwargs): - fail("bun_bundle is not implemented yet") +"""Rule for bundling JS/TS sources with Bun.""" + + +def _output_name(target_name, entry): + stem = entry.basename.rsplit(".", 1)[0] + return "{}__{}.js".format(target_name, stem) + + +def _bun_bundle_impl(ctx): + toolchain = ctx.toolchains["//bun:toolchain_type"] + bun_bin = toolchain.bun.bun_bin + + transitive_inputs = [] + if ctx.attr.node_modules: + transitive_inputs.append(ctx.attr.node_modules[DefaultInfo].files) + + outputs = [] + for entry in ctx.files.entry_points: + output = ctx.actions.declare_file(_output_name(ctx.label.name, entry)) + outputs.append(output) + + args = ctx.actions.args() + args.add("build") + args.add(entry.path) + args.add("--outfile") + args.add(output.path) + args.add("--target") + args.add(ctx.attr.target) + args.add("--format") + args.add(ctx.attr.format) + if ctx.attr.minify: + args.add("--minify") + if ctx.attr.sourcemap: + args.add("--sourcemap") + for package in ctx.attr.external: + args.add("--external") + args.add(package) + + ctx.actions.run( + executable = bun_bin, + arguments = [args], + inputs = depset( + direct = [entry] + ctx.files.data, + transitive = transitive_inputs, + ), + outputs = [output], + mnemonic = "BunBundle", + progress_message = "Bundling {} with Bun".format(entry.short_path), + ) + + return [DefaultInfo(files = depset(outputs))] + + +bun_bundle = rule( + implementation = _bun_bundle_impl, + attrs = { + "entry_points": attr.label_list( + mandatory = True, + allow_files = [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"], + ), + "node_modules": attr.label(), + "data": attr.label_list(allow_files = True), + "target": attr.string( + default = "browser", + values = ["browser", "node", "bun"], + ), + "format": attr.string( + default = "esm", + values = ["esm", "cjs", "iife"], + ), + "minify": attr.bool(default = False), + "sourcemap": attr.bool(default = False), + "external": attr.string_list(), + }, + toolchains = ["//bun:toolchain_type"], +) diff --git a/tests/bundle_test/BUILD.bazel b/tests/bundle_test/BUILD.bazel new file mode 100644 index 0000000..2417e43 --- /dev/null +++ b/tests/bundle_test/BUILD.bazel @@ -0,0 +1,48 @@ +load("//bun:defs.bzl", "bun_bundle") + +bun_bundle( + name = "simple_bundle", + entry_points = ["main.ts"], + target_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:linux", + ], +) + +bun_bundle( + name = "minified_bundle", + entry_points = ["main.ts"], + minify = True, + target_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:linux", + ], +) + +sh_test( + name = "bundle_output_test", + srcs = ["verify_bundle.sh"], + args = ["$(location :simple_bundle)"], + data = [":simple_bundle"], + target_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:linux", + ], +) + +sh_test( + name = "bundle_minify_test", + srcs = ["verify_minify.sh"], + args = [ + "$(location :simple_bundle)", + "$(location :minified_bundle)", + ], + data = [ + ":simple_bundle", + ":minified_bundle", + ], + target_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:linux", + ], +) diff --git a/tests/bundle_test/main.ts b/tests/bundle_test/main.ts new file mode 100644 index 0000000..ff55828 --- /dev/null +++ b/tests/bundle_test/main.ts @@ -0,0 +1,5 @@ +export function greet(name: string): string { + return `Hello ${name}`; +} + +console.log(greet("bundle")); diff --git a/tests/bundle_test/verify_bundle.sh b/tests/bundle_test/verify_bundle.sh new file mode 100755 index 0000000..b0122f9 --- /dev/null +++ b/tests/bundle_test/verify_bundle.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +bundle="$1" + +if [[ ! -f "${bundle}" ]]; then + echo "Bundle output not found: ${bundle}" >&2 + exit 1 +fi + +if [[ ! -s "${bundle}" ]]; then + echo "Bundle output is empty: ${bundle}" >&2 + exit 1 +fi diff --git a/tests/bundle_test/verify_minify.sh b/tests/bundle_test/verify_minify.sh new file mode 100755 index 0000000..eab37d7 --- /dev/null +++ b/tests/bundle_test/verify_minify.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +bundle="$1" +minified="$2" + +bundle_size="$(wc -c < "${bundle}")" +minified_size="$(wc -c < "${minified}")" + +if (( minified_size >= bundle_size )); then + echo "Expected minified bundle (${minified_size}) to be smaller than regular bundle (${bundle_size})" >&2 + exit 1 +fi