Bundler

Client-side asset bundler — produces content-hashed dist/.. files plus a manifest.json mapping logical name to hashed filename. Designed to drop into a static server (b.static) so cache-busting lives at the filename layer and HTML can long-cache hashed paths.

No-build-step fallback: the default engine.passthrough reads each entry from disk verbatim, hashes it, and writes the hashed copy. Operators with no module-graph need ship their source files directly through the bundler and skip the toolchain entirely.

Module-graph / tree-shake / minify / sourcemaps: operators supply esbuild (devDependency, never vendored) and adapt it via engine.fromEsbuild(esbuild, opts) — the framework owns the integration seam, the operator brings the heavy machinery. The ~10 MB esbuild-wasm blob is intentionally not vendored.

Hashes are SHA3-512, first 16 hex chars by default (operators override via opts.hashLen between 4 and 64). Source maps written by an engine land as ..map siblings.

Watch mode: bundler.watch(callback) arms fs.watch on each entry's directory, debounces bursts via opts.graceMs (default 100 ms), and rebuilds the entire entry set on change.

Manifest format:

{ "app": "app.4a8c2f1d9e3b7062.js", "styles": "styles.b29f1e7c.css" }

Integrates with lib/static.js: serve outdir as a static directory; b.static's hashed-path detection sets long-cache headers on files that look hashed, and integrity() reads the manifest to emit Subresource Integrity attributes.

b.bundler.create(opts) #

stable0.4.0
{
  entries:  { [name: string]: string },   // logical name → source path
  outdir:   string,                        // dist directory (created if missing, mode 0o755)
  cwd:      string,                        // resolves relative entries / outdir; defaults to process.cwd()
  engine:   { name: string, transform: async (entryPath, contentBuf) => { content, sourceMap?, imports? } },
                                           // defaults to engine.passthrough
  manifest: string | false,                // manifest filename ("manifest.json"), or false to skip
  hash:     boolean,                       // emit ..; default true
  hashLen:  number,                        // hex chars in the hash, 4..64; default 16
  graceMs:  number,                        // watch-mode debounce ms; default 100
  log:      object,                        // structured logger ({ info, warn, error })
}

Build a content-hashed asset pipeline for a fixed set of named entries. The returned object exposes build() (one-shot rebuild, resolves to { outputs, manifestPath, manifest, durationMs }), watch(callback) (arm fs.watch and debounce-rebuild on change), and close() (drop watchers and pending timers).

Throws BundlerError at config time on missing / malformed entries, missing outdir, an out-of-range hashLen, or an engine that does not implement { name, transform }.

var bundler = b.bundler.create({
  entries: { app: "./src/app.js", styles: "./src/styles.css" },
  outdir:  "./public/dist",
  hashLen: 16,
});

// bundler.build() returns a Promise resolving to:
//   { outputs: [...], manifest: { app: "app..js", styles: "styles..css" },
//     manifestPath: ".../public/dist/manifest.json", durationMs:  }

// Watch mode — rebuild on edits.
bundler.watch(function (err, result) {
  if (err) return;
  // result.manifest is the freshly-written name→hashed-filename map
});

// Operator-supplied esbuild for module-graph + tree-shake + minify.
// var esbuild = require("esbuild");
// var modGraph = b.bundler.create({
//   entries: { app: "./src/app.js" },
//   outdir:  "./public/dist",
//   engine:  b.bundler.engine.fromEsbuild(esbuild, { minify: true, sourcemap: true }),
// });

Last updated 2026-08-08T16:39:49.652Z by seeder.