Extensions
Extensions are user enabled file processors. Nothing loads by default. List a name or path in the
extensions array and the build loads it, resolves it, and runs its hooks on matching
files.
{
"bb": {
"extensions": ["./tools/minify-json", "my-pack-tools"]
}
}Resolution order
-
Relative path from the project dir, plus
index.mjsandindex.jsprobes. - Project
node_modules. - Project
.builder/extensions/<name>. - Global
~/.bedrock-builder/extensions/<name>. - Dev-only repo
extensions/samples, excluded from npm.
Missing or broken extensions warn and skip. The build never fails because of an extension.
bb ext lists each spec with its resolved path plus ok, missing, or broken status.
Missing node deps show a hint to run bb ext --install. Extensions can also report
their own health checks, such as an external tool they need.
Per-extension dependencies
Each extension keeps its own node_modules. Declare what it needs in its manifest and
install with one command. Core stays lean.
{
"name": "json-cleaner",
"entry": "index.mjs",
"dependencies": { "jsonc-parser": "^3.3.1" }
}bb ext --install
Installs each enabled extension's deps into its own folder with
--no-save. Never touches the core package or the project root.
Processor hooks
Each processor declares a name plus a match(file) function. Four
optional hooks run in order:
remap(file)returns a new output path or null. Runs before the cache check.pre(file, ctx)runs before the file is read. Use it for setup or validation.-
transform(bytes, file, ctx)maps input bytes to output bytes. Return null to keep the input unchanged. -
post(file, ctx)runs after the output is written. Use it for logging or side files.
A processor that throws in match is skipped for that file with a warning. A processor
that throws in pre, transform, or post warns and the
pipeline keeps the last good bytes. Same name replaces the old entry, so an extension can override
a default or another extension.
Minimal extension
export default {
name: "minify-json",
match: (file) => file.rel.endsWith(".json"),
transform: (bytes) => {
const text = new TextDecoder().decode(bytes);
const min = JSON.stringify(JSON.parse(text));
return new TextEncoder().encode(min);
},
};
Save it as tools/minify-json/index.mjs, add "./tools/minify-json" to
extensions, and every JSON file compacts on build. Return null from
transform when the file needs no change.
Bundled samples
tga-converterconverts pack png and jpg textures to tga, except pack icons.- Audio conversion can be provided by a private extension through ffmpeg.
-
emissive-fixerzeroes rgb on fully transparent png pixels, fixing emissive bleed from editors that leave color data behind. -
json-cleanerremoves JSON comments, and can strip root$schemafields or minify files.
Each sample can carry two manifests. extension.json owns the builder entry point,
package.json owns npm metadata and dependencies. Deps merge from both files, and a
conflicting entry warns and keeps the extension.json value.
Copy a sample folder into your project, add its path to
extensions, and it runs on matching files. Factory extensions receive helpers from bb
itself, so they work with no installed dep. That covers global-only installs too.
export default function myExtension({ settings }) {
return {
name: "my-extension",
match: (file) => file.rel.endsWith(".png"),
transform: (content) => doWork(content, settings),
};
}Json cleaner settings
{
"bb": {
"extensions": [
{
"name": "json-cleaner",
"settings": { "stripSchemas": true, "minify": true }
}
]
}
}Both settings default to false. The extension runs on every JSON file and leaves unchanged files alone.
Per-extension settings
Use an object when an extension needs settings. String entries still work and use an empty settings object.
{
"bb": {
"extensions": [
{
"name": "emissive-fixer",
"settings": { "stripPackIcons": false }
}
]
}
}Default processors
normalize-textunifies line endings and encoding for text files.validate-jsonparses JSON and warns on invalid files.raw-copyis the fallback that copies anything unmatched.
Core texture and audio helpers stay exported for extension authors. Nothing loads them unless an extension calls them.