Using Grunt to Auto-Restart node.js with File Watchers

Written by Russell on . Posted in App Dev, Deployment, Front End, Productivity, Software

Preprocessors have become a very important part of the development life cycle. In the past we would just write some HTML, JavaScript and CSS with a backend and deploy a website.  Now for better speed, development experience and more manageable outcomes we have a multitude of languages that compile into these standards, e.g: CoffeeScript–> JavaScript, LESS –> CSS, Jade –> HTML… Then there is JS, CSS and HTML compression and minification after that.

Creating a development workflow to manage all of these transformations can be a very daunting task at the beginning of a new project. The complexity of the workflow can can also make or break a project. When ever I try to solve a problem I always try to look at the difficulty curve of reproduction and repeatability. In other words, it shouldn’t be difficult to setup a new developer on the project and it should be easy to perform 1k times a day without a work-performance loss.

Grunt has become a very important part of our  development life cycles. For compiled projects such as Java, adding in Grunt from ANT or Maven is relatively simple to in-line. For our node.js projects we wanted to be able to not only run the node server, but we wanted to be able to auto-restart the process while also auto-building resource files like LESS and JS files. Below you will find a lengthy Grunt file with commentary interlaced. This should help you get started with your own development environment.

'use strict';

module.exports = function(grunt) {
    grunt.initConfig({
        /**
            The concurrent task will let us spin up all of required tasks. It is very 
            important to list the 'watch' task last because it is blocking and nothing 
            after it will be run.
        **/
        concurrent: {
            dev: ["less:dev", "nodemon", "watch"],
            options: {
                logConcurrentOutput: true
            }
        },

        /**
            The nodemon task will start your node server. The watch parameter will tell 
            nodemon what files to look at that will trigger a restart. Full grunt-nodemon 
            documentation
        **/
        nodemon: {
            dev: {
                script: 'index.js',
                options: {
                    /** Environment variables required by the NODE application **/
                    env: {
                          "NODE_ENV": "development"
                        , "NODE_CONFIG": "dev"
                    },
                    watch: ["server"],
                    delay: 300,

                    callback: function (nodemon) {
                        nodemon.on('log', function (event) {
                            console.log(event.colour);
                        });

                        /** Open the application in a new browser window and is optional **/
                        nodemon.on('config:update', function () {
                            // Delay before server listens on port
                            setTimeout(function() {
                                require('open')('http://127.0.0.1:8000');
                            }, 1000);
                        });

                        /** Update .rebooted to fire Live-Reload **/
                        nodemon.on('restart', function () {
                            // Delay before server listens on port
                            setTimeout(function() {
                                require('fs').writeFileSync('.rebooted', 'rebooted');
                            }, 1000);
                        });
                    }
                }
            }
        },

        /**
            Watch the JS and LESS folders for changes. Triggering 
            fires off the listed tasks
        **/
        watch: {
            js: {
                files: ["client/resources/less/**/*.js"],
                tasks: ['copy:dev:custom'],
                options: { nospawn: true, livereload: true }
            },
            less: {
                files: ["client/resources/less/**/*.less"],
                tasks: ['less'],
                options: { nospawn: true, livereload: true }
            }
        },

        /** 
            Less task to compile LESS into CSS.
            Different options for dev and prod
        **/
        less: {
            dev: {
                options: {
                    compress: false,
                    yuicompress: false,
                    strictMath: true,
                    strictUnits: true,
                    strictImports: true
                },
                files: lessFiles
            }, 
            prod: {
                options: {
                    compress: true,
                    yuicompress: true,
                    strictMath: true,
                    strictUnits: true,
                    strictImports: true
                },
                files: lessFiles
            }
        },

        /**
            Used for production mode, minify and uglyfy the JavaScript Output
        **/
        uglify: {
            prod: {
                options: {
                    mangle: true,
                    compress: true,
                    sourceMap: true,
                    drop_console: true
                },
                files: {
                    'client/public/js/main.js': ['client/resources/js/main.js']
                }
            }
        },

        /**
            This copy tasks has two parts. The libraries will be rarely updated and are 
            only copied on startup. The custom sub-task will copy over application specific 
            JS since it doesn't need a preprocessor in dev
        **/
        copy: {
            dev: {
                custom: {
                    files: [
                        {
                            src: ["client/public/js/*.js"], 
                            dest: "client/public/js", 
                            expand: true, 
                            flatten: true
                        }
                    ]
                },
                libs: {
                    files: [
                      /** 
                        Array of file objects that reference bower libs }}
                      **/
                    ]
                }
            }
        }
    });

    /**
        Load all the GRUNT tasks
    **/
    grunt.loadNpmTasks("grunt-nodemon");
    grunt.loadNpmTasks("grunt-concurrent")
    grunt.loadNpmTasks("grunt-contrib-copy")
    grunt.loadNpmTasks("grunt-contrib-less")
    grunt.loadNpmTasks("grunt-contrib-watch");
    grunt.loadNpmTasks("grunt-contrib-uglify");

    /**
        Register tasks allowing you to run:
            grunt
            grunt run
            grun dev
            grun prod
    **/
    grunt.registerTask("run", ["concurrent:dev"]);
    grunt.registerTask("default", ["concurrent:dev"]);

    grunt.registerTask("dev", ["less:dev", "copy:dev"]);
    grunt.registerTask("prod", ["uglify:prod", "less:prod"]);
};

You will need to add a few requirements to your packages.json file to pull in the new requrements

    "devDependencies": {
          "open": "*"
        , "grunt-nodemon": "*"
        , "grunt-concurrent": "*"
        , "grunt-contrib-copy": "*"
        , "grunt-contrib-less": "*"
        , "grunt-contrib-watch": "*"
        , "grunt-contrib-uglify": "*"
    }

Front-End Resource Roundup

Written by tphillippi on . Posted in Front End

Note: this is a list of resources I’ve used for clients in the past to help other developers beginning to learn front-end tools get up to speed


Here is a list of resources for you to use to become more familiar with html, css & javascript. The resources are categorized  by the amount of time or difficulty required for adequate digestion of the information. The easiest/shortest is surfing, resources you can skim through in minutes as you need them. Next is snorkeling, resources better digested over a period of about an hour or more to really go through Lastly, deep diving, resources that cover topics in depth in several hours or more (this doesn’t mean you can’t pick and choose chapters or sections as you need them, though!). 

General Resources:

HTML (Structure):

CSS (Appearance):

JavaScript (Functionality): 

UX/Usability/Best Practices:

Some Tools:

Don’t be intimated by the vastness of the resources outlined here. We suggest for each topic you want to dive in to, take a look, see what appeals to you, and jump in. Then, over time, periodically refer to the deep diving sections to further your skills. I hope this is helpful! Enjoy!