How to add Bower support to a SailsJS application

Another extremely asset that SailsJS does not necessary "officially" support is the use of Bower to import and compile your front end assets. While you can easily add everything to your /assets directory, there is something about manual copying and sorting of files/directories that is just annoying. Again, this process though detailed is not difficult to do,

The bower.json file

There is a couple different ways to get this file into your project. Please note that it will be easier if you place this in the root of your project. If you don't necessarily want your /bower_components in the root of your project (even though I would recommend it), you can change their location using the .bowerrc (Bower configuration) file. See how to use it here.

Init

The first is using Bower's wizard that you can initiate in your shell/terminal by simply entering:

bower init  

This process will ask you a series of questions that are specific to your project such as author, repository name, liscense, etc. If you are unsure as to some valid answers to these questions, feel free to consult the documentation. It is worth noting that Bower is somewhat picky as to the answers for some of the question. Once complete Bower will build your bower.json file for you in your project.

Manually

While this may be contradicitive, my preferred method most of the time, is to create my bower.json file by hand. As stated prior, Bower can be picky as to what you enter during the setup wizard. More often than not, this will be to its detriment. At the very minimum, you need to specify 4 different values:

  • name (string; slug)
  • version (string; valid software version syntax ie 0.0.0)
  • private (boolean)
  • dependencies (object)

Like so:

{
  "name": "application-name",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "jquery": "~2.1.4"
  }
}

Install/require dependencies

Once your bower.json file is constructed, go ahead and install/require each Bower package that you need; via command line or manual entry. Doing so will through everything into the configured location of the bower_components directory (by default this will install in the same directory as the bower.json).

Grunt/Bower package

Just like if we are using SASS/LESS, Grunt needs a task to be able to automatically copy and move around your assets within your project. Before we can create any kind of configuration for Bower, we need to tell Grunt that we want to support it. Lets install the Grunt/Bower node package with:

npm install grunt-bower --save  

Grunt task

Now that the package is installed, we need to tell Grunt to look at our /bower_components directory. Obviously this will require a new task. So to create this task, create a new file within the /tasks/config directory named bower.js. Within this file paste the following code:

module.exports = function(grunt) {  
  grunt.config.set('bower', {
    dev: {
      dest: '.tmp/public',
      js_dest: '.tmp/public/js/dependencies',
      css_dest: '.tmp/public/styles',
      fonts_dest: '.tmp/public'
    }
  });

  grunt.loadNpmTasks('grunt-bower');

};

Go ahead and save this file but don't close it quite yet.

Register the new Bower task

While this new package is exactly what we want to copy all of our assets to our .tmp directory so SailsJS can find them, we need to register our new bower:dev task so it will run. In it's current form, Grunt does not know to run it. Open up the /tasks/register/compileAssets.js file and add bower:dev right after the clean:dev task.

The order of these tasks is important. You need to make sure that this new Bower task is placed before any sort of Javascript/CSS preprocessing takes place, otherwise you are going to get some errors. Your compileAssets task should look something like this:

module.exports = function (grunt) {  
    grunt.registerTask('compileAssets', [
        'clean:dev',
        'bower:dev',
        'jst:dev',
        'less:dev',
        'copy:dev',
        'coffee:dev'
    ]);
};

Save this file and close it.

Font support

If you are not using any Bower packages that do not include font files, skip this section.

Fonts can pose another level of difficulty if when using Bower with Grunt. Without any additional configuration, Grunt will most likely ignore the font files and then you will have 404 errors when your stylesheet won't be able to figure out where they are at.

For the sake of this example, lets use Font Awesome. The icon sets that these guys have created are about as industry leading as you can get. Most likely you have used/seen a Font Awesome icon somewhere.

Once you have added font-awesome as a Bower dependency, you now need to import the CSS library into my project using LESS or SCSS. Go ahead and open your importer.less (or importer.scss) and add the following line towards the top of your stylesheet:

@import "../../bower_components/font-awesome/less/font-awesome.less";

Or if you are using SCSS:

@import "../../bower_components/font-awesome/scss/font-awesome.scss";

This will import the necessary CSS into your project. BUT WAIT! Again, this will not take care of importing the actual icon files into your project. Grunt is smart but not that smart. We will need to put some additional configuration into our Bower task. Open up our /tasks/config/bower.js file and add the necessary lines so our task looks like this:

module.exports = function(grunt) {  
  grunt.config.set('bower', {
    dev: {
      dest: '.tmp/public',
      js_dest: '.tmp/public/js/dependencies',
      css_dest: '.tmp/public/styles',
      fonts_dest: '.tmp/public',
      options: {
        packageSpecific: {
          expand: true,
          'font-awesome': {
            files: [
              'fonts/fontawesome-webfont.eot',
              'fonts/fontawesome-webfont.svg',
              'fonts/fontawesome-webfont.ttf',
              'fonts/fontawesome-webfont.woff',
              'fonts/fontawesome-webfont.woff2',
              'fonts/FontAwesome.otf'
            ]
          }
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-bower');

};

The Grunt/Bower package allows us to create objects of options that match certain Bower packages. In this case it is 'font-awesome.' Basically what I am Grunt to do is take the contents of the fonts/ directory and then copy them to the .tmp/public directory. It's that simple.

Restart your server

Now that we have added all of the necessary configuration for SailsJS to use, we now need to restart our server so Sails will acknowledge our new settings and copy the necessary assets.

Finish it up

Assuming that you did everything correctly, you should now see the new CSS and fonts (if necessary) show up in your temp directory.