Fast client-side asset builder with plugin-based architecture for transforming files and directories
npx @tessl/cli install tessl/npm-broccoli@3.5.0Broccoli is a fast, reliable asset pipeline and build tool for frontend development, supporting constant-time rebuilds and compact build definitions. It provides a plugin-based architecture for transforming files and directories, with support for TypeScript compilation, asset processing, and live reloading during development.
npm install --save-dev broccoli + npm install --global broccoli-cliBroccoli uses CommonJS exports exclusively:
const broccoli = require("broccoli");
// Access main components
const Builder = broccoli.Builder;
const Watcher = broccoli.Watcher;
const WatcherAdapter = broccoli.WatcherAdapter;
const loadBrocfile = broccoli.loadBrocfile;
const getMiddleware = broccoli.getMiddleware;
const cli = broccoli.cli;
// Server functionality requires separate destructuring
const { Server, serve } = broccoli.server;Destructured imports:
const { Builder, Watcher, loadBrocfile, getMiddleware, cli } = require("broccoli");
const { serve } = require("broccoli").server;const { Builder, loadBrocfile } = require("broccoli");
// Load Brocfile configuration
const buildFn = loadBrocfile({
brocfilePath: './Brocfile.js',
cwd: process.cwd()
});
// Create build tree from Brocfile
const tree = buildFn({ env: 'development' });
// Create and run builder
const builder = new Builder(tree);
await builder.build();
console.log('Build output at:', builder.outputPath);
await builder.cleanup();Development server with file watching:
const { Builder, Watcher, loadBrocfile } = require("broccoli");
const { serve } = require("broccoli").server;
const buildFn = loadBrocfile();
const tree = buildFn({ env: 'development' });
const builder = new Builder(tree);
// Start file watcher
const watcher = new Watcher(builder, builder.watchedSourceNodeWrappers);
await watcher.start();
// Start development server
await serve(watcher, 'localhost', '4200', undefined, undefined, undefined, false, '', '');Broccoli is built around several key components:
Core build functionality for executing transformation pipelines and managing build state.
class Builder {
constructor(outputNode: Node, options?: BuilderOptions);
readonly outputNode: Node;
readonly outputPath: string;
readonly buildId: number;
readonly watchedPaths: string[];
readonly unwatchedPaths: string[];
readonly watchedSourceNodeWrappers: SourceNodeWrapper[];
build(): Promise<void>;
cancel(): Promise<void>;
cleanup(): Promise<void>;
makeNodeWrapper(node: Node, _stack?: any): NodeWrapper;
}
interface BuilderOptions {
tmpdir?: string | null;
}
// Static error classes available on Builder
Builder.BuilderError: typeof BuilderError;
Builder.InvalidNodeError: typeof InvalidNodeError;
Builder.NodeSetupError: typeof NodeSetupError;
Builder.BuildError: typeof BuildError;
Builder.NodeWrapper: typeof NodeWrapper;
Builder.TransformNodeWrapper: typeof TransformNodeWrapper;
Builder.SourceNodeWrapper: typeof SourceNodeWrapper;File system monitoring and incremental rebuild capabilities for development workflows.
class Watcher extends EventEmitter {
constructor(
builder: any,
watchedNodes: SourceNodeWrapper[],
options?: WatcherOptions
);
readonly currentBuild: Promise<void>;
readonly builder: any;
start(): Promise<void>;
quit(): Promise<void>;
}
interface WatcherOptions {
debounce?: number;
watcherAdapter?: WatcherAdapter;
saneOptions?: any;
ignored?: string[];
}
// Events emitted by Watcher:
// 'buildStart' - When a build starts
// 'buildSuccess' - When a build succeeds
// 'buildFailure' - When a build fails with error
// 'change' - When files change
// 'debounce' - During debounce period
// 'quitStart', 'quitEnd' - During shutdownHTTP server for serving built assets during development with live reloading support.
// Server module exports: { Server, serve }
const { Server, serve } = require("broccoli").server;
class Server {
constructor(
watcher: Watcher,
host: string,
port: string,
connect?: any,
ui?: UI,
ssl?: boolean,
sslKey?: string,
sslCert?: string
);
start(): Promise<void>;
stop(): Promise<void>;
}
function serve(
watcher: Watcher,
host: string,
port: string,
_connect?: any,
_process?: any,
ui?: UI,
ssl?: boolean,
sslKey?: string,
sslCert?: string
): Promise<void>;
function getMiddleware(
watcher: Watcher,
options?: MiddlewareOptions
): (req: any, res: any, next: any) => any;
interface MiddlewareOptions {
autoIndex?: boolean;
liveReloadPath?: string;
}Brocfile configuration loading and processing functionality.
function loadBrocfile(options?: LoadBrocfileOptions): (options: BrocfileOptions) => Node;
interface LoadBrocfileOptions {
brocfilePath?: string;
cwd?: string;
}
interface BrocfileOptions {
env: string; // Default: 'development'
}Complete CLI implementation for build, serve, and other commands.
function cli(args: string[], ui?: UI): Promise<any>;Low-level file system monitoring using the sane package for custom watching implementations.
class WatcherAdapter extends EventEmitter {
constructor(
watchedNodes: SourceNodeWrapper[],
options?: any,
ignored?: string[]
);
watch(): Promise<void>;
quit(): Promise<void>;
}
// Events emitted by WatcherAdapter:
// 'change' - File change events
// 'error' - Watch errorsComprehensive error system for build failures, node setup issues, and cancellation.
// Error classes accessed via Builder static properties
const BuilderError = Builder.BuilderError;
const BuildError = Builder.BuildError;
const NodeSetupError = Builder.NodeSetupError;
const InvalidNodeError = Builder.InvalidNodeError;
class BuilderError extends Error {
readonly isBuilderError: boolean;
constructor(message?: string);
static isBuilderError(error: any): boolean;
}
class BuildError extends BuilderError {
readonly isSilent: boolean;
readonly isCancellation: boolean;
readonly broccoliPayload: BroccoliPayloadError;
constructor(originalError: any, nodeWrapper?: NodeWrapper);
}
class NodeSetupError extends BuilderError {
constructor(originalError: Error, nodeWrapper?: NodeWrapper);
}
class InvalidNodeError extends BuilderError {
constructor(message?: string);
}
class Cancelation extends Error {
readonly isCancelation: boolean;
readonly isSilent: boolean;
constructor(message?: string);
static isCancelationError(e: any): boolean;
}
interface BroccoliPayloadError {
originalError: Error;
originalMessage: string;
nodeId: number;
nodeLabel: string;
nodeName: string;
nodeAnnotation: string | undefined | null;
instantiationStack: string;
location: {
file: string;
treeDir: string;
line: number;
column: number;
};
}interface Node {
// Broccoli plugin node interface
[key: string]: any;
}
// Node wrapper classes (available via Builder static properties)
class NodeWrapper {
readonly id: number;
readonly label: string;
readonly cachePath: string;
readonly outputPath: string;
readonly nodeInfo: any;
readonly inputNodeWrappers: NodeWrapper[];
readonly buildState: {
selfTime?: number;
totalTime?: number;
built?: boolean;
};
constructor();
build(): void | Promise<void>;
revise(): void;
get revision(): number;
toString(): string;
toJSON(): object;
formatInstantiationStackForTerminal(): string;
nodeInfoToJSON(): object;
}
class SourceNodeWrapper extends NodeWrapper {
setup(features: any): void;
build(): void;
toString(): string;
nodeInfoToJSON(): object;
}
class TransformNodeWrapper extends NodeWrapper {
readonly inputRevisions: WeakMap<any, { revision: number; changed: boolean }>;
readonly callbackObject: any;
readonly inputPaths: string[];
setup(features: any): void;
shouldBuild(): boolean;
build(): Promise<void>;
toString(): string;
nodeInfoToJSON(): object;
}
interface UI {
write(message: string, writeLevel?: string): void;
writeLine(message: string, writeLevel?: string): void;
writeError(error: Error): void;
}