Find file
46c8e71 Jan 4, 2017
@tdd @beznosd @samihda @paulmillr @alp82
156 lines (102 sloc) 19.1 KB

Plugins for all your build needs

This is part of The 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.

The official website has a decent list, based on authors’ pull requests, but there are actually a lot more; we’ll try and browse through the main ones below.

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 package.json and 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 npm install.

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 type of "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:

Brunch and JavaScript

This is a similar landscape to CSS, except type is now "javascript". I’ll talk about linters later, but sticking with transpilers we’re pretty well stocked already:

And just because this is 2017 after all, you’ll find a bunch of options for automatic JSX (React) processing and ES6 goodness:

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:

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.

Linters first:

  • jshint-brunch of 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-brunch for CoffeeLint, if you’re going with CoffeeScript.
  • jsxhint-brunch for JSXHint, which can run JSHint over JSX without tripping over markup literals.
  • eslint-brunch for 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-brunch reacts 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-brunch embeds 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-brunch naturally, 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-brunch uses environment variables;
  • keyword-brunch (two variants) uses the global configuration to map keys and switch between its replacement behaviors;
  • jspreprocess-brunch adds a “C-style” preprocessor (with #BRUNCH_IF directives 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-brunch is 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-brunch lets 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-brunch strips from your JS files anything that could hinder production: console calls, debugger statements, specific blocks… (if minification is used, it must happen after this).
  • after-brunch provides 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-brunch takes a high-res “Retina” image (one with @2x in its name) and creates a lower-res variant for lower-DPI screens;
  • sprite-brunch relies 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:

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-brunch computes the fingerprint based on the file’s contents;
  • git-digest-brunch and hg-digest-brunch use the current commit’s SHA instead (which assumes you’re committing in a manner consistent with that).
  • gzip-brunch compresses 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-brunch maintains 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-signature computes 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-brunch auto-maintains a version number for your app, based on the one in your package.json but 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.

Finally, 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.

« Previous: Web server: built-in or custom • Next: Writing a Brunch plugin »