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": "*"
    }

Google Discontinues Free Version of Google Apps for Business

Written by Perry Woodin on . Posted in Software, Strategy

On Thursday (12/06/12), Google announced changes to their Google Apps for Business offering. They will no longer offer a free version of Google Apps for Business. As of 12/06/12, any company that wants to use Google Apps will need to sign up for the paid version which costs $50 per user, per year.

If you are an existing Google Apps customer who is taking advantage of the free version, nothing changes. You are essentially grandfathered in and will not be charged the $50 per user, per year fee. Google is offering existing users an upgrade path to Google Apps for Business at the rate of $5 per user, per year.

I should also note that Google Apps for Education is still available as a free service for schools and universities.

Troy Web is an official Google Apps Reseller http://goo.gl/VRk1y. If you need assistance with setting up Google Apps for Business, let us know. We can help with everything from simple account setup, to full-scale migration from your existing service provider.

Make Eclipse Editor Work with Retina Displays

Written by Sean Ryan on . Posted in Software

I recently had to buy a new computer – a MacBook – because I spilled a full cup of coffee all over the keyboard of my 17″ MacBook.  I was a little upset. Apple stopped making 17″ laptops so to make up the for the lack of screen real estate, I decided to go all out with a shiny new retina display. I admit, I’m more impressed than I thought I would be but the technology comes at a cost.

Not all applications look nice with the display. With retina, applications need to display different icons and fonts that are made specifically for a much higher pixel density. Any web developer already deals with this when targeting iPhones or iPads, but since very few non-mobile devices have such displays, not all desktop applications have the necessary files yet.

Eclipse is such a popular IDE that I was devastated to see it doesn’t support retina yet. I use the IDE all day long so I scoured the Internet tubes for a solution and found one that is good enough. It only updates the fonts for the editor part and not any of the graphics – obviously – but that’s good enough for now. Here’s what you need to do…

  1. Right click and  “Show package contents” on the Eclipse.app. (STS.app, if using Spring Source Toolkit)
  2. Edit Contents/Info.plist. Just above the closing </dict> </plist>, add <key>NSHighResolutionCapable</key> <true/>
  3. Make a copy of the app (Eclipse copy.app)
  4. Open the copy
  5. Close the copy
  6. Rename the original (Eclipse-NON-RETINA.app)
  7. Rename the copy (Eclipse.app)
  8. Open
  9. Enjoy

My Love/Hate Relationship with WordPress

Written by Perry Woodin on . Posted in Misc Ramblings, Software

WordPress is really amazing. I can standup a WordPress site on Amazon’s EC2 in under 15 minutes. And we’ve got a developer here at Troy Web who is adept at writing plugins. So, I love WordPress because it can facilitate launching a basic website in under a day.

What I hate about WordPress is it is quite often the wrong tool for the job. That’s not really the fault of WordPress. People become enamored by its ease of use and try to shoehorn functionality that is probably better served by custom application development. At a certain point they feel locked into the platform. That’s never a good thing.

But what really prompted this post/vent is the ubiquity of WordPress plugins. I recently helped a friend move from WordPress.com to a self hosted install. We had to replace some widgets and it took me hours to find a suitable plugin. Not because the plugin didn’t exist but rather because there were hundreds of plugins that claimed to offer the same functionality. My new rule for plugins is only install if the number of downloads exceeds 250,000.

So, if you want a WordPress site, I’m happy to help, but lets talk about your site’s goals before you commit to the platform.

Authenticating to Twitter Using OAuth and twitter4j 2.2x API with ColdFusion

Written by Sean Ryan on . Posted in Software

Twitter LogoRay Camden has a great blog entry on adding support in ColdFusion for Twitter but at the time he wrote it, the version of twitter4j was 2.1. Since then, twitter4j has been changed and the code in Ray’s blog won’t work if you need to use version 2.2.x.

Specifically, the Twitter object is now an interface and the can’t be directly instantiated. Also, the setOAuthAccessToken method on the Twitter interface no longer accepts the access token and access token secret as paremeters. The method now accepts an AccessToken object.

The change in code is small, but important.  To make the new version of the API work, change the following three lines from Ray’s blog to these new method calls and everything should work as he explains.

(Sorry about the wrapped lines, but you get the idea)

Change

 <cfset application.Twitter = 
     application.javaloader.create("twitter4j.Twitter")>

 <cfset application.Twitter.setOAuthConsumer
     ('consumerkey',consumersecret')>

 <cfset application.Twitter.setOAuthAccessToken
     ("storedaccesstoken" ,"storedaccesssecret")>

To

 <cfset application.Twitter = javaloader.create
     ("twitter4j.TwitterFactory").getInstance()>

 <cfset application.Twitter.setOAuthConsumer
     ('consumerkey',consumersecret')>

 <cfset local.accessToken = javaloader.create
     ("twitter4j.auth.AccessToken").init
          ("storedaccesstoken" ,"storedaccesssecret")>

 <cfset application.Twitter.setOAuthAccessToken
     (local.accessToken)>


Since there is no ColdFusion Twitter client out there, I plan on building one soon that you can just drop into your applications. Stay tuned for that blog entry where I’ll walk you through using it.

CFWheels Workarounds Numero Uno – Application Proxy

Written by jbriccetti on . Posted in Architecture, Misc Ramblings, Software

One of the interesting features of the CFWheels framework is the fact that the core application architecture leverages <cfinclude /> tags.  I say interesting because in an environment that is essentially java under the hood, most frameworks use inheritance. Such is the case with FW/1 (“Framework One”), the awesomely simple to use framework from Sean Corield

FW/1 implementation of Application.cfc

<cfcomponent extends="org.corfield.framework">
</cfcomponent>

CFWheels implementation of Application.cfc

<cfcomponent output="false">
   <cfinclude template="wheels/functions.cfm">
</cfcomponent>

In many ways, how it is wired in doesnt really matter… and <cfinclude /> is lighting fast, much faster than inheritance. The challenging part becomes when you want to override (or extend) a method in the core application framework – you can’t just create the method and use super.method() as needed. Instead, wheels creates a way for you to piggyback onto the application events, but at that point you are at the mercy of the framework and whatever code it already ran – there is no obvious way to orchestrate the firing order. your custom code comes last, done deal.

But of course where there is a will, there is a way. while it would be a big no-no to hack the framework code itself (in the wheels directory) the answer is quite simple. simply rename your root Application.cfc file (coded above) and name it “Wheels-Application-Proxy.cfc” Then, just create the following Application.cfc in your root directory

<cfcomponent extends="Wheels-Application-Proxy">
</cfcomponent>

Now if you want to rewrite the OnRequestEnd event (say to modify that ugly debug information wheels gives you, or perhaps tweek it a bit) you are ready to go.  In such a case you may want to be careful… if you aren’t going to call super.OnRequestEnd() at some point in your method, you may want to have a peak in the framework code and see what its doing and be sure you dont cut out any fundamental framework code… but that’s easy enough to do with a copy-and-paste