Getting Started with Brunch: The Ultra-Fast Simple-Config Build Tool

0
549

When it comes to build tools, web developers have a hard time choosing between Gulp, Grunt, Webpack, and Browserify to mention but a few. These tools are great helpers and they come with their own pros and cons. Unfortunately, a lot of time goes into learning, configuring and evaluating if the tool measures up to the task instead of actually coding.

Recently, I stumbled upon Brunch. Brunch is a build tool that has amazing capabilities which are provided out of the box performance. Brunch has actually been around before Grunt and Gulp, Unfortunately, it has not been marketed that much.

#What is Brunch?

Brunch is purely an asset build tool with almost zero-config, seamless incremental compilation meant for rapid development.

Brunch compiles, concats and minifies your scripts and stylesheets. It also packages JavaScript files into AMD or CommonJS modules. Furthermore, it automatically applies plugins in the correct order and to the right files with no explicit setup necessary.

Brunch comes pre-equipped with a number of behaviors and features which include:

  • Categorization of source files into either JavaScript, templates or stylesheet.
  • Smart concatenation of these files towards one or more target files.
  • Module wrapping of JavaScript files.
  • Minification of resulting files in production mode.
  • Watching of source files and updating builds on the fly.

#Why Brunch?

Brunch sets itself apart from other build tools through its technical and architectural aspects, which include in summary:

  • Speed and Simplicity
  • Configurations
  • Plugins
  • Commands
  • Live reload
  • Skeletons

Speed and Simplicity

Brunch was built for speed and simplicity.

One factor to consider when choosing a build tool is how fast it compiles or builds the project. A long build time is detrimental to a developer’s efficiency and performance.

Brunch uses pipelines instead of full builds. What this means is, when you make changes to a file, only the new content gets read and piped down to any number of processing avenues, be they sequential or parallel.

Moreover, Brunch goes a step further by using incremental build system and caching. Incremental builds are achieved by only rerunning the necessary build steps based on the detected changes, this immensely reduces the workload and time taken for a build to complete.

Here is an illustration of the Brunch pipeline.

Configurations

Brunch relies on configuration over code approach.

Configuration over Code approach reduces your configuration needs to the bare minimum, no code is needed. It also makes setting up the configuration easy and straight forward.

brunch-config. js or brunch-config.coffe is the config file used to manage the project. There are four main configuration properties that determine how Brunch will handle your project assets, these are:

  1. paths : Here you to specify a folder called ‘assets’ that is directly copied into your output folder(public) with no modifications.
  2. files : Most Brunch projects have two separate JavaScript files:
    • app.js, which contains your code, and
    • vendor.js for all external libraries, including bower packages.

    This allows you to package your files into modules without affecting external libraries.

  3. npm : Holds npm dependencies settings
  4. Plugins: Alters individual plugin settings.

Here is a sample of brunch-config.js file

module.exports = {
    paths: {
        public: '/user/www/deploy'
    },
    files: {
        javascripts: {
            joinTo: {
                'app.js': /^app/, // all js code from 'app/' ,
                'vendor.js': /^(?!app)/ // all BUT app js code - 'vendor/', 'node_modules/', etc
            }
        },
        stylesheets: {
            joinTo: 'app.css' /
        }
    },
    npm: {
        styles: {
            pikaday: ['css/pikaday.css']
        },
        globals: {
            Pikaday: 'pikaday'
        }
    },
    plugins: {
        on: ['postcss-brunch'],
        off: ['jade-brunch', 'handlebars-brunch'],
        npm: ['babel-brunch'],
        autoReload: {
            enabled: true
        }
    }
}

NB: Brunch has other settings but we won’t be discussing them for now.

Plugins

Brunch performs all transformations through plugins listed in package.jsons.

Commands

Brunch has three simple commands

  1. brunch new —> Creates a new project.
  2. brunch build —> Building and compiling the app’s assets.
  3. brunch watch —> Executes live builds and browser reloading.

Live reload

Brunch has built-in dev server with live reloads. Brunch automatic reloads the browser when using the brunch watch command.

Application Structure

Brunch has a simple application conventional structure which consists of an App folder which contains any files that will be served statically e.g index.html images, JavaScript, CSS, templates or media files.

├── README.md
├── app         // Files inside `assets` folder will be copied to the public` dir.
│   ├── assets
│   │   └── index.html
│   └── initialize.js
├── brunch-config.js             // Basic assumptions about the project, like paths & outputs.
├── package.json               // Describes dependencies and Brunch plugins your app uses.
└── public                   // The "output" Brunch will regenerate on every build.
    ├── app.js              //  was generated from `initialize.js`
    ├── app.js.map        // Source mappings for simple debugging.
    └── index.html      // This was copied from our `app/assets`

This structure allows Brunch to easily identify which files are part of our app and which files are external libraries without having to write any complex regular expressions.

Skeletons

A Brunch Skeleton is simply a boilerplate

  • Skeletons provide a good starting point for new applications. For example, if you are building a React application you might runbrunch new command and pass brunch/with-react as the repository option. This will clone your boilerplate fromgit://github.com/brunch/with-react.git.
  • Skeletons contain pre-required dependencies in package.json and providing a default Brunch configuration. Visit Brunch skeleton section to see a full list of available skeletons.

#Brunch vs Webpack

If you are a JavaScript developer you must be asking, “what is the difference between Brunch and Webpack?”

It’s all a matter of preference. Both tools almost do the same thing. The upside for using Webpack is its ability to asynchronously load modules and cleverly process non-js/non-CSS assets. Although Webpack has a large community and support, most people spend a lot of time trying to find ways to make the right configurations. Brunch shines when it comes to handling configurations. You do not need to specify how to compile a file, every time you use it, just add a compiler plugin and voila!! everything works.

#Setting up a basic Brunch project

Enough talking let us get started.

Prerequisites

We shall be setting up a simple project that uses ES6.

You need node and Brunch installed on your system.

To install brunch run

$ npm i brunch -g

#Creating the project structure

Creating a Brunch project structure is simple, we use the brunch new command.

In your terminal run the following command

$ brunch new myproject -s es6

This command does the following:

  1. It creates a folder called myproject
  2. Next, it clones our es6 skeleton. This creates our App folder and configuration files.
  3. Once the cloning is done npm install is activated, this installs app dependencies and brunch plugins

Our folder structure should look like this once the cloning is done.

myproject
├── README.md
├── app                             // Main folder that handles our source files
│   ├── assets
│   │   └── index.html             // Folder stores static files
│   ├── components
│   │   └── App.jsx               // Stores our React component and .jsx files
│   ├── initialize.js
│   └── styles                    // Will store all our styling sheets
│       └── application.css
├── brunch-config.js              // Maintains our project configurations
└── package.json                  // Holds plugins and project dependencies

#Project Configuration

Let’s have a look at the generated package.json

# package.json

{
  "name": "your-app",
  "description": "Description",
  "author": "Your Name",
  "version": "0.0.1",
  "repository": {
    "type": "git",
    "url": ""
  },
  "scripts": {
    "start": "brunch watch --server",
    "prod": "brunch build --production"
  },
  "dependencies": {},
  "devDependencies": {
    "auto-reload-brunch": "^2.0.0",
    "babel-brunch": "~6.0.0",
    "babel-preset-es2015": "~6.3.13",
    "brunch": "^2.4.0",
    "clean-css-brunch": "^2.0.0",
    "css-brunch": "^2.0.0",
    "javascript-brunch": "^2.0.0",
    "uglify-js-brunch": "^2.0.0" // default for all
  }
}

From package.json we can see the Babel ES6 transpiler has been installed through the Babel-brunch and babel-preset-es2015 dependencies. The other 5 dependencies are default dependencies that come with most skeletons.

 ....
  "auto-reload-brunch": "^2.0.0",       // adds automatic browser reloading support to brunch
    "brunch": "^2.4.0",                // Installs brunch locally
    "clean-css-brunch": "^2.0.0",   // CSS minifier
    "css-brunch": "^2.0.0",        // Provides CSS
    "uglify-js-brunch": "^2.0.0"  // JavaScript minifier

    .......

brunch-config.js does not need any configuration at this time. All the necessary settings are predefined. The file conforms to our discussion on configurations in the why brunch section

 # brunch-config.js
 module.exports = {
  files: {
    javascripts: {
      joinTo: {
        'vendor.js': /^(?!app)/, // Compiled from  js files except those in app folder
        'app.js': /^app/         // Compiles from all js files in the app
      }
    },
    stylesheets: {
    joinTo: 'app.css'  // compiled from css files in the app folder
    }
  },

  plugins: {
    babel: {presets: ['es2015']} // modifies es6 to es5
  }
};

NB: Brunch uses anymatch an npm module to match strings against configurable strings, globs, regular expressions or functions.

#Building the App

To build our project, open ‘myproject’ folder cd myprojectand run the build command.

 $ brunch build

brunch build compiles initialize.js into app.js and copies index.html into the public folder

 myproject
├── README.md
├── app
│   ├── assets
│   │   └── index.html
│   └── initialize.js
├── brunch-config.js
├── package.json
└── public
    ├── app.js          // compiled from app/initialize.js
    ├── app.js.map
    └── index.html // copied from app/assets/index.html

#Running our app

Time to see what we have built, run the watch command.

   $ brunch watch --server

The bundle watch command automatically & efficiently rebuilds the app on every change. Adding --server flag makes it launch a HTTPserver at http://localhost:3333.

Open your browser and navigate to http://localhost:3333

#Live Rebuild

So far nothing is displayed apart from the title. Open app/assets/index.html and add a header to the body and save it.


<!DOCTYPE html>
<!------- index.html----->
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
    <meta name="viewport" content="user-scalable=no, initial-scale=1,maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
    <title>Brunch with ES6</title>
    <script src="/vendor.js"></script>
    <script src="/app.js"></script>
    <script>
        require('initialize');
    </script>
</head>
<body>
    <div id="app"> <h2>Brunch is served</h2></div>
</body>
</html>

When the HTML file is saved, two things happen:

  1. On the terminal, a new log will notify us that compilation has taken place.
  2. The browser will display the header we just added.

Adding new dependencies

New dependencies added while the server is running are compiled effortlessly. There is no need of restarting the server.

Let’s install dimsum ( a random sentence generator library) and watch how Brunch will handle the new dependency.

While the server is running open a new terminal and run

$ npm install -S [email protected]

You will notice immediately the install happens Brunch starts compiling the new changes

Next let’s use the new library in our code. Open app/initializer.js and add this code, save and check the browser.

// app/initializer.js
var dimsum = require('dimsum');

document.addEventListener('DOMContentLoaded', () => {
  // do your setup here
  console.log('Initialized app');
        document.body.innerHTML += "Yeaah!! <div><p>" + dimsum() +"</p></div>";

});

Yeaah!! The browser instantly picks the changes.

That’s all you need!!! You are ready to build your awesome app.

#Conclusion

A recap of what we discussed:

  • Brunch was made for speed and simplicity
  • Brunch uses incremental builds instead of full builds
  • Brunch uses npm packages to run its plugins
  • Skeletons provides a good starting point for new applications
  • brunch new, brunch build and brunch watch --server are the only three commands that you need to get you started.
  • Brunch uses configuration over code approach
  • Live-build and live-reload make development workflow a piece of cake
  • Adding dependencies and plugins does not warrant you to restart your dev server when using Brunch

Brunch is a long time standing tool that does a job very well and if your project doesn’t require any special configuration or architecture it’s so easy to use.

I hope this inspires you to give it a try.

Suggest

The Complete Node.js Developer Course 2.0

Angular 2 (or 4) & NodeJS – The Practical MEAN Stack Guide

Beginner API development in Node, Express, ES6, & MongoDB 

LEAVE A REPLY

Please enter your comment!
Please enter your name here