336 lines
12 KiB
Python
336 lines
12 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", "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"],
|
|
)
|