Generating a Javascript Loader with Grunt

If you’re building a web application you’re going to end up with a sizable body of Javascript code, which you’ll usually want to keep separate until deployment. The best way to do this, that won’t require you to change the HTML on deployment, is to use a generated loader file that will load the full body of javascript code.

Recently I’ve made a Grunt Specific task for automating this based on ways I’ve done it in the past. It parses using Coffeescript but it’d be really trivial to change for your purposes. The script also assumes the presence of head.js You can find the Gist of it here: https://gist.github.com/MalucoMarinero/5473658

You can then configure it using options like the ones below.


  grunt.initConfig {
    loader:
      desktopClient:
        # The directory to look for javascript files.
        srcDir: 'www/clients/desktop/js'

        # The loader file to generate
        dest: 'www/clients/desktop/js/loader.js' 
        
        # Javascript files that must be loaded first due to dependency, when they
        # match they'll get pushed to the top of the head.js caal.
        priorityMatches: ['**/app.js', '**/module.js']

        # Patterns which will not get included in the loader. If the loader ends up in the source
        # you'll want to make sure the loader filename is in there.
        ignorePattern: 'loader.js'

        # A URL Prefix to make sure the filenames work in the browser. Without it all file paths
        # will be relative to the srcDir.
        prefix: 'js/'

        # What global variable the loader call will be attached to. This makes the loader a function
        # that can perform callback actions once the load is complete.
        varName: 'desktopLoader'
  } 

Once the loader is generated, on your HTML page all you need is to load that single loader.js file, and then run the function, at which point your application will come into being. Any initialisation that needs to be done after loading can be done by running the function with a callback.

When it comes time for deployment, the same HTML will be all you need, the loader will just point to a concatenated and minified file instead and everything will work as before. Hope you find it useful.

Resolving LiveReload Conflicts in Grunt

Grunt is an excellent automation tool and part of the Yeoman toolset. It has this ridiculously cool feature that allows you to watch files for changes and then tell every browser looking at your webpages to refresh — mobile, tablet, desktop, whatever — and it does this without browser extensions. It’s pretty speccy.

There’s a problem though: if your HTML, CSS and JS is all generated from HAML, SASS and Coffeescript like me, it doesn’t work like you’d expect it to:


# Examples in Coffeescript, that's how I roll.

  grunt.initConfig {
    watch:
      livereload:
        files: [
          'src/example/**/*.{haml|coffee|sass}'
          'www/example/**/*.{html|js|css}'
        ]
        tasks: ['coffee', 'compass', 'hamlpy', 'livereload']
  }

Rather than compiling the Coffeescript, SASS and HAML, followed by a LiveReload, the watch event doesn’t pick up the changes to the HTML, CSS and Javascript so that reload never happens. Makes sense really, it’s not watching during the task run so it misses it.

You can’t run two watch tasks concurrently though, unless you open another terminal session. If you want to keep it all in one process, you can do this:


mm = require 'minimatch'

  grunt.initConfig {
    watch:
      livereload:
        files: [
          'src/example/**/*.{haml|coffee|sass}'
          'www/example/**/*.{html|js|css}'
        ]
        tasks: ['reloadDispatcher:example']
    reloadDispatcher:
      example:
        "**/*.haml" : ['hamlpy']
        "**/*.sass" : ['compass']
        "**/*.coffee" : ['coffee']
        "**/*.{html,css,js}" : ['livereload']
  }

  grunt.registerMultiTask 'reloadDispatcher', 'Run tasks based on extensions.', () ->
    for pattern, tasks of this.data
      if grunt.regarde.changed.some mm.filter pattern
        grunt.task.run tasks

With this new task, what it’s doing is checking the list of files changed that the watcher (grunt.regarde) detected against your patterns in the config, and then for any matches it runs the appropriate tasks. Dunno how it will behave in bigger projects but that’s enough experimentation for now.