With Broccoli 1.0, the Broccoli plugin API is changing.
If you are a Broccoli user wishing to upgrade to Broccoli 1.0, or if you are a plugin author wishing to make your plugin compatible with Broccoli 1.0, then this document is for you.
If you have been directed here from an ember-cli
build error, please see
#374 for details on next steps
to resolve the error.
The old API requires that a plugin implement a .read
or .rebuild
method.
The new API requires that a plugin be a subclass of broccoli-plugin.
Broccoli 0.x can run plugins that use either the old or the new API.
Broccoli 1.x can only run plugins that use the new API. In return, we get new features, such as improved error reporting and being able to control the location of temporary directories, as well as future extensibility.
Along with the API change, we are making two stylistic changes in convention:
We used to call plugin instances "trees", but we now prefer calling them
"nodes" (as in "nodes in the build graph"). We also prefer using explicit
new
to instantiate plugins.
// Old convention:
var outputTree = jshintTree(inputTree);
// New convention:
var outputNode = new JSHinter(inputNode);
Both styles will continue to work, but we'll gradually change code and documentation to follow the new convention.
If you are using Broccoli 0.16.5 or newer right now, set the
BROCCOLI_WARN_READ_API
environment variable to find out whether all your
plugins are compatible with Broccoli 1.0:
BROCCOLI_WARN_READ_API=y broccoli serve
# Or, for Ember CLI users:
BROCCOLI_WARN_READ_API=y ember server
If you get warnings about a plugin using the deprecated .read/.rebuild
API,
try upgrading that plugin to the latest version. If the latest version of a
plugin still isn't compatible, consider opening an issue on its GitHub repo,
or better yet, send a pull request.
If you depend on the "broccoli" package directly, then bump the version spec
in your package.json
like so:
"broccoli": "^1.0.0"
The command-line interface (broccoli serve
and broccoli build
) is still
the same. However, the programmatic API (require('broccoli')
) has changed a
bit. If you are using Broccoli programmatically, refer to
CHANGELOG.md
to see what has changed.
Ember CLI users: Due to the changes in Broccoli's programmatic API, you cannot
use Broccoli 1.0 through the ember
tool until Ember CLI is updated. However,
if you still want to give Broccoli 1.0 a spin right now, try using the
following hack:
npm install broccoli@latest
echo "module.exports = require('./ember-cli-build')();" > Brocfile.js
broccoli serve
Updating your plugin will make it ready for Broccoli 1.x without breaking backwards compatibility with Broccoli 0.x.
If your plugin subclasses broccoli-filter, upgrade to broccoli-filter 1.0.0 or newer. Be sure to call the base class constructor as detailed in the README; other than that, no changes are needed.
If your plugin subclasses broccoli-caching-writer, upgrade to broccoli-caching-writer 2.0.0.
With version 2.0.0, broccoli-caching-writer's API is a drop-in replacement for
broccoli-plugin. As a result, its API is completely different from
broccoli-caching-writer 0.x/1.x, and your plugin's code will need to be
updated. To do so, it's best to read the
broccoli-plugin README to
familiarize yourself with the new API, while replacing all instances of
Plugin
with CachingWriter
in your plugin code.
As a guide, where you previously implemented
MyPlugin.prototype.updateCache = function(sourcePaths, destPath) {
// Compile from sourcePaths into destPath
}
you'll now want to implement
MyPlugin.prototype.build = function() {
// Compile from this.inputPaths into this.outputPath
}
If you always have exactly one input node, use this.inputPaths[0]
.
If your plugin subclasses
broccoli-writer or implements
.read
or .rebuild
directly without using a baseclass, subclass
broccoli-plugin instead.
If you were using broccoli-writer, your implementation might have looked something like this:
var Writer = require('broccoli-writer');
MyPlugin.prototype = Object.create(Writer.prototype);
MyPlugin.prototype.constructor = MyPlugin;
function MyPlugin(inputTree) {
this.inputTree = inputTree;
}
MyPlugin.prototype.write = function(readTree, destDir) {
readTree(this.inputTree).then(function(srcDir) {
// Build from srcDir to destDir
});
};
With broccoli-plugin, the same plugin might be implemented like this:
var Plugin = require('broccoli-plugin');
MyPlugin.prototype = Object.create(Plugin.prototype);
MyPlugin.prototype.constructor = MyPlugin;
function MyPlugin(inputNode) {
Plugin.call(this, [inputNode]);
}
MyPlugin.prototype.build = function() {
// Build from this.inputPaths[0] to this.outputPath
};
See the broccoli-plugin README for details.