Bundling¶
ts_binary and ts_bundle collect transitive .js outputs and optionally invoke a pluggable bundler.
Basic Usage (Placeholder Mode)¶
Without a bundler, the rule concatenates all .js files in dependency order. This is useful during development and keeps the build graph valid.
load("@rules_typescript//ts:defs.bzl", "ts_binary")
ts_binary(
name = "app",
entry_point = "//src/app",
format = "esm",
sourcemap = True,
)
With Vite¶
load("@rules_typescript//vite:bundler.bzl", "vite_bundler")
load("@rules_typescript//npm:defs.bzl", "node_modules")
load("@rules_typescript//ts:defs.bzl", "ts_bundle")
node_modules(
name = "node_modules",
deps = ["@npm//:vite"],
)
vite_bundler(
name = "vite",
vite = "@npm//:vite",
node_modules = ":node_modules",
)
ts_bundle(
name = "app",
entry_point = "//src/app",
bundler = ":vite",
format = "esm",
sourcemap = True,
minify = True,
external = ["react", "react-dom"],
)
Custom Bundler (BundlerInfo Interface)¶
Any Bazel rule that returns BundlerInfo can plug into ts_bundle and ts_binary. This lets you bring your own bundler — esbuild, Rolldown, webpack — without modifying rules_typescript.
load("@rules_typescript//ts:defs.bzl", "BundlerInfo")
def _my_bundler_impl(ctx):
return [BundlerInfo(
bundler_binary = ctx.file.binary,
config_file = None, # optional static config
runtime_deps = depset([]), # files needed at bundle time
use_generated_config = False, # set True for Vite-style config
)]
my_bundler = rule(
implementation = _my_bundler_impl,
attrs = {
"binary": attr.label(
allow_single_file = True,
executable = True,
cfg = "exec",
),
},
)
BundlerInfo Invocation Modes¶
Mode 1 — Standard CLI (use_generated_config = False, the default)
ts_bundle invokes the bundler binary with:
<bundler_binary>
--entry <path/to/entry.js>
--out-dir <output/dir>
--format esm|cjs|iife
[--external <pkg>]...
[--sourcemap]
[--config <config_file>] (only when config_file is set)
Output is expected at <out-dir>/<bundle_name>.js (and .js.map if --sourcemap).
Mode 2 — Generated config (use_generated_config = True)
ts_bundle generates a vite.config.mjs containing all bundle options and invokes:
| Format | Output file |
|---|---|
esm |
<bundle_name>.es.js |
cjs |
<bundle_name>.cjs.js |
iife |
<bundle_name>.iife.js |
BundlerInfo Fields¶
| Field | Type | Description |
|---|---|---|
bundler_binary |
File |
The executable that performs bundling |
config_file |
File or None |
Optional static config passed via --config (mode 1 only) |
runtime_deps |
depset of File |
Files the bundler needs at runtime |
use_generated_config |
bool |
When True, use mode 2 (generated vite.config.mjs) |
ts_binary / ts_bundle Attributes¶
| Attribute | Type | Default | Description |
|---|---|---|---|
entry_point |
label |
required | ts_compile target providing JsInfo |
bundler |
label |
None |
Target providing BundlerInfo |
bundle_name |
string |
rule name | Output file name (without .js) |
format |
string |
"esm" |
Output format: esm, cjs, iife |
sourcemap |
bool |
True |
Emit source map |
minify |
bool |
True |
Minify the bundle (esbuild minifier via Vite) |
split_chunks |
bool |
False |
Enable chunk splitting (Vite mode only; output is a directory) |
external |
string_list |
[] |
Module specifiers to leave external |
define |
string_dict |
{} |
Global constant replacements |