Boilerplate web app using Backbone.js, ExpressJS, node.js, MongoDB

A boilerplate project for a complete web application written using Backbone.js & Marionette, node.js & ExpressJS, MongoDB & Mongoose, Handlebars, Grunt.js, Bower, and Browserify!

View eBook on Amazon!

Only $1.99!

Important Note: This article gets a ton of traffic, and the information here is a lot to consume. Please note that the article is over a year old now but the information is still relevant. Some things have changed, most definitely version numbers etc. I will be posting a pretty massive update to this article and the code repo in the coming weeks/months.

I created a super basic single page application (SPA) that is a simple Contacts manager. While this app is pretty simple, there’s actually a lot that’s involved. My goal with this article is to cover the entire stack of the application including; back-end, data, front-end, tools and testing. The stack consists of the following core technologies:

  • Back-end: node.js and ExpressJS
    • Testing: Mocha, Chai, Sinon, Proxyquire
  • Data Layer: MongoDB and Mongoose
  • Tools: Grunt, Bower and Browserify
  • Front-end: Backbone.js and Marionette.js
    • Testing: Jasmine, Karma, and PhantomJS

I’ll go into detail on each of the above components comprising the “full” stack. Again, because its such a simple app, not a whole lot of time will be spent covering the bells and whistles of the user interface or how the app works because that’s fairly obvious (nor did I spend a whole lot of time on the actual implementation, as I didn’t want it to distract from the core of the app). Instead, I’ll go into detail covering every aspect of how the app was built and the workflow process using the various tools.

The end goal is to have a code base to act as a boilerplate starter for any new projects down the road. The code should be fully functional and complete, yet easily digestible. Ultimately, after you read this article and have a solid understand of everything under the hood, you should be able to simply clone the repo and start building your app!

What you can expect from the remainder of this article:

  • Part 0: Project setup and dependencies
  • Part 1: Back-end – A simple node.js and ExpressJS server
    • node.js – initial setup
    • ExpressJS – routes/controllers
    • Handlebars – templates for rendering page views/layouts
    • Data layer – Mongoose and MongoDB:
      • MongoDB – server itself and how it works in the Express layer
      • Mongoose – Schema definitions for data models
      • Seeder – How we seed data when the app is run for the first time
    • Routes & Controllers – API layer called from the frontend
    • Testing with Mocha, Chai, Sinon, and Proxyquire
  • Part 2: Development Tools (Grunt, Bower, Browserify, TDD)
    • Grunt – Does all the things!
      • Initial configuration (load grunt tasks)
      • Clean
      • Bower installs
      • Browserify (vendor, shim dependencies, and app files)
      • LESS transpiling
      • Handlebars (precompiling / transform via Browserify)
      • Concatenation / Minification & Uglification / Copying
      • Watchers (for both backend and frontend rebuilds)
      • Karma commands/watchers
      • jshint
      • Concurrent tasks
      • Commands breakdown
        • init:dev, build:dev, build:prod, tdd, test:client, etc.
    • Bower – Manage front-end dependencies for the project
        bower.json explained
    • Karma/Jasmine – basic explanation of tdd tasks vs test:client (single run)
  • Part 3: Front-end – Contacts app with Backbone & Marionette
    • Browserify – why we are using Browserify and its benefits
    • Backbone / Underscore & Marionette
    • Contacts Application – introduction and basic explanation of the app
      • Core:
        • Marionette
        • Connection to the data layer to cache data
        • Router and Controller setup
        • Start!
      • Views:
        • Marionette.ItemView (versus Backbone.View)
        • Handlebar precompiled templates
      • Models / Collections
      • Controller calls to the API
    • TDD with Karma and Jasmine
  • Part 4: Deploy with Heroku!

Part 0: Project setup and dependencies

Before we can get started, lets make sure you have the project and can run it. First, you will want a copy of the project itself. The easiest way to download a copy is by cloning the repo locally using Git:

$ git clone git@github.com:jkat98/benm.git

If you don’t have Git installed or are unfamiliar with the concept, I strongly urge you to read some getting started articles (I wrote a pretty quick guide that should help!).

Once you have the project cloned to a local directory on your machine, you’ll want to make sure you have a few of the most basic requirements.

Install node.js and npm

If you don’t have node.js (and npm) installed already, do so by going to http://nodejs.org (npm is included by default with a standard node.js installation). Be sure to download the latest stable version (v0.10.24 as of the time of this writing).

Once you’ve installed node.js the easiest way to confirm that its working is by going to a terminal or command prompt and simply typing:

$ node --version

Assuming its working, you should simply get an output of “0.10.24” or whatever version you actually have installed.

Install the MongoDB server

Next you’ll want to be sure you have the MongoDB server installed on your machine. This is a pretty simple install, similar to node.js. You can find the appropriate download and installation files by visiting the downloads section of the MongoDB website: http://www.mongodb.org/downloads. Please do read the install/getting started docs as there are a few additional steps beyond installation. (i.e. creating/setting your data dir, etc)

Note: Installing MongoDB isn’t required, but most of the project won’t work unless you make some manual edits to remove the MongoDB/Mongoose stuff.

Install the Grunt CLI

One last tool that the project absolutely requires is the Grunt command line tool, which can be very easily installed via npm:

$ npm install -g grunt-cli

Note: doing a -g install with npm will install that package globally, meaning it is now installed on your machine and available everywhere. Without -g, the packages are only installed locally to the specific project or repo you are working with (and are stored in a node_modules directory within the project).

Mac users: a global npm install may require sudo for it to install properly.

Run the app!

So, assuming that all of the above was successful, you’re now ready to boot up the web app and take it for a spin! First you need to install all of the project’s dependencies (explained in more detail in the next section) and use Grunt.js to initialize the project and launch the server:

$ npm install
$ grunt init:dev
$ grunt server

Again, assuming everything is working correctly, Grunt should report that the server is up. You should have seen a lot of log output including the MongoDB server connecting, and some seed data inserted. Point your browser to http://localhost:3300 and the app should be up and running! Feel free to play around, click a Contact to view details, add a new Contact, etc.

Don’t worry about all the craziness that just happened – we’ll cover all of it!

Part 1: Backend – A simple node.js and ExpressJS server

Our server, which will be running in node.js, like any web server really has 2 main purposes. The first is that it should handle requests from a browser and serve up whatever files are requested. These files typically fall into 2 main categories: static files (JavaScript, CSS, HTML, images, etc.) and dynamic files (server generated HTML from templates). Because our app is mainly a thick front-end client the server side templates aren’t really necessary (as we could have just served a static html file). Support for Handlebars template rendering has been included in this project, however, so that this is a complete code base. Should you decide you want to create and host a more traditional website (i.e. no Backbone single page front-end) you can do so easily using Handlebars templates on the back-end alone.

The second thing our server should do is communicate with some form of data layer to persist data between visitor sessions. (i.e. you interact with the app, close your browser, come back and your work was saved and is presented back to you.) This is where MongoDB comes in – a noSQL database server that basically uses JSON to store all data.

Package.json – everything the project needs:

Before we can get started writing pretty much any server code, we need to make sure everything our server is going to need actually exists in our development environment. The easiest way to do this is to put together a basic package.json file that contains a list of all of the dependencies the server will require in order to function. As you determine what your server will need, and install them with npm, your package.json file will grow to account for these new dependencies.

Lets take a look at the file and explain some of what’s going on here:

{
  "name": "myapp",
  "description": "Boilerplate web app using node, express, mongodb, backbone, marionette.  Tooling includes Grunt, Bower, Browserify, etc.",
  "version": "0.0.1",
  "author": "Jason Krol",
  "repository": {
    "type": "git",
    "url": "https://github.com/jkat98/benm.git"
  },

1. The top most portion contains just standard descriptive stuff for the project. Pretty self explanatory.

  "engines": {
    "node": "0.10.x"
  },

2. The engines item just lists the necessary runtime needed in order to run this project, obviously this is node.js and its version.

  "scripts": {
    "start": "node server.js"
  },

3. Scripts just notes what the “run” command would be to start the project/server/app/whatever.

  "dependencies": {
    "express": "latest",
    "mongoose": "~3.8.3",
    "handlebars-runtime": "~1.0.12",
    "express3-handlebars": "~0.5.0",
    "MD5": "~1.2.0"
  },

4. Dependencies is a list of the absolute minimum required dependencies the project has in order for it to run properly. Without these, the server just won’t run.

  "devDependencies": {
    "bower": "~1.2.8",
    "grunt": "~0.4.1",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-jshint": "~0.7.2",
    "grunt-contrib-uglify": "~0.2.7",
    "grunt-bower-task": "~0.3.4",
    "grunt-nodemon": "~0.1.2",
    "karma-script-launcher": "~0.1.0",
    "karma-chrome-launcher": "~0.1.1",
    "karma-html2js-preprocessor": "~0.1.0",
    "karma-firefox-launcher": "~0.1.2",
    "karma-jasmine": "~0.1.4",
    "karma-requirejs": "~0.2.0",
    "karma-coffee-preprocessor": "~0.1.1",
    "karma-phantomjs-launcher": "~0.1.1",
    "karma": "~0.10.8",
    "grunt-contrib-copy": "~0.4.1",
    "grunt-contrib-clean": "~0.5.0",
    "browserify": "2.36.1",
    "grunt-browserify": "~1.3.0",
    "load-grunt-tasks": "~0.2.0",
    "time-grunt": "~0.2.3",
    "grunt-contrib-watch": "~0.5.3",
    "grunt-concurrent": "~0.4.2",
    "grunt-karma": "~0.6.2",
    "grunt-contrib-less": "~0.8.3",
    "grunt-contrib-handlebars": "~0.6.0",
    "grunt-contrib-cssmin": "~0.7.0",
    "hbsfy": "~1.0.0",
    "grunt-shell-spawn": "~0.3.0",
    "chai": "~1.9.0",
    "sinon": "~1.8.1",
    "sinon-chai": "~2.5.0",
    "grunt-simple-mocha": "~0.4.0",
    "proxyquire": "~0.5.2"
  }
}

5. DevDependencies is a list of all of the dependencies the project has for the purposes of development. This list is huge because most of it involves plugins for Grunt (that will be explained later). Also included is Bower, Browserify, Karma, etc. Again, a list of everything we need in order to develop against the project but not necessarily required for the project to just run.

So, with that package.json file in place the first step is to do a simple npm install to get all dependencies installed and ready to rock with our server:

$ npm install

This might take a few minutes as its downloading a fair amount of modules. Note, you probably did this step already if you completed the steps in Part 0 getting the project up and running.

If you are starting a new project, the easiest way to get started with your package.json file is to execute an npm init, which will take you through a few quick questions and then generate a new package.json file for you:

$ npm init

You could just hit return/enter on every prompt and be satisfied with a mainly empty but complete package.json file.

The node.js server with ExpressJS and Mongoose:

Let’s take a look at some pretty basic node.js code that will act as the main server. We’ll let ExpressJS do what it does best and handle a lot of the low-level stuff we just don’t want to worry about. We can then focus on configuration and creating the API routes that our front-end app will talk to.

Most of the directories within the root pertain to our node.js server. These include app, controllers, views, and views/layouts. The client directory is where all of our front-end code will reside and the public folder will be where its served from. Basically anything inside the public or views directories is visible from a browser, everything else is not.

---- app
---- controllers
---- views
-------- layouts
---- public
-------- js
-------- css
---- client
-------- requires
-------- spec
-------- src
-------- styles
-------- templates
---- spec
-------- app
-------- controllers

The core server file that will house the bulk of the node.js code (at least the boot-up code) will reside in a file called server.js. Lets take a look at that:

var express = require('express'),
    http = require('http'),
    path = require('path'),
    routes = require('./app/routes'),
    exphbs = require('express3-handlebars'),
    mongoose = require('mongoose'),
    seeder = require('./app/seeder'),
    app = express();

Here we are declaring a bunch of modules that are pulled in via node’s require function. Any items in a require() call that do not have ./ or ../ are modules that are being loaded in from the npm packages that were installed or from node.js itself (for example: http is a part of node.js core, express was installed via npm). The requires() that include a ./ or ../ are our own modules, which we will be defining in a bit.

Now that we have a bunch of modules ready to be used, lets look at some basic ExpressJS configuration code that boots up the server:

app.set('port', process.env.PORT || 3300);
// ...

app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.cookieParser('some-secret-value-here'));
app.use(app.router);
app.use('/', express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
    app.use(express.errorHandler());
}

This code is pretty standard ExpressJS stuff. Each of the app.use calls is loading some form of ExpressJS middleware. These are basically plugins that handle a lot of stuff we just don’t want to have to worry about! The last app.use() (before the // development only comment) is setting the public folder to be a static folder, which means Express will serve files in that folder as is (and won’t do anything to them other than serve them).

Handlebars templates for serving dynamic HTML pages

app.set('views', __dirname + '/views');
app.engine('handlebars', exphbs({
    defaultLayout: 'main',
    layoutsDir: app.get('views') + '/layouts'
}));
app.set('view engine', 'handlebars');

We are initializing our view engine with Handlebars and setting it to point to our views directory. Its common you might see Jade being used instead as its a popular template engine, and I do like Jade (especially its concise HTML syntax which looks like Zen coding). However, I wanted to use Handlebars instead so that the template language was the same on the back-end and front-end. The server side Handlebars templates are stored in the views directory and subsequently the layouts stored in a layouts directory. The syntax to use Handlebars on the back-end is pretty much identical to that of the front-end!

The Data layer with Mongoose and MongoDB:

So far so good. The last thing left to do is include a connection to our database server. The database server we are using for this project is MongoDB – a noSQL JSON based data store. In my opinion, using MongoDB with a full stack JavaScript project like this is a no-brainer so it was the obvious choice for me to use. Your mileage may vary.

Getting started with MongoDB:

If you are unfamiliar with MongoDB, here’s a super quick crash course. Assuming you have MongoDB installed on your machine, you can start the server by simply typing the command mongod at any terminal or command prompt:

$ mongod

In another terminal or command prompt, use mongo to enter the MongoDB shell:

$ mongo

This will change your prompt as you are now using the MongoDB shell. A few quick commands:

  • show dbs – displays a list of available databases on the system.
  • use databasename – switch to existing databasename (or create it if it doesn’t already exist)
  • db.things.find() – list all records in the “things” collection of the currently active database (set with ‘use’ earlier)
  • db.things.insert({ a: 1, b: 2, c: 3}) – insert a new record into the ‘things’ collection with the object provided.
  • db.things.find({a : 1}) – return a list of all records that has the property a with a value of ‘1’
//connect to the db server:
mongoose.connect('mongodb://localhost/MyApp');
mongoose.connection.on('open', function() {
    console.log("Connected to Mongoose...");

    // check if the db is empty, if so seed it with some contacts:
    seeder.check();
});

The node.js driver we are using to connect to our MongoDB server is Mongoose. There are a number of node.js drivers available that work with MongoDB, but I like Mongoose because of the schemas that you can use with your models. (Coming from a “Code First” .net development background personally, this was the most direct comparison when I was learning node.) In our server.js file we just include a small chunk of code that connects to the MongoDB server using the Mongoose driver. Note that the connection url to the MongoDB server is “mongodb://localhost/” followed by the name of the database to connect to. The beauty of MongoDB is that if a database doesn’t exist when its attempted to be connected to, one is created automatically!

Once the connection is established, we run a simple seeder check function that basically checks to see if this is the first time we are running the app – if so it throws a few records into the Contacts collection (a.k.a “table”) so the app isn’t completely empty the first time its run. This isn’t necessary, but just makes for a nice initial impression on first use.

Seeder module:

The seeder object is actually a great introduction to modules in node.js. If you go back to the very top of server.js you’ll recall we included a bunch of require() statements. This is where we take modules in node.js, either those that come with node, those we’ve installed via npm, or our very own, and include them as regular JavaScript variables that we can work with later in our code. Lets look at the seeder module and see what its doing:

var mongoose = require('mongoose'),
    models = require('./models'),
    md5 = require('MD5');

module.exports = {
    check: function() {
        // ...

Here we include a few requires() again, fewer this time since this is a specific module and only needs to do what it does and depends on only a few things; namely Mongoose, our data models, and MD5. (MD5 is only used to generate hash values that Gravatar uses for their images.) The more important part is the module.exports line – which exports a JavaScript object that basically has 1 property function called ‘check’. Check() will check to see if there are any records in the Contacts collection, if not it will just insert a bunch of sample records to start with.

API Routes and Controllers:

//routes list:
routes.initialize(app);

//finally boot up the server:
http.createServer(app).listen(app.get('port'), function() {
    console.log('Server up: http://localhost:' + app.get('port'));
});

Finally, now that our server code is all set up and we have our connection to our database server, the last thing to do is get our routes ready and then start the server!

var home = require('../controllers/home'),
    contacts = require('../controllers/contacts');

module.exports.initialize = function(app) {
    app.get('/', home.index);
    app.get('/api/contacts', contacts.index);
    app.get('/api/contacts/:id', contacts.getById);
    app.post('/api/contacts', contacts.add);
    app.put('/api/contacts', contacts.update);
};

 

module.exports = {
    index: function(req, res) {
        res.render('index');
    }
};

We’re using a 1:1 relationship with a router and controller in this project, so if you take a look at the routes.js file in the app/ dir, you’ll see that its pretty basic. It’s literally just defining all of the endpoints for our API layer that the server will respond to when calls are made from the front-end layer. The actual implementation for each router is defined in the controllers module which can be found in controllers/*.js. Again, noting the requires() at the top of the routes.js file, we include our own modules by referencing ../controllers/file (no .js). One thing to note is that our home controller only has an index which returns a rendered Handlebars template (as noted by the res.render(‘index’)). The contacts controller returns pure JSON results – different results depending on the URL being requested.

The most important controller is the contacts controller (controllers/contacts.js). This is the one that the front-end actually talks to to get the initial collection of contacts, retrieve an individual contact’s full details, as well as add new contacts and update existing contacts. Each of the functions in contacts.js is mainly doing Mongoose inserts/updates/gets against the MongoDB server.

Data Models:

The last piece of our server code is our data models. Our data models are objects where the data schema has been defined. If you look at the app/models.js file you will see a few requires() at the top (specifically Mongoose, Schema, and ObjectId – all related to Mongoose). We define a Contact model which is just a new data schema and the properties defined (and of what type). Finally we export an object that contains a property specifically for the Content model. We do it this way so we can define our entire project’s data schemas and return them all via the primary “models” module. Let’s say in addition to Contacts, we also wanted to store a collection of our favorite books. In the models.js file we would declare another var of Book that = new Schema({}) and inside the object define the properties for each Book (i.e. Title, Author, Description, ISBN, etc). Then in the module.exports after the Contact: line we simply put a , and then Book: mongoose.model(‘Book’, Book);. Then everywhere that we’ve already included var models = require(‘./models’) will instantly also have our Book model as well. You don’t have to include all of your models in 1 file/module this way – its just the way I did it for this project (and probably would work well for most projects unless you had a very large amount of models).

var mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId;

var Contact = new Schema({
    email:      { type: String },
    name: {
        first:  { type: String },
        last:   { type: String }
    },
    phone:      { type: String },
    gravatar:   { type: String }
});

module.exports = {
    Contact: mongoose.model('Contact', Contact)
};

Our entire server consists of just 6 small .js files, most of which have very few lines of code. All of that serves up a fully functional web server with a database connection and data CRUD logic!

Testing node with Mocha, Chai, Sinon, and Proxyquire

We are using a few different tools on the server side to handle testing of our node code. Primarily we are using Mocha, combined with a Grunt mocha runner to execute our tests. The tests themselves are written using Chai as the assertion language, Sinon for spies and stubs, and Proxyquire to do a little magic when it comes to the idea of “fakes” in the node world.

To run the tests for the code, execute the following command:

$ grunt test:server

This will execute the mocha runner, and all of the tests we have in the spec folder will be run. You should see the output for each test right in your terminal, hopefully with green checkmarks all the way down the list.

The tests are organized in a similar fashion to the app itself, with an app and controllers folder.

To learn more about testing with node.js, checkout my other post that goes into more detail.

Part 2: Development Tools (Bower, Grunt, Browserify)

Now that the server has been covered, and before we can get to the front-end app, I want to go over the suite of tools that were used during the development of this app.

Bower – Front-end dependency management

Bower is a great little tool! Its basically what npm is to node. Using Bower you can quickly and easily install any front-end dependencies required by your project. Typically, in the past, whenever we wanted to use something like jQuery, underscore, Backbone.js, etc. we always went to the libraries website or GitHub repo (many times one in the same), found the download link, saved a copy of the .js file somewhere in our project, and then added a reference to that file in our main layout. With Bower that process is a whole lot easier.

Like most things done with node, Bower depends on its own bower.json file. This is going to be very similar to the existing package.json (explained earlier) file.

{
  "name": "myapp",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "backbone.marionette": "~1.4.1",
    "jquery": "~1.10.2",
    "underscore": "~1.5.2",
    "backbone": "~1.1.0"
  },
  "devDependencies": {
    "jasmine": "~1.3.1"
  },
  "exportsOverride": {
    "jquery": {
      "js": "jquery.js"
    },
    "underscore": {
      "js": "underscore.js"
    },
    "backbone": {
      "js": "backbone.js"
    },
    "backbone.marionette": {
      "js": "lib/backbone.marionette.js"
    },
    "jasmine": {}
  }
}

Both the dependencies and devDependencies sections are defined. With those defined, you could simply execute ‘bower install’, and like ‘npm install’ it would download the files listed that were predefined in the bower.json file (without having to manually install each).

The exportsOverride section simply defines how the files are going to be organized when they are installed from the ‘bower_components’ to the ‘client/requires’ directory. Note that Jasmine has nothing defined which means it will not be copied over during the client requires phase. This is because the clients don’t need to load the Jasmine library when the app is run on the front-end, Jasmine is simply for testing during local development.

If you were starting a fresh project from scratch and wanted to include jQuery into your project simply install it via Bower:

$ bower install jquery

While you’re at it – lets assume you want Backbone.js and underscore.js as well:

$ bower install backbone
$ bower install underscore

Then, all you need to do is add a reference in your main layout file to bower_components/jquery/jquery.js!

Of course, wouldn’t it be nice if it were even easier than that…

Grunt.js – Task runner to do all the things

Grunt.js is pretty much the shit. The sheer volume of plugins available for it is overwhelming. To that end, however, actually understanding and getting started with Grunt can be really confusing if its not clearly defined why you actually need to use it.

Lets take a step back and look at what a typical development workflow could be without any automated task runners (like Grunt) to take care of the bulk of it:

You have all of your frontend files organized in a way that you’re happy with. You may have many many files for many different reasons – Backbone models, views, collections, routers, controllers, etc. On top of that, you’ve decided that you want to use LESS to write your CSS – cause you’re fancy and everyone else is using it. Being a good web developer, you ultimately want your project .js files to all be concatenated into a single file, ideally compressed (and uglified so people can’t make any sense out of your source code and steal your work). Obviously your LESS files shouldn’t be served up to the browser as is – they need to be converted to normal .css files as well. On top of all of that, you practice TDD so you want your tests for your frontend code to run regularly as you make changes to either the application code or the tests themselves. Furthermore, you need to actually start up your node.js server so you can view the app in a local browser – and any time you make changes to the node code, you need to restart the server. Last but not least – all of those tasks are for a single test run of your app. You would have to repeat most of that every time you make any changes.

O_o Thats a lot of stuff to worry about! That’s where Grunt comes in to save the day. Using Grunt you can create an automated “script” that is run every time you edit certain files or make any changes. With this automated process, running something like “grunt server” can do the following:

  • Bower install any of your frontend dependencies
  • Concatenate all .js files into a single file (including those Bower dependencies)
  • Compress (minify) that single .js file and also uglify it
  • Transpile LESS files into a single .css file
  • Copy those 2 files to a public folder that your app index.html file actually references
  • Launch Karma and execute your suite of tests
  • Start up your node server
  • Do ALL of the above every time any of the appropriate files are modified
    • Make a change to any .js file – Concatenate, Compress, and Copy are rerun. Tests are also rerun.
    • Make a change to any .LESS file – Transpile and Copy are rerun.
    • Make a change to any of your server specific node.js files – restart the node server
  • On top of that, you can run some other handy items like jsHint so all of your JavaScript is instantly checked for syntax errors.

So now a typical development work flow would look a little more like:

  • Launch “grunt server”.
  • Do work.
  • Refresh browser.*

*Note: you could event get fancier and use a Live reload plugin and remove that last part!

Pretty awesome huh?! All the countless b.s. you worry about is thrown right out the window and forgotten about, all so making a website can get out of the way of making a website!

Let’s take a look at the Gruntfile.js we created for this project. Warning – its pretty big so we’ll tackle it in chunks.

module.exports = function(grunt) {

    require('time-grunt')(grunt);
    require('load-grunt-tasks')(grunt);

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

This is just the most basic part of the Gruntfile. It basically just uses node’s module.exports to return a Grunt function, which you then launch using initConfig() passing in configuration object. The first 2 items are additional requires for 2 Grunt plugins that are very handy. The more important one is the load-grunt-tasks. Typically with a Gruntfile you need to manually specify all of the tasks that you are going to be using a plugin for. This handy little plugin automates that by reading your package.json file and looking for any plugins in the dependencies and devDependencies list that start with “grunt-” and loads them automatically! That gets a big part of the config work out of the way.

Next up we run Grunt’s initConfig function and configure our entire script. The very first line we read in the main package.json file for user a little later – most specifically we’ll be taking the name of our project from the package file and using that to name some of the files that we create during our build process.

Bower install

Read the bower.json file and install any front-end dependencies.

        bower: {
            install: {
                options: {
                    targetDir: 'client/requires',
                    layout: 'byComponent'
                }
            }
        },
Clean

Any temporary build folders we maintain should be cleaned before each build (so theres no leftover files lying around). The ‘build’ command cleans the entire ‘build’ directory. The dev command cleans a specific list of files (i.e. doesn’t delete the vendor.js file since that typically never changes). Finally, the ‘prod’ command will clean out a directory called ‘dist’ which is what we would use to distribute our app when its ready for release. (This directory would typically only contain 2 key files, myapp.js and myapp.css – plus any necessary images.)

       clean: {
            build: ['build'],
            dev: {
                src: ['build/app.js', 'build/<%= pkg.name %>.css', 'build/<%= pkg.name %>.js']
            },
            prod: ['dist']
        },
Browserify

This is a biggie – and not to be taken lightly. Browserify is a pretty amazing tool, which basically allows you to use modules in your front-end code in the exact same way that you do in node.js on the back-end. What this means is that you can use the exact same coding habits and styles in the full stack. Browserify allows you to build your front-end code in a modular style, and only pull in dependencies in areas of your app as you need them. On top of that, the Browserify Grunt plugin will merge all of the app and vendor files together into a single respective file for each. (So if you had 5 vendors and 20 app files, you would wind up with only a single vendor.js file and a single app.js file.)

The browserify config block is broken into 3 main sections; vendor, app, and test. The vendor file will take all of the frontend dependencies defined from Bower and Browserify them and then merge them into a single vendor.js file. App will do the same for your core app files. Notice that with the app section, we only define main.js (and not an array of all of our .js files). This is because the way Browserify works, it will basically crawl your entire app and everywhere it finds require() functions will load in those dependencies as needed. node.js works pretty much the same way.

Additionally you can shim vendors, defining the dependencies that they themselves have. So, for example, with Marionette you can define that it depends on jQuery, Backbone and underscore. This way, in your frontend app .js files, you need only require(‘backbone.marionette’) and it will automatically include jQuery, underscore, and Backbone without you having to manually require those as well!

Finally, Browserify will also find all requires() that specifically point to front-end Handlebars templates and automatically precompile them into JavaScript functions. This will speed up the front-end rendering process significantly for users since the view templates aren’t being rendered during runtime (which is how Handlebars typically works).

        browserify: {
            vendor: {
                src: ['client/requires/**/*.js'],
                dest: 'build/vendor.js',
                options: {
                    shim: {
                        jquery: {
                            path: 'client/requires/jquery/js/jquery.js',
                            exports: '$'
                        },
                        underscore: {
                            path: 'client/requires/underscore/js/underscore.js',
                            exports: '_'
                        },
                        backbone: {
                            path: 'client/requires/backbone/js/backbone.js',
                            exports: 'Backbone',
                            depends: {
                                underscore: 'underscore'
                            }
                        },
                        'backbone.marionette': {
                            path: 'client/requires/backbone.marionette/js/backbone.marionette.js',
                            exports: 'Marionette',
                            depends: {
                                jquery: '$',
                                backbone: 'Backbone',
                                underscore: '_'
                            }
                        }
                    }
                }
            },
            app: {
                files: {
                    'build/app.js': ['client/src/main.js']
                },
                options: {
                    transform: ['hbsfy'],
                    external: ['jquery', 'underscore', 'backbone', 'backbone.marionette']
                }
            },
            test: {
                files: {
                    'build/tests.js': [
                        'client/spec/**/*.test.js'
                    ]
                },
                options: {
                    transform: ['hbsfy'],
                    external: ['jquery', 'underscore', 'backbone', 'backbone.marionette']
                }
            }
        },
LESS

Transpile any .less files to .css and put the .css file in the build directory named ‘myapp’.css. Not only should this file consist of all .less files, but also any other .css files that exist and are required by our vendor dependencies (jQueryUI, reset.css, etc).

        less: {
            transpile: {
                files: {
                    'build/<%= pkg.name %>.css': [
                        'client/styles/reset.css',
                        'client/requires/*/css/*',
                        'client/styles/less/main.less'
                    ]
                }
            }
        },
Concat

Concatenate all of the .js files into a single file. Take the vendor.js file and app.js file (both created by Browserify) and merge them into a single file named ‘myapp’.js. Put this final single file in the build directory.

        concat: {
            'build/<%= pkg.name %>.js': ['build/vendor.js', 'build/app.js']
        },
Copy

When we are running our Grunt server in dev mode, copy the files from the build directory to the destination that they must reside so that our front-end app can see them and our server can serve them. A different directory for .js files, .css files, and image files. (Take a look at the main.handlebars layout file in server/views/layout/ and you will see where the final .js and .css files are included into the layout.)

        copy: {
            dev: {
                files: [{
                    src: 'build/<%= pkg.name %>.js',
                    dest: 'server/public/js/<%= pkg.name %>.js'
                }, {
                    src: 'build/<%= pkg.name %>.css',
                    dest: 'server/public/css/<%= pkg.name %>.css'
                }, {
                    src: 'client/img/*',
                    dest: 'server/public/img/'
                }]
            },
            prod: {
                files: [{
                    src: ['client/img/*'],
                    dest: 'dist/img/'
                }]
            }
        },
cssmin

Remove all white space from our .css file and make it as compressed as possible. By default this is only set for production runs of our app (since during development, it might be nice to still be able to read the final .css file if you inspect it by viewing the source in a browser).

        cssmin: {
            minify: {
                src: ['build/<%= pkg.name %>.css'],
                dest: 'dist/css/<%= pkg.name %>.css'
            }
        },
uglify

Do the same for our main .js file, remove any white space and trim variable names and comments. Make the file as small as possible while still functional. Again, this only occurs during a production run (as during development, while debugging in the browser etc., we still want to be able to read the .js file).

        uglify: {
            compile: {
                options: {
                    compress: true,
                    verbose: true
                },
                files: [{
                    src: 'build/<%= pkg.name %>.js',
                    dest: 'dist/js/<%= pkg.name %>.js'
                }]
            }
        },
watch

Watch all files for any time they get modified. When they do change, execute pre-existing Grunt tasks already defined (most explained above). Watched client/src/*.js files will rerun the Browserify tasks, watched .less files will rerun the transpile step, then all of the necessary copies and repeat every time a file is modified.

        watch: {
            scripts: {
                files: ['client/templates/*.hbs', 'client/src/**/*.js'],
                tasks: ['clean:dev', 'browserify:app', 'concat', 'copy:dev']
            },
            less: {
                files: ['client/styles/**/*.less'],
                tasks: ['less:transpile', 'copy:dev']
            },
            test: {
                files: ['build/app.js', 'client/spec/**/*.test.js'],
                tasks: ['browserify:test']
            },
            karma: {
                files: ['build/tests.js'],
                tasks: ['jshint:test', 'karma:watcher:run']
            }
        },
nodemon

The same as watch, except for the server related .js files. Whenever a node.js file is changed on the server, restart the server so the latest version is running.

        nodemon: {
            dev: {
                options: {
                    file: 'server/server.js',
                    nodeArgs: ['--debug'],
                    watchedFolders: ['server/controllers', 'server/app'],
                    env: {
                        PORT: '3300'
                    }
                }
            }
        },
shell

This is just a simple command line execution. Specifically, launch the ‘mongod’ server command whenever the main server starts (since they must both be running for the app to work properly).

        shell: {
            mongo: {
                command: 'mongod',
                options: {
                    async: true
                }
            }
        },
concurrent

Concurrent means that you can execute a number of “blocking” tasks asynchronously at the same time. For dev the tasks that are run are the nodemon watcher for the server, mongod server for the database, and watcher for the front-end scripts, less, and tests. Without concurrent, typically only one of these would be able to run before it sits and waits and causes Grunt to hang and be blocked before it could execute all of the other necessary tasks that must all run parallel to each other simultaneously.

        concurrent: {
            dev: {
                tasks: ['nodemon:dev', 'shell:mongo', 'watch:scripts', 'watch:less', 'watch:test'],
                options: {
                    logConcurrentOutput: true
                }
            },
            test: {
                tasks: ['watch:karma'],
                options: {
                    logConcurrentOutput: true
                }
            }
        },
karma

Tasks specific to running the Karma test runner and watcher. We’ll touch more on this in a little bit.

        karma: {
            options: {
                configFile: 'karma.conf.js'
            },
            watcher: {
                background: true,
                singleRun: false
            },
            test: {
                singleRun: true
            }
        },
jsHint

Run jsHint syntax checking on all necessary .js files.

        jshint: {
            all: ['Gruntfile.js', 'client/src/**/*.js', 'client/spec/**/*.js'],
            dev: ['client/src/**/*.js'],
            test: ['client/spec/**/*.js']
        }

And that concludes the initConfig block for our Gruntfile.js! Thats a lot, and typically it could get a whole lot longer as you automate all the things and make your life easier. The amount of time you spend configuring your Gruntfile in the beginning will save you 10 fold during the lifetime of your project development. Not to mention freeing up head space to not have to worry about all that stuff.

Now that all of that is out of the way, we need to setup some simple command line commands that you can execute when starting Grunt to actually do all of this stuff!

    grunt.registerTask('init:dev', ['clean', 'bower', 'browserify:vendor']);

    grunt.registerTask('build:dev', ['clean:dev', 'browserify:app', 'browserify:test', 'jshint:dev', 'less:transpile', 'concat', 'copy:dev']);
    grunt.registerTask('build:prod', ['clean:prod', 'browserify:vendor', 'browserify:app', 'jshint:all', 'less:transpile', 'concat', 'cssmin', 'uglify', 'copy:prod']);

    grunt.registerTask('server', ['build:dev', 'concurrent:dev']);

    grunt.registerTask('test:client', ['karma:test']);
    grunt.registerTask('tdd', ['karma:watcher:start', 'concurrent:test']);

Each tasks ‘register’ is pretty self explanatory, but basically you register a task by first giving it a name, which you execute by:

$ grunt mytask

Where ‘mytask’ can be anything you want. Following the name of your task in the registerTask() is an array of tasks you want executed, all defined in the ‘initConfig’ earlier.

init:dev – the task that is executed the first time you want to start working with the project. This will do a Bower install, copy those files to the client_requires folder, and run Browserify for the vendor file. The reason this only needs to execute once at the beginning of development is that your Bower dependencies typically won’t change all that much, so there’s no reason to do a Bower install every single time you make changes to your app files.

build:dev – this does most of the work. This is executed every time you run grunt server. This handles the tasks that are repeated every time you make a change and need to rebuild all of your files.

grunt server – the brains of the operation. This is the command you will execute the most often. It does a build:dev, and then concurrent:dev which launches all of the watchers and servers.

Finally test:client and tdd both launch Karma and run the tests, the only difference is that ‘test:client’ runs once, and ‘tdd’ will run Karma in auto watch mode – rerunning the tests any time the app.js or tests.js files are modified.

TDD with Jasmine, Karma, and PhantomJS

I’ve touched a bit here and there on Karma and TDD in this article so far, but haven’t really explained any of it. That’s because I’ve already written a pretty thorough article covering that in greater detail which you can read here! Suffice it to say that TDD (Test Driven Development) is fairly important. The basic idea behind it is that you have a suite of tests written that check against your actual code. Should you make tweaks or changes to your core code which inadvertently breaks something, your tests will alert you immediately! If you’re not doing TDD regularly, I strongly suggest you consider looking into it and at least giving my other article a read through.

Part 3: Front-end app with Backbone.js & Marionette.js

Now its time to go into detail covering the build of the actual front-end app. The app itself is a very rudimentary and basic app that manages a list of Contacts. The app presents a collection of contacts as small “cards” with a name, email, and Gravatar image. Click a card to get a full details view for the contact. You can also add New contacts and update or delete existing contacts. Its no “To Do” app, but it gets the job done!

A note about Browserify
As covered earlier in the Gruntfile.js configuration section, we are relying heavily on Browserify for the front-end portion of the app. This is simply because I really like the way Browserify works and I love that it makes coding on the front-end feel exactly like coding on the back-end. Previously I wrote an article discussing using Backbone.js with require.js – but for the purposes of this project I decided to change it up and try something different. Turns out I personally like working with Browserify a lot more than my initial experience with require.js. That being said, if you’ve never worked with node.js before or any other kind of modular front-end development framework, it can all seem pretty confusing. I suggest you give my earlier article a read as the topics and concepts covered translate pretty much the same between require.js and Browserify.

Main.js and App.js – boot up and brains

var App = require('./app');
var myapp = new App();
myapp.start();

Main.js is exactly what it sounds like – the main JavaScript file. This file is small, but it boots everything up! The very first thing it does is, using Browserify, require our main app object (located in app.js). With that object we can create a new instance and officially start the app.

app.js is also exactly what it sounds like – its basically our entire app, well sort of. Its really the brains that coordinates all of the moving parts of the app from this central location. Lets break down app.js and see what its really doing.

var Marionette = require('backbone.marionette'),
    Controller = require('./controller'),
    Router = require('./router'),
    ContactModel = require('./models/contact'),
    ContactsCollection = require('./collections/contacts');

Looks pretty familiar right? Here we are declaring the dependencies for our main app.js file and stating that we are going to be working with Marionette, our Controller, Router, Contact model, and Contacts collection. Each of these modules (except Marionette) are our own files which will be explained in a bit. Note that Marionette depends on jQuery, underscore and Backbone but we didn’t need to require any of those because they are done so via the dependencies shim defined in the Browserify config in our Gruntfile.js.

Next an empty function is created and exported via the module system. Even though its empty, that function object is then immediately prototyped with a function called “start” that does all the work.

module.exports = App = function App() {};

App.prototype.start = function(){
    App.core = new Marionette.Application();

Inside App.start() four important things occur:

  • Create a new Marionette.Application()
  • bind an event to initialize:before
  • bind an event to app:start
  • Start the Marionette app!

The 2 events that are bound to are not actually triggered until the Marionette app starts (which is why App.core.start() is called last). Lets look at each of those events now:

initialize:before

    App.core.on("initialize:before", function (options) {
        App.core.vent.trigger('app:log', 'App: Initializing');

        App.views = {};
        App.data = {};

        // load up some initial data:
        var contacts = new ContactsCollection();
        contacts.fetch({
            success: function() {
                App.data.contacts = contacts;
                App.core.vent.trigger('app:start');
            }
        });
    });

This event will occur first, immediately before the app is actually started. You can refer to the Marionette documentation on what events are available and the order in which they execute. Here initialize:before happens before app:start – so we define what we want to happen before our app starts. Specifically we create a few cache objects on the App itself (views and data), and fetch our contacts data from the server. Once the fetch is complete, we actually trigger app:start.

app:start

    App.core.vent.bind('app:start', function(options){
        App.core.vent.trigger('app:log', 'App: Starting');
        if (Backbone.history) {
            App.controller = new Controller();
            App.router = new Router({ controller: App.controller });
            App.core.vent.trigger('app:log', 'App: Backbone.history starting');
            Backbone.history.start();
        }

        //new up and views and render for base app here...
        App.core.vent.trigger('app:log', 'App: Done starting and running!');
    });
    // ...
    App.core.start();

Inside app:start, basically we create a new instance of the app’s controller and a new instance of our router, and the router takes the controller as a part of its constructor. Both of these are Marionette objects (explained in a bit). In this project, our front-end router and controller work almost exactly the same way as their counterparts on the back-end with the node.js router and controller. The only difference is that the node.js router manages actual URLs visitors can hit on the server – and the Marionette router manages the routes in the URL that can be hit while the front-end app is running. Think of Backbone or Marionette routes as being something like a DOM event but the DOM element is the window.location bar. If the URL in the Browser’s address bar changes, trigger a route event in the app. (Not actually try to load a new page like a normal URL.)

Marionette Router and Controller

As you saw in app.js, we defined new instances of a Router and Controller in the app:start event. I also mentioned that they work almost exactly the same way as the node.js counterparts.

router.js

var Marionette = require('backbone.marionette');

module.exports = Router = Marionette.AppRouter.extend({
    appRoutes: {
        '#'  : 'home',
        'details/:id' : 'details',
        'add' : 'add'
    }
});

The router.js file is pretty simple – create a Marionette AppRouter object and assign a collection of appRoutes. These appRoutes will match 1:1 with functions of the same name in our Controller object. Here we have the root url for the app ‘#’, which points to the ‘home’ function in the Controller. Then there’s ‘details/:id’ which is the URL for a contact’s details view and that points to the ‘details’ function in the Controller. Finally we have ‘add’ which points to the ‘add’ function in the Controller.

controller.js

    home: function() {
        var view = window.App.views.contactsView;
        this.renderView(view);
        window.App.router.navigate('#');
    },

The controller acts as the actual logic pertaining to our Router. As we mentioned earlier, the router and controller have a 1:1 relationship which means that every route defined in our router pertains to a function defined in our controller. Each function in the controller takes care of rendering the screen for each route. Using the ‘home’ function as an example, we create a new view, include a model if we are viewing a detail view, and then render it calling the controller’s renderView function. The renderView function will first destroy an existing view if it has already been rendered. This is to take care of event handling and make sure we don’t have zombie views and/or event handlers sticking around.

Models and Collections

var Backbone = require('backbone');

module.exports = ContactModel = Backbone.Model.extend({
    idAttribute: '_id'
});

 

var Backbone = require('backbone'),
    ContactModel = require('../models/contact');

module.exports = ContactsCollection = Backbone.Collection.extend({
    model:  ContactModel,
    url: '/api/contacts'
});

This simple app has a single, basic model – the Contact. In addition there is a single collection of Contacts. Both are defined in their respective directories in the ‘src’ directory. You can see that the url for the collection has been set to that of our API. In addition, because we are using MongoDB we manually point the id attribute of our model to the _id field, which MongoDB uses by default as a unique identifier.

Views

There are 3 primary views for this application, a small contact “card” that appears as a collection on the homepage, the full details of a contact, and an add new contact form.

views/contacts.js

The contacts view file actually contains 2 views, a Marionette ItemView which is the individual “card” for a contact, and then a Marionette CollectionView which is just a collection of the “card” views for the collection of contacts. The contacts CollectionView has a listener on its collection for any change events, and if that happens the collection view is re-rendered. This is so that any new contacts added to the main collection will be rendered after they are added.

var Marionette = require('backbone.marionette');

var itemView = Marionette.ItemView.extend({
    template: require('../../templates/contact_small.hbs'),
    initialize: function() {
        this.listenTo(this.model, 'change', this.render);
    },
    events: {
        'click': 'showDetails'
    },

    showDetails: function() {
        window.App.core.vent.trigger('app:log', 'Contacts View: showDetails hit.');
        window.App.controller.details(this.model.id);
    }
});

module.exports = CollectionView = Marionette.CollectionView.extend({
    initialize: function() {
        this.listenTo(this.collection, 'change', this.render);
    },
    itemView: itemView
});

The ItemView itself simply has an event that will trigger the ‘details’ function in the controller. The ItemView also has a listener to its model so that if the details for a contact are changed, the view is re-rendered as well. Notice that the ItemView has a template defined as a Handlebars template and that its being referenced via a require(). Browserify will effectively replace that line with a precompiled javascript function of the template during build time. This will make view rendering much faster versus relying on the browser to do the compilation every time a view is rendered.

views/contact_details.js

The details view for a contact is pretty simple – just an event handler for going “<< Back” and a Handlebars template.

views/add.js

Finally we have the view that renders a form that is used to insert a new contact. The big piece of functionality here is the save function:

    events: {
        'click a.save-button': 'save'
    },

    save: function(e) {
        e.preventDefault();
        var newContact = {
            name: {
                first: this.$el.find('#name_first').val(),
                last: this.$el.find('#name_last').val()
            },
            email: this.$el.find('#email').val(),
            phone: this.$el.find('#phone').val()
        };

        window.App.data.contacts.create(newContact);
        window.App.core.vent.trigger('app:log', 'Add View: Saved new contact!');
        window.App.controller.home();
    }

Here we are defining a new contact that is just a generic JavaScript object that matches what our data objects look like on the MongoDB side. Then we simply pass that into Backbone’s collection.create() function – which will, using the default implementation of Backbone, make a POST call to the API url (defined in the collection earlier) passing the JSON object for the variable that was defined. Back on the server side, the node.js router has a listener for a POST to ‘api/contacts’ which calls the ‘add’ function in the (node.js) controller. The server’s contacts controller ‘add’ function will create a new contact model using Mongoose and save it to the MongoDB server:

    add: function(req, res) {
        var newContact = new models.Contact(req.body);
        newContact.gravatar = md5(newContact.email);
        newContact.save(function(err, contact) {
            if (err)
                res.json({});
            console.log('successfully inserted contact: ' + contact._id);
            res.json(contact);
        });
    },
Important Note about Validation:
Its important to note that none of the front-end or back-end code does any kind of validation. This is obviously bad, but I omitted any simply to make the code more concise and easier to digest. This would be implementation that you will want to take care in your actual app. (And is always a good idea to validate on both the back-end and front-end to be safe!)

View Templates with Handlebars

As I mentioned earlier when I covered the back-end, the template engine we decided to use for both back-end and front-end is Handlebars. I did this to both keep things consistent and because I’m a fan of Handlebars. You can find the view templates in the ‘client/templates’ directory. Each is basically an HTML document with a .hbs file extension.

Part 4: Deploy with Heroku!

From here, we have a completely functional app, albeit a bit basic. The best way to test it, and the most logical next step, is to deploy it so its actually on the Internet! A fantastic service that is both free and super easy to use is Heroku! Heroku is basically a cloud based scalable hosting solution with a ton of amazing features and support for add-ons. Its an obvious choice for hosting an app like this. Lets take a look at the steps involved in launching the app.

Register a free account at Heroku.com

If you don’t have an account with Heroku, go there now and register a free account. It takes 2 seconds…

Download the Heroku Toolbelt

Once you have an account, make sure to download and install the Heroku Toolbelt, a command line tool that makes creating apps and pushing code to Heroku a breeze!

Create a Heroku app, Install Add-ons, and push your code live

Now that you have a Heroku account and the Toolbelt installed, you’re ready to create an app under your account, prepare the app, and push your code live. Along the way you’ll install a few Add-ons as well.

Note: All of the following commands should be executed from the root of the project directory.

$ heroku login

After logging in, you may be prompted to add SSH keys. Follow the directions as you go.

Next create a file named ‘Procfile’ and put the following single line of code in it:

web: node server.js

Create an app under your Heroku account:

$ heroku create

Next we need to install the first add-on for the app, MongoHQ. MongoHQ is another cloud based hosting service specifically for MongoDB that works extremely well with Heroku. Like Heroku, MongoHQ has a sandbox level service that is absolutely free!

$ heroku addons:add mongohq

Note: In order to actually use add-ons, you will need to be sure your account has complete billing information. This is only because most services are scalable and have limited terms. Should you exceed those terms then billing would kick in.

Next go to the Heroku website and access your dashboard/Apps. Click on the app that was just created, and then click on the MongoHQ Add-on. Go into the Collections and add a collection for your app (i.e. “contacts”). Then go into Admin and select the Users tab. Create a new user to access the database (give it any username/password you want). Switch back to the Overview tab and copy the Mongo URI.

Edit server.js and the line that connects to the mongodb server will need to be changed to the Mongo URI that was just copied. Change the <user> and <password> to the MongoHQ user that you just created.

Now we can push our code up to Heroku:

Note: Before you push your code to Heroku, because it uses Git to do so, you want to make sure that any changes you’ve made up to this point have been staged and committed (i.e. that change you just made to server.js for your MongoHQ connection URI). The easiest way to do that is with the following commands:

$ git add .
$ git commit -m "Updates for Heroku"
$ git push heroku master

Now that the app is setup, add-ons installed, and code pushed up we need Heroku to actually launch our server. To do this Heroku uses something called a dyno which will read the Procfile and execute its command:

$ heroku ps:scale web=1

Finally, launch your new Heorku app in a browser:

$ heroku open

Conclusion

For what appears to be a seemingly small app, there was a lot to cover. This boilerplate project should act as a great foundation for any future projects you want to quickly get up and running. Without having to worry about all the nuts and bolts that go into a standard web project, your time is freed up to worry about actually making the app!

If you have any questions at all about this project, please feel free to post a comment or hit me up on Twitter. Also, any suggestions or recommendations would be greatly appreciated! Thanks for reading, hope you find the code useful – now go build something!

Like this post? Want to show your support?

Wow! You made it this far! Long post huh? Well it took a while to create! I hope you liked it though. If so, I would really appreciate you showing your support:

Buy the book on Amazon.com! For only $1.99 you can buy the eBook (mobi) version for your Kindle!

Leave a review on Amazon.com! If you don’t want to spend any money (because well you just read the whole thing for free) why not leave a review anyway?! It would help me out greatly and anyone else interested in reading it that might find it on Amazon.

Thanks!!

96 thoughts on “Boilerplate web app using Backbone.js, ExpressJS, node.js, MongoDB

  1. Jason,
    I was struggling with how to structure my express app until I read your approach to having the router invoke controllers. It really makes the code much easier to understand and read.
    I’ve just knocked an app together using your code as a template and it works a treat.
    Thanks for posting it!

    Like

    • Thanks for reading! Coming from a .net MVC background, when I got into node and found that it was just so open and literally had no boundaries, I felt it needed some structure. The MVC style approach seemed to work really well and I like working with it. I apply the same approach to the frontend with Backbone and Marionette, and Marionette is almost identical with its router/controller pairing!

      Like

  2. Hi,

    Thanks for the great tutorial. The one thing I don’t understand though, is the difference between the express routes and the backbone routes. What’s the difference between routing things server-side (Express) versus client-side (Backbone). I guess I’m just not sure about exactly how you’ve done that. Or, maybe I have a real misunderstanding of what you’ve done.

    Thanks for the help!

    Like

    • The express routes are actual full fledged urls that are triggered by the browser making a full page request to the server. Typically the browser hits a URL and sends a request to the server saying “hey, send me the page!” and the server responds in kind. The routes on the frontend are different – in that the browsers currently loaded page isnt changing in the sense that its sending a request for a new page to the server. But instead is telling the browser to trigger an event. You can think of routes in Backbone as something no different than an onclick in jquery. Onclick of this button, make a div appear = jquery events. On url change in the location bar, make a div appear = backbone routes.

      Like

  3. From the line: grunt server and even before I knew it was an awesome stack,
    Thanks that someone has made such a perfect tutorial, I have been spending the last two weeks, trying one stack and the other, every single one of them was missing some information that made so I coulnd t make the database work properly, or various errors but this is just insane, dead simple, Probably saved at least another 2 weeks trying to figure out and make these modules work properly together.

    Like

  4. This was hugely helpful. I have 2 questions.
    1) If I want to use this boilerplate to correctly/effectively start a new project. What would the steps be?
    2) What sort of tweaks would be required to have this app update the contact list in one window if a new contact were added in another window. Is there a simple socketio replacement that makes the browser aware of changes on the server?

    Like

    • hey, thanks!
      1. that part is a little tricky. Your best bet is to try to get familiar with git/github – as bringing down a copy of the project repository is literally one command (git clone repo_url). There is a link in the post as well as on the homepage of another featured article I did covering getting started with Git (on Windows, but the topics apply to pretty much any OS). Hope that helps you get started!

      2. Im actually going to try implementing Backbone.ioBind (http://alogicalparadox.com/backbone.iobind/) which sounds like it would be exactly what you’re looking for (uses socket.io and replaces the Backbone.sync implementation). Will hopefully have that up some time early next week.

      Like

    • Hmm good question. It certainly wasnt designed to be production code by any means, nor a full fledged contacts app. Its a boilerplate so its really just a starting point. At 1000+ contacts the way the app is designed initially is to load the entire app db into memory as a Backbone collection. I can’t see that being very efficient from a memory management standpoint. Pagination would very much need to be implemented – both in the frontend and backend. MongoDB itself can certainly handle that kind of data, but Indexing will most definitely need to be implemented (for speed of search results).

      Like

  5. Great post! It’s helping me a lot in my project to learn nodejs and the modern web development tools. I’ve forked the project in GitHub and I’m very excited to start a new application based in this boilerplate. Thanks a lot!

    Like

  6. Jason, great assembly of tools, similar to what I was cooking up. I ran into a seemingly weird problem I have not had time to get to the bottom of yet:
    installing all as is and running grunt server starts up fine, the browser complains about “Uncaught Error: Cannot find module ‘backbone.marionette’ ” even though it is in the myapp.js file.
    Have you encountered that before ?

    Great job!

    Like

    • Yes! And I’m not exagerating I spent probably 5 hours banging my head against a wall trying to figure it out. In the end it came down to being really careful and explicit about how the shimming is defined for Browserify and the dependencies list specifically for Marionette. Take a close look at both my Gruntfile.js and specifically the package.json file that has the browserify shim sections defined. Actually, on second thought if you fork my repo, specifically checkout the gulp branch where I started experimenting with gulp. That branch has a more improved implementation of the Grunt and browserify shims. Hope that helps!

      Like

      • Yes I forked this, and love it! I started with gulpjs, I went ahead and picked up grunt for this tut, then thankfully found out about your branch. I’m glad I did because gulp is so much better IMO. I struggled just like you guys for over 5 hours banging my head as well. It would compile the script properly until I did a little messing around then the compiled script would get messed up. It’s running smooth using gulp, I love it. I’m new to github in terms of contributing but if I put together some gulpjs code I’ll share.

        Like

  7. Hi, Jason! This is very good tutorial! I’m now trying to do all the things as you wrote here with my existing project. Doing refactoring I’ve encountered several problems like that I have different pages and had to browserify boundless for each one with its own scope of the vendors libs and scripts. Yet the more tough is to set up the external dependencies while testing with the karma. All because karma has its own plugin karma-browserify(https://github.com/xdissent/karma-browserify), which worked for me with the only browserify-shim (https://github.com/thlorenz/browserify-shim) extension. This extension accepts the options provided in package.json while grunt-browserify takes them from Gruntfile.js. I assume that I’m missing something in my approach. So how do you have a deal with the external libraries ?

    Like

  8. Hi Jason, just bought the book, and it’s great. Is there a quick way to enable ejs for templates? I’d like to use that instead of handlebars. I’ve removed all references to handlebars and installed ejs, but get an error “ParseError: Unexpected token <" in the ejs template. The '<' char is referencing the opening bracket of a div element. This occurs when I try to launch the grunt server command.

    The server.js shows app.set('view engine', 'ejs'); and ejs is in the node_modules folder. Any thoughts where troubleshooting might begin?

    Like

    • can you try just running node server.js to rule out Grunt doing anything fishy. If that throws the error its likely just a weird syntax error with the ejs file. Maybe mismatched tags? Or you arent closing a properly? Honestly I havent really worked with ejs its usually been Jade or Handlebars, so Im not quite sure what the problem is. If you have a repo up Id be more than happy to take a peek though 😉

      Like

      • Thanks for writing this post! It really has saved me MASSIVE amounts of time. I think I’m just going to have to learn handlebars and all the benefits that come with it. Thanks for your reply.

        Like

  9. Thanks a lot for this tutorial and even got the kindle version! I am totally novice concerning node.js, I followed your instructions (I believe) but cannot go further than $ npm install after $ npm install -g grunt-cli. It gives me the following error message:
    npm ERR! install Couldn’t read dependencies. I read the section concerning dependencies, but don’t know if I have to copy all the lines and put in package.json, and then put it at the root of my project.
    Now $ npm install passed, but then $ grunt init:dev produces the message: A valid Gruntfile could not be found….

    What should I do?
    Thanks a lot for your advice.

    Like

    • Can you confirm that you cloned the repo properly from github? When you view the contents of the project in your environment the files listed should match those that are listed in the actual repo up at github.com (link very top of the article). Sometimes npm wont install the dependencies correctly and you might need to use sudo (especially for a global install like grunt-cli).

      Like

      • Wait, does the book really mention the AnimationFramework repo?!? I sure as heck hope not! The repo you want to clone is at the top of this article: https://github.com/jkat98/benm.git That should clone into a benm folder, and from there npm install, grunt init:dev, grunt server should do the trick. (no need for sudo in Windows)

        Like

      • Thks again, and I can feel the passion you have beyond your technical expertise… it’s great! Using the link you gave me in the reply, everything works, even though I had an issue with grunt.cmd, but it is fixed when I added it manually in the PATH.

        Like

  10. Hi Jason,

    I have just got your book from amazon and was trying out your setup. I got stuck at the demo. It looks like the routes are not firing i.e. when i click on add contacts or contact list nothing happens. Can you let me know what the issues is thanks 🙂

    Like

    • Unfortunately not really sure. The demo works for me and many other people and this is the first I’m hearing of that issue. Have you taken a look at the browser console and see what errors occur if any whenever you click add etc?

      Like

      • I get this error, cannot call method Defered of undefined, which looks like it cant find jquery. I have checked the files in the require folder and it is there.

        Like

  11. Hi Jason… thanks for writing this post. Quick question – for the client side, where do you put the handlebars helpers and how would you define a simple helper?

    Like

    • Specifically on the client side of this project. Where do we define the handlebars helpers and what do we require? I bought your book and it is great.

      Like

      • Sorry for the delay in responding! You could create a new file and call it handlebars_helpers.js and put the following in it:

        var Handlebars = require(‘hbsfy/runtime’);
        Handlebars.registerHelper(‘breaklines’, function(text) {
        if (text) {
        text = text.replace(new RegExp(‘r?n’,’g’), ”);
        }
        return text;
        });

        Then in a view that you want to use the helper, require the file at the top:

        require(‘../handlebars_helpers’);

        Then just use the helper in your template file:

        {{{breaklines model.description}}}

        For this particular example, the helper will convert line breaks in a description to actual HTML breaks.

        Like

    • I’m having the same issues. I purchased the Kindle version and was able to download the repo the first time. However, I got all kinds of errors and “node install” so I deleted the repo and tried to download again. Now it ask’s for username and password. So I saw this post and get this message:

      $ git clone git@github.com:jkat98/ben.git

      Cloning into ‘ben’…

      Permission denied (publickey).

      fatal: Could not read from remote repository.

      Please make sure you have the correct access rights

      and the repository exists.

      Like

      • That was the problem a typo. Thanks. BTW I still could not compile I think because I had multiple versions of Visual Studio. So I installed on CentOS VM and everything worked great.

        Like

  12. Hi Jason,

    First time I am seeing such a nicely engineered and practically usable node project.

    How I can integrate an authentication module using PassportJS and Marionette in this application?

    Thanks,
    Sandesh Magdum

    Like

    • Feel free! The Handlebars templates on the node side are rendering basic HTML, but the sky’s the limit with regard to what you can actually render. Add a bunch of routes and controllers on the node side to render more pages on the server and just strip out the entire client folder basically.

      Like

  13. Hey, its truly an awesome learning post. Thanks a lot for this. I have worked on Angular JS alone but now my idea of UI has completely changed.

    The only doubt i have is, the entire setup done above is for Development Environment. If i want to place the same code for production environment, which all files to copy and move. Also my hosting provider provides MySQL as the database. Can you tell me how can i configure Mongo over a server so that the website uses it.

    Like

    • Hi! Thanks for the feedback. There typically isnt going to be an easy way for you to configure Mongo on a regular hosting account. Its either going to be available as an option or something you can enable via some sort of Control Panel. Node and Mongo both seem to be not the norm when it comes to hosting plans like GoDaddy or Dreamhost et al. I think this is because they typically dont run in a shared environment very well (versus LAMP which runs very well in a shared hosting environment). That is why I went into detail on the article about using Heroku. Another great alternative is a service called DigitalOcean.com – they provide VPS servers for as little as 5 bucks a month! Using that service you can preconfigure a server with the MEAN stack but then just write your app using my repo (Angular isnt a server side depencency so I thought it was kind of odd that they referenced MEAN as a server setup – but whatevs).

      Like

  14. Jason…Thanks for this wonderful tutorial. Can you please let me know how do I debug this code in my local? Now all the files are minified and I am unable to debug this code. Please help.

    Like

    • Because this is just a scaffolded project, its still going to need some tweaks. One of the most obvious is to remove the minify and uglify steps from the grunt build tasks and instead push them off to another task thats specifically for production. An example would be that grunt build:dev performs everything necessary except the minify and uglify. Then grunt build:prod would do the same exactly steps as grunt build:dev AND also include minification and uglification.

      Hope that makes sense/helps?

      Like

  15. Hi Jason. Thanks for this awesome stack and the explanation of it. I am fairly new to backbone and node. I was wondering why this setup does not like res.redirects? For instance I want to test if a user has a session and redirect them back to (‘/’); however the call returns 200 and says that it is successful but the view does not update. Can you give me some insight why this might be or a better way to handle this situation?

    Like

    • Hey Nigel, Its probably because most of the routes are being called via frontend ajax requests. In a situation like that you could do 2 things – either setup a special route and view on the node side and start the app out with a login screen. Or you could res.json a special response that indicates the user isnt logged in and check for that in the backbone app. Most likely before any other requests are sent (i.e. before it attempts to retrieve any account specific data etc). You could even use a statusCode like 401 (Unauthenticated). So from the frontend in the app.js most likely, send an ajax request to a /authenticate route, maybe passing username and password. if that route returns a 401 you know to not proceed any further and redirect from the backbone app to another page that prompts to login.

      Like

      • Thanks for this reply that is awesome! Last thing is it possible to take the frontend aspects of this kind of framework and export it with something like PhoneGap? Or is this not feasible?

        Like

      • Very feasible – likely even. Ive used a similar app (on the frontend) with a Phonegap app. The process is a little different since you need to bundle all the things when you ship your “package” along with the app, but using the Grunt tasks and Browserify to create a single “app.js” file really makes a lot of sense when working with a mobile HTML app and using PhoneGap to make it native.

        Like

  16. Hello Jason,

    I have really enjoyed looking over your boilerplate app. This is best tutorial on these technologies that I have found to date. I would love to see your take on splitting myapp.js (public folder) into a manageable file structure with separate files for Backbone routes, views, models, collections, etc.

    Cheers,
    Jeremy

    Like

    • Are you referring to the idea that the code files are all maintained separately? That is how they are originally, and only bundled into myapp.js as a build step using Grunt. That step could easily be skipped, the only downside (albiet a major one) is that youd have to maintain the list of source script files to be loaded into the index.html file – and this list would continue to grow and likely become a source of pain for you as a developer.

      Like

  17. Hi,

    one question. How did you get that file/folder structure in the part where you’re talking about:

    The node.js server with ExpressJS and Mongoose.

    I mean how did you get this:

    —- app
    —- controllers
    —- views
    ——– layouts
    —- public
    ——– js
    ——– css
    —- client
    ——– requires
    ——– spec
    ——– src
    ——– styles
    ——– templates
    —- spec
    ——– app
    ——– controllers

    Like

    • If by how did you get you mean where did it come from? Simply create the folder structure – it doesn’t actually come from anywhere, just needs to exist that way. Another solution is to just download the entire codeset from github using the link at the top of the article.

      Like

  18. Hi Jason,

    I was struggling by the installation of your app.

    When I execute: grunt init:dev, I´ll get the followings messages.

    module.js:340

    throw err;

    ^

    Error: Cannot find module ‘lru-cache’

    at Function.Module._resolveFilename (module.js:338:15)

    at Function.Module._load (module.js:280:25)

    at Module.require (module.js:364:17)

    at require (module.js:380:17)

    at /usr/local/bin/benm/node_modules/grunt/node_modules/minimatch/minimatch.js:35:11

    at Object. (/usr/local/bin/benm/node_modules/grunt/node_modules/minimatch/minimatch.js:1051:3)

    at Module._compile (module.js:456:26)

    at Object.Module._extensions..js (module.js:474:10)

    at Module.load (module.js:356:32)

    at Function.Module._load (module.js:312:12)

    Can you give a tip for this issue?

    Thanks, traulfs

    Like

    • Its possible your npm install got borked somehow – thats an odd error. I would try this from your project root:

      $ rm -rf node_modules && npm cache clean && npm install

      Which will simply delete your node_modules folder, and reinstall the modules agin. Separately, I would double check to make sure grunt-cli was installed globally via:

      $ npm install -g grunt-cli

      Hope that helps!

      Like

      • Hello Jason,
        Thanks, for your fast reply.

        But now I have an issue if I start the server.

        I´ll get the following output:

        MacBook-Pro-TR:benm thorsten$ sudo grunt server

        Running “clean:dev” (clean) task

        Running “browserify:app” (browserify) task

        >> Bundled build/app.js

        Running “browserify:test” (browserify) task

        >> Bundled build/tests.js

        Running “jshint:dev” (jshint) task

        >> 9 files lint free.

        Running “less:transpile” (less) task

        File build/myapp.css created.

        Running “concat:build/.js” (concat) task

        File “build/myapp.js” created.

        Running “copy:dev” (copy) task

        Copied 2 files

        Running “concurrent:dev” (concurrent) task

        Running “watch:test” (watch) task

        Waiting…Running “watch:scripts” (watch) task

        Waiting…Running “shell:mongo” (shell) task

        Done, without errors.

        Execution Time (2014-07-29 18:27:47 UTC)

        loading tasks 1.9s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 99%

        Total 1.9s

        Running “nodemon:dev” (nodemon) task

        Running “watch:less” (watch) task

        Waiting…29 Jul 20:27:49 – [nodemon] v0.7.10

        29 Jul 20:27:49 – [nodemon] to restart at any time, enter `rs`

        29 Jul 20:27:49 – [nodemon] watching: /Users/thorsten/benm/controllers

        29 Jul 20:27:49 – [nodemon] watching: /Users/thorsten/benm/app

        29 Jul 20:27:49 – [nodemon] starting `node –debug server.js`

        debugger listening on port 5858

        Server up: http://localhost:3300

        events.js:72

        throw er; // Unhandled ‘error’ event

        ^

        Error: failed to connect to [localhost:27017]

        at null. (/Users/thorsten/benm/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:546:74)

        at emit (events.js:106:17)

        at null. (/Users/thorsten/benm/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:150:15)

        at emit (events.js:98:17)

        at Socket. (/Users/thorsten/benm/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:533:10)

        at Socket.emit (events.js:95:17)

        at net.js:440:14

        at process._tickCallback (node.js:419:13)

        29 Jul 20:27:50 – [nodemon] app crashed – waiting for file changes before starting…

        Like

      • Was this issue ever addressed? I’m currently experiencing this problem. 3 Jan 16:52:12 – [nodemon] app crashed – waiting for file changes before starting…

        Thanks!

        Like

      • The first stackflow link had nothing useful. However, the second one was most helpful. Thanks! If I had paid more attention to the error “Error: failed to connect to [localhost:27017]” I would have seen that that is the mongo default port. So, starting my mongo server fixed it. I’m also sure that if had read the book, rather than jumping ahead to install and run the app without background information I would not have had a problem. Lesson learned: Buy the book. It’s worth it.

        Like

  19. Hi Jason,

    Thanks for this awesome stack and the great explication. I am using your boilerplate to build a web app, but I am confused about how the views / templates are rendered. Can you give me more details about how this process works? I mean, how to organize the code between each following directories : /views, /views/layouts, /client/views, /client/templates… An simple example could be a great reply 😉

    Thanks a lot!

    Like

    • Hi Grégory!

      I can see how that can be confusing. So the basic premise is that theres an MVC like design pattern in both the backend and frontend. The root views/ and views/layouts/ are the html templates for the “pages” that will be rendered and served by express. Think of these as traditional HTML pages that a server renders and serves up. if you wanted, you could build a completely flat standard website and use only these views to render the HTML for your site.

      On the other hand, the client folder is where ALL of the backbone code lives. So the client/views are actually Backbone “views” and the client/templates are where the HTML templates for those views live. Here is where it could become confusing because Backbone has a different opinion of what a view is versus Express (Express considers views simply HTML pages whereas Backbone considers Views almost more like ViewModels where they take care of rendering the HTML and as such typically require an HTML template counterpart.

      Hope that makes sense?

      Like

      • Hi Jason,

        I’m facing issues using your boilerplate. Actually, I need to get some advices to organize my code for specifics functionalities, and to stay homogeneous.

        Firstly, I’ve got some Backbone “views” that contain a form, in which I want to include two input fields of type=”file” in order to upload images (with some transformations to have thumbnail image for example), and .pdf attachements. Those images + pdf files have to be attached to a particular mongoose schema.

        Secondly, I’ve got one Backbone “view” that also contain a form, but with one input field of [ type=”file”, multiple ] to upload csv files. The goal is to provide a solution to populate the database via mongoose with the data from csv files.

        So, my questioning is about to found a way to manage all the forms ‘homogeneously’ within the Backbone app or/and Express app along with validations, transformations, and database manipulation. Do you have some advices and tools to give me in order to achieve my goal and use as best as possible the boilerplate?

        One more question, which solution will you consider to store uploaded files (images, .pdf)? Given that a lot of files will be added in the future. Amazon S3?

        Thanks a lot!

        Like

      • I’ve been working on a similar project recently where a backbone view has a file input field, and I upload the file via ajax and then store the file using S3. I havent completed it yet, but the path Im going is to store the file locally first, then transfer it via S3 using the AWS SDK (or the s3 npm module) and then delete locally. The mongodb record would then only contain a pointer to the file (most likely unique filename). As for your other questions, they are pretty broad and probably beyond the scope of anything I could answer using the comments system 😉 The only piece of advice I can give you is good luck! LOL. Honestly dont get hung up on if youre doing it right or not – just do it and get the app working and then you can always iterate and refactor as you learn and find mistakes here or there. I found that if I worry too much early on if im “doing it right” I just wont get done and Ill wind up restarting too many times and get frustrated.

        Like

    • Correct..ish. The routes in Express explicitly are setup for / to serve the index.handlebars and its main layout couterpart. Because the app is designed as a single page application (where only 1 page will ever be served and loaded from the server) the main layout file actually hosts the myapp.js file, which is the concatenated file to rule all files – that is that its the 1 file that is the merged result of every single .js file within the client folder (thanks to Browserify and Grunt’s concat). If you look here: https://github.com/jkat98/benm/blob/master/views/layouts/main.handlebars#L17 you can see the .js file reference. That file includes main.js which is the only .js file in the entire client folder that actually triggers live JavaScript functions (i.e. it launches the app and everything else that happens after that is a direct result of myapp.start() within main.js -> https://github.com/jkat98/benm/blob/master/client/src/main.js#L3)

      Like

      • Ok that is starting to make sense after tracing around in the code you have on git. Still not clicking on how the client directory is used and what code in node js calls the main.js which calls start on the marionette app. Tracing node js it looks like when ‘/’ is called it routes to controllers/homes.js where it calls render on “index” which goes to /Views/index.handlebars correct? This doesn’t seem to really have anything in it to render.

        Like

      • Its going to be tricky to make sense out of it by looking at the github repo alone – thats because the entire build and most of public are not under source control (because they are built at runtime). So in that regard, the entire myapp.js file doesnt exist in the repo (so while your looking for where main.js shows up or is referenced, you wont find it).

        You seem to have it though – the node.js route listens for the ‘/’ route, and when caught fires the controllers/home.js index function. That function renders /views/index.handlebars (and by default every view inherits views/layouts/main.handlebars as a layout wrapper). The index.handlebars page literally only contains a div that the app will evetually get injected in via Backbone. The main.habdlebars has all the boilerplate layout code as well as a script tag at the bottom that references myapp.js. Interestingly enough that file doesnt exist, until you run the grunt build:dev command which literally creates that file from scratch. That file, contains all of your js include the main.js contents (which ultimately fires the app.start()).

        Like

      • I forgot to mention that you dont need to run grunt build:dev manually as running grunt server takes care of that for you – running it once by default before starting the server as well as constantly watching any of your files for changes and re-building the myapp.js file every time.

        Like

  20. Hi, I am trying to install your project on my machine and run it. I already installed git, node, npm, and MongoDB.

    From the command line, in the directory where I cloned your repo to, I do:

    npm install
    grunt init:dev
    grunt server

    Everything seems to go well until this appears (see image, please)

    No idea what that means… Help please!

    Like

    • Hi, This error specifically means that mongodb isnt currently running on your system. The easiest solution is to open another terminal session and just start mongodb by executing c:/wherever_mongodb_is_installed/mongod (if youre on windows) and then in the other terminal window do the grunt server command.

      Like

  21. Is there a reference like a book or something that goes through the process of setting up a stack like this in more detail and at a beginners level? Thanks.

    Like

  22. Great work! I have it up and running and I’m able to make some changes for my app, but I’m still confused on a lot of points that I’m having to go elsewhere on the internet to figure out. It would be really helpful for your readers to have a few extra paragraphs talking about how you can change routes, create new models, etc. Or perhaps even a 2nd post teaching how to take this boilerplate and make common changes.

    Like

  23. Jason, I like your project. I used this as my cheatsheet for my personal projects and I referred my friends to this article too. But It has been lots of upgrades for NodeJS, Browerify etc. do you think you can update this to article to latest dependencies?

    Like

  24. Jason,

    Great tutorial! I already bought your book on amazon and right now I would like to setup a project withouty the back end but just a nodejs server serving the front end since I already have an back end api running on another serve. Could you walk me through?

    Thanks

    Like

  25. Hi Jason

    I successfully setup your project. But I’m a bit confused about adding other client modules. I tried to add “blueimp-gallery” with bower install. After that I get an error in myApp.js “cannot read property helper of undefined” (code snippet: factory(window.blueimp.helper || window.jQuery,window.blueimp.Gallery);) How do I get the blueimp as a browser global?

    Best, C

    Like

  26. Hi Jason

    I successfully setup your project. But I’m a bit confused about adding other client modules. I tried to add “blueimp-gallery” with bower install. After that I get an error in myApp.js “cannot read property helper of undefined” (code snippet: factory(window.blueimp.helper || window.jQuery,window.blueimp.Gallery);) How do I get the blueimp as a browser global?

    Best, C

    Like

  27. “This event will occur first, immediately before the app is actually started.” This statement refers to the initialize:before event. I don’t think this event occurs first before the app actually starts. From what i can see in the Marionette.js source code, it is one of the events(functions) that is triggered(called) when a Marionette applications starts. The actual order of things is 1. initialize:before. 2. initialization. 3. Initialize before. 4. OnStart.

    But then i love this tutorial and am definitely using your framework for my next project.

    Like

  28. HI Jason K

    This is really useful for me. Very appreciate.

    In one of you comment, you said
    “Because the app is designed as a single page application”

    Does this mean this template is only of SPA? As in my app, I will have a navigator bar which has four tab and each tab has totally different pages. So I not sure if this can be used for my app.

    Thanks

    Like

    • Hi Song,

      You can definitely use this repo as a base for your project. You’d just need to do a little tweaking here and there. The express portion of the app is designed to serve up only a single page, but it would be very easy for you to just keep adding routes and views on the node side to make it a multipage website. Then depending on each page, you could (or could not) include the single page app .js file thats built as the backbone app with Grunt.

      Like

  29. Hi,
    i had issues when bundling the vendor file with a later version of grunt-browserify (3.8.0) instad of v1.3.0 which you used for this article.
    Well, long story short, it appears that now the shim part should be put inside package.json ‘s “browserify-shim”. I didn’t see it here in the comments, so i paste my solution here, maybe it helps other people having the same issue:

    in package.json:
    “browserify-shim”: {
    “jquery”: {
    “path”: “client/requires/jquery/js/jquery.js”,
    “exports”: “$”
    },
    “underscore”: {
    “path”: “client/requires/underscore/js/underscore.js”,
    “exports”: “_”
    },
    “backbone”: {
    “path”: “client/requires/backbone/js/backbone.js”,
    “exports”: “Backbone”,
    “depends”: [
    “underscore:underscore”
    ]
    },
    “backbone.marionette”: {
    “path”: “client/requires/backbone.marionette/js/backbone.marionette.js”,
    “exports”: “Marionette”,
    “depends”: [
    “jquery: $”,
    “backbone: Backbone”,
    “underscore: _”
    ]
    }
    },
    in Gruntfile.js:
    browserify: {
    vendor: {
    src: [‘client/requires/**/*.js’],
    dest: ‘build/vendor.js’
    }
    },
    hence using double quotes in package json and array for the depends.

    Great and really helpful article btw.
    Mero

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s