Files
rules_bun/internal/bun_compile.bzl

316 lines
11 KiB
Python

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