Plugins for all your build needs
This is part of The Brunch.io Guide.
With Brunch, features don’t get provided through the same architectural split as you’d find in Grunt, Gulp, etc. A ton of features and behaviors are built-in (build pipeline, incremental watcher, sourcemaps, etc.) but everything else remains in plugins, including the handling of every source language.
You will generally use at least one plugin for scripts, one for styles, and a minifier for each.
Note: in this chapter’s text, plugin names are always links to their npm homepage (featuring their description, links, download counts, etc.).
Enabling a plugin
For a plugin to be enabled and used, you just need to install it, which means it is both in
node_modules. The easiest way to do that for the first time is with
npm install --save-dev <pluginName>, and the easiest way from an existing
package.json is through a simple
Brunch will then inspect all modules that satisfy both these requirements, looking for any module whose default export is a constructor featuring a
brunchPlugin property set to
true on its
prototype property. Otherwise, the module is ignored.
Any module that passes this filter has its constructor automatically instantiated, with the global configuration passed as argument, and gets registered based on its scope declaration (file type, extensions, pattern… we’ll dive into this later).
In short, forget about crazy splatters of redundant
loadNpmTasks here. Brunch keeps it short and sweet.
It’s worth noting that plugin order matters (as in, the order in which they’re listed in
package.json): when plugins operate on the same files (usually target files), their order can impact their ability to work. For instance,
groundskeeper-brunch requires running before any minifiers, as these will obfuscate some code constructs the former relies on to detect trimmable code.
Fine-tuning through optional configuration
Every plugin is usually designed to be operational and useful without any configuration; that being said, it’s often possible to tweak their behavior through specific configuration. These settings are defined inside
brunch-config.js, under the
plugins key and a subkey named after the plugin.
For instance, the
appcache-brunch plugin looks for
plugins.appcache. Most often, key names are trivial to infer, but they can stray from an exact match, or opt for camel case… Just like
browser-sync-brunch that looks for
plugins.browserSync. Check out the plugin’s documentation to be sure!
Brunch and CSS
CSS-related plugins feature a
"stylesheet" on their prototype, and usually provide a specific value for their
extension property. These are mostly transpilers, what Brunch generically refers to as compilers. At the time of this writing, the main ones are:
css-brunch, for vanilla (W3C) CSS files;
sass-brunchfor Less and Sass.
sass-brunchalso comes with Compass support.
stylus-brunchfor Stylus, my personal favorite;
- There are various Swiss-army knives for CSS; they get plugins, such as
pleeease-brunchfor pleeease or
- When it comes to coding style, CSSComb is nice and offers plugins for builders, including
This is a similar landscape to CSS, except
type is now
coffee-script-brunch, of course, and even
json-brunch, so you can use JSON files directly as modules;
- In the same corner, but way less popular, you can get
ember-script-brunchfor the rather niche EmberScript,
roy-brunchfor the even more niche Roy and
typescript-brunchfor the vastly better-known TypeScript.
- Subtler stuff:
wisp-brunchhandles Wisp, a kind of ClojureScript, and
sweet-js-brunchopens the heavenly doors of “hygienic macros” thanks to sweet.js.
And just because this is 2017 after all, you’ll find a bunch of options for automatic JSX (React) processing and ES6 goodness:
es6-module-transpiler-brunchfocuses on the native ES6 module syntax (the future!);
babel-brunchlet you use a ton of ES6 features. Currently, Babel (formerly 6to5 + CoreJS) is solidly ahead when it comes to feature coverage, and what’s more, it can handle JSX too!
Brunch and templates
After scripts and styles, the third category of files that Brunch has special processing for is templates.
Let me reiterate: a template plugin for Brunch is a compiler that turns a template into a module whose default export is a pre-compiled function, hence you do not incur any run-time penalty. That function takes as unique argument an object whose properties are directly usable by your template, just like local variables: what is commonly referred to as a presenter or view model. The function synchronously returns HTML.
When it comes to template languages, we have a world of choices:
- All-time classics:
- The almighty Dust has superb support through
dustjs-linkedin-brunchfor LinkedIn’s Dust extension, also used by PayPal, among other high-profile users…
- Someone came up with
jade-react-brunch, that avoids having to use kludgy JSX by letting you use a separate Jade file, but outputs code using the
React.DOMbuilder, just like JSX literals… This makes me drool, I must say!
- Then you’ll get a lot of more niche syntaxes:
eco-brunchfor Eco, an ERB variant that used CoffeeScript;
emblem-brunchfor Emblem, which is much like Jade but has a lot of syntactic sugar for Ember and Handlebars regulars;
yaml-front-matter-brunch, which end up looking kinda like Jekyll;
swig-brunchfor Swig, for the Django fans out there;
nunjucks-brunchfor Nunjucks, and finally
- You’ll also find plugins that “statically” compile templates: this is for people who don’t want to have a vanilla HTML static asset, and would rather use an alternative syntax, possibly injecting a presenter in there from, say, a JSON file:
Brunch and development workflows
These days, web front dev is hard. We use a metric ton of different techs, want to debug in a snap, get a super-fast in-browser feedback loop, pay attention to performance, and so on and so forth.
There are many tools to help us get there, but having to manually install, setup and run these individually is a major PITA. Brunch can help, thanks to integration plugins.
jshint-brunchof course, that will run JSHint with current settings (e.g. coming from
.jshintrc) on all our applicative codebase (by default,
app). This can operate either in warning mode (log but don’t break the build) or error (stop the build). Runs in watcher mode as well.
coffeelint-brunchfor CoffeeLint, if you’re going with CoffeeScript.
jsxhint-brunchfor JSXHint, which can run JSHint over JSX without tripping over markup literals.
eslint-brunchfor ESLint, is also available.
- No integration for JSLint, but I sure won’t whine about that…
A fast feedback loop is a must-have when doing web front dev, that lets us see the result of our CSS or JS tweaks nearly instantly in our open browser(s). There are a few plugins for this, all designed to run in watcher mode:
auto-reload-brunchreacts to any change by live-injecting CSS changes if that’s all there is; it reloads the whole page if JS is involved. This relies on native Web Sockets, so IE10+.
browser-sync-brunchembeds the excellent BrowserSync, that lets you live inject CSS (no page reload), remote debug pages (embeds Weinre), sync a lot of interactions across open browsers (form filling, scrolling, clicking, etc.). Super handy to test responsive stuff (full disclaimer: I’m one of the maintainers of the plugin).
fb-flo-brunch, by yours truly, transparently embeds the awesome fb-flo, check it out now!
Code documentation isn’t forgotten either: several integrations let you regenerate docs at build time, to spare you an extra command line.
jsdoc-brunchnaturally, but also…
docco-brunch, for Docco, the tool that popularized annotated sources.
- I’d love to see someone contribute
groc-brunch, because Groc goes way beyond Docco!
There are also a number of plugins designed to replace keywords, markers or translation keys during the build:
process-env-brunchuses environment variables;
keyword-brunch(two variants) uses the global configuration to map keys and switch between its replacement behaviors;
jspreprocess-brunchadds a “C-style” preprocessor (with
#BRUNCH_IFdirectives inside comments) that lets you change the resulting code depending on the build target;
constangular-brunch, along the same lines, injects YAML-based configurations inside your AngularJS app as a specific module, in an environment-sensitive way (development, production);
yaml-i18n-brunchis a bit more specialized, and convertsYAML files into JSON, taking care to fill in the blanks in your locales from the default locale (assumed to be complete).
A few more plugins are worth mentioning:
dependency-brunchlets you tell Brunch about specific dependencies you have between source files, when it doesn’t auto-detect these, so that it triggers proper rebuilds. For instance, when Jade views extend a layout or include mixins, such dependencies can ensure you only need to change the layout/mixins for views that use them to get rebuilt.
groundskeeper-brunchstrips from your JS files anything that could hinder production:
debuggerstatements, specific blocks… (if minification is used, it must happen after this).
after-brunchprovides a simple way to register command lines for execution after a build, which lets you add custom tasks in a generic way!
Brunch and web performance
Brunch naturally cares about your performance, so it attempts to produce assets that are as optimized as possible, through third-party technologies. Most of these plugins are irrelevant in watcher mode, but are more targeted at one-shot production builds.
Let’s start with images:
retina-brunchtakes a high-res “Retina” image (one with
@2xin its name) and creates a lower-res variant for lower-DPI screens;
sprite-brunchrelies on Spritesmith to produce an image sprite and the matching CSS (using SASS, LESS or Stylus) from your source images. Not as versatile and powerful as Glue, but pretty good still.
imageoptmizer-brunch(notice the missing central
i…) runs in production/optimized mode to automatically run your target folder’s images through whatever relevant tools you have installed: JPEGTran, OptiPNG and SmushIt. For a systematic, express weight reduction.
We certainly have top-notch JS/CSS minifiers, too:
uglify-js-brunchuses UglifyJS 2 for badass reduction of target JS files;
clean-css-brunchrelies on CleanCSS, one of the best CSS minifiers out there (and if you want to play with the all-new more-css, feel free to contribute a plugin!).
- Let’s not forget
uncss-brunchuses the awesome UnCSS to detect unused code in our stylesheets; if you want to combine that with clean-css, you can either use both separately, or go with the
There are also a number of plugins designed to maintain a “fingerprint” on filenames, allowing for far-expiry caching, and to GZip your files for static gzipping (e.g. on nginx):
digest-brunchcomputes the fingerprint based on the file’s contents;
hg-digest-brunchuse the current commit’s SHA instead (which assumes you’re committing in a manner consistent with that).
gzip-brunchcompresses your finalized CSS/JS assets, either as copies (preferred) or replacements of your original files.
If you’re using AppCache (and until we can all get our hands on
ServiceWorker, you should!), there are a few useful plugins too:
appcache-brunchmaintains an up-to-date manifest, complete with the names of all files in the target folder, but also with a unique digest, so that if a source file changes, so does the manifest! Without that, invalidating the AppCache in dev quickly grows super tedious…
- In the same spirit,
brunch-signaturecomputes a digest from produced files and puts it in a static file of your choosing; you could then, for instance, do a low-frequency Ajax polling from your app to detect it’s changed and suggest a refresh.
- Still along these lines,
version-brunchauto-maintains a version number for your app, based on the one in your
package.jsonbut with an extra build number tacked onto it. It also puts it in a static file (that you can therefore poll), and auto-replaces specific version markers in all your produced files.
cloudfront-brunch is one of the plugins capable of auto-uploading your assets to an S3 bucket, and send the proper invalidation request to CloudFront, to boot. Sweet.