Broccoli Bridge
The `broccoli-bridge` package, currently at version 1.0.0, provides a specific utility for managing dependencies between Broccoli build system nodes. Its primary function is to allow developers to define dependencies between Broccoli plugins (`nodes`) even when those nodes are instantiated in different parts of an application's codebase or at different times, thus addressing potential circular dependency issues or inconvenient instantiation order. It achieves this by offering `placeholderFor(name)` to create a temporary node and `fulfill(name, node)` to later link that placeholder to an actual Broccoli node. This enables a more flexible composition of complex Broccoli build pipelines. The package has not seen a new major release, remaining at 1.0.0. A key architectural note is its reliance on internal details of the Broccoli `Plugin` API, meaning its stability is inherently tied to the evolution of the core Broccoli project and it carries a risk of breaking changes if Broccoli's internals change.
Common errors
-
TypeError: node.inputPaths is not a function
cause The underlying internal Broccoli Plugin API that `broccoli-bridge` relies on has changed, making the placeholders incompatible with how Broccoli nodes are expected to be processed.fixCheck the `broccoli` changelog for breaking changes related to its Plugin API. Verify if a newer version of `broccoli-bridge` or a patch exists, or if a manual update to your build configuration is required to adapt to Broccoli's new internal structure. -
ReferenceError: BroccoliBridge is not defined
cause This error typically occurs when attempting to use ESM `import` syntax (`import BroccoliBridge from 'broccoli-bridge'`) with `broccoli-bridge` v1.0.0, which is a CommonJS package, or if the `require` statement itself is missing or malformed.fixEnsure you are using the correct CommonJS `require` syntax: `const BroccoliBridge = require('broccoli-bridge');`. -
Error: Placeholder 'some-name' was never fulfilled before build started.
cause While `placeholderFor(name)` can be called before `fulfill(name, node)`, the Broccoli build process expects all node dependencies to be resolvable. If a placeholder is created but never fulfilled with an actual Broccoli node before the build begins, it will result in a build-time error.fixConfirm that every `bridge.placeholderFor(name)` call has a corresponding `bridge.fulfill(name, node)` call with a valid Broccoli node for that exact `name` before your Broccoli build command is executed.
Warnings
- breaking This package explicitly relies on internal, undocumented details of the Broccoli `Plugin` API. This makes it inherently unstable and highly susceptible to breaking changes with any updates to the core Broccoli library, as internal APIs can change without warning or adherence to semantic versioning.
Install
-
npm install broccoli-bridge -
yarn add broccoli-bridge -
pnpm add broccoli-bridge
Imports
- BroccoliBridge
import BroccoliBridge from 'broccoli-bridge';
const BroccoliBridge = require('broccoli-bridge');
Quickstart
class MockBroccoliNode {
constructor(name) {
this.name = name;
this.inputPaths = []; // Mock required property for some Broccoli contexts
this.outputPath = `/tmp/broccoli-${name}`;
}
}
// Mock Broccoli Plugin classes for demonstration
class PluginA {
constructor(inputNodes) {
this.inputNodes = inputNodes;
this.name = 'PluginA_Node';
console.log('PluginA instantiated with inputs:', inputNodes.map(n => n.name || 'placeholder'));
}
// In a real scenario, PluginA would implement a `build` method.
}
class PluginB {
constructor(inputNodes) {
this.inputNodes = inputNodes;
this.name = 'PluginB_Node';
console.log('PluginB instantiated with inputs:', inputNodes.map(n => n.name || 'unknown'));
}
// In a real scenario, PluginB would implement a `build` method.
}
const BroccoliBridge = require('broccoli-bridge');
// Stash your bridge instance somewhere central for later access
let bridge = new BroccoliBridge();
console.log('BroccoliBridge instance created.\n');
// Create your `PluginA` instance using a placeholder for PluginB's output
const inputOne = new MockBroccoliNode('InputOne');
const placeholderForB = bridge.placeholderFor('plugin-b');
console.log('Placeholder for "plugin-b" created.');
let a = new PluginA([
inputOne,
placeholderForB // PluginA depends on the future output of 'plugin-b'
]);
console.log('PluginA created, its second input is currently a placeholder.\n');
// Instantiate PluginB and fulfill the placeholder with its actual instance
const inputTwo = new MockBroccoliNode('InputTwo');
const inputThree = new MockBroccoliNode('InputThree');
let b = new PluginB([inputTwo, inputThree]);
console.log('PluginB created with its own inputs.');
bridge.fulfill('plugin-b', b);
console.log('Placeholder "plugin-b" fulfilled with the actual PluginB instance.\n');
// At this point, if a Broccoli build process were to start,
// PluginA would correctly receive the output of PluginB
// via the fulfilled placeholder. The conceptual dependency is resolved.
console.log('During a Broccoli build, PluginA will effectively receive the node named: ' + b.name + ' as its second input.');
console.log('The order of instantiation for PluginA and PluginB did not matter thanks to broccoli-bridge.');