interfacelab

Avatar

Introducing makejs

I have recently been working on the mobile UI for a site I built called Sessions+.  Sessions+ is a poker bankroll tracker that has a companion iPhone application for live tracking during live poker games, and now a mobile UI for Android and other HTML5 capable mobile browsers which replicates the most of the important functionality of the iPhone app.

The framework I used to build the app uses a lot of separate javascript and css files, though the entire app is housed in a single html file.  So I end up with a <head> element jam packed with stuff.  While this is perfect for development, it’s no good for deployment or QA.

For an example of what the <head> element looks like during development:

That’s a lot of stuff.  To optimize for mobile, I’m going to need to smash these files together and run them through yui-compressor to make it as small as possible (and then serve it up with GZip to make it even smaller).

Now after some googling, I ran into Juicer.  Juicer is a great tool, but it still didn’t do everything I wanted, and specifying the dependencies within the javascript and CSS files was not as explicit as I desire.  It just seemed to prone to error.  Finally, after merging everything with Juicer, I’d have to manually update the html files by hand to replace all those script and link tags with the new ones.

Next up on the google list was Apache Ant.  I haven’t used Ant since doing a random Flex project a few years ago, and I was afraid it was simply too complicated to setup for my small little project.  But in my quest to avoid NIH syndrome, I gave it a spin anyhow.

I gave up after an hour or two as it was just too much.  Maybe I’m getting lazy in my older years, maybe I am suffering insufferable NIH syndrome, I’m not sure.  Also, I hate XML.

Tick Tock

So the clock is ticking down on my self-imposed deadline to get a system setup that “builds” my little HTML5 app into a production ready thing.  There were a couple of other options presented to me by google, but again, they either used the dependency thing of Juicer, or were horribly complicated.

So I did what any self-respecting developer would do: fired up TextMate and started hammering.

Meet makejs

When I set about building it, I had a few simple goals in mind:

  • YAML based configuration files.  I love me some YAML.  I love being explicit.
  • Ability to modify HTML files to replace <script> and <link> tags
  • Generate an HTML5 cache manifest
  • Run in continuous integration mode where changes to files would trigger a re-build.

So five hours later I had a working system.

Using makejs

makejs uses a YAML based configuration file to direct the build process.  Here is an example:

Now that’s a lot to process, but it’s pretty simple once you break it down.  The general layout for the build configuration is thus:

  • Build Target
    • Version (Major.Minor.Build)
    • Pre-Requisite Build Targets
    • Build
      • Build Phase
        • Settings

And that’s essentially it.  But let’s look at it in more detail.

In the configuration above, you’ll notice I have two distinct build targets: “glamrock” and “example”.  GlamRock is the mobile framework I built, Example is a sample project that uses GlamRock.  For the GlamRock build target, you’ll see that I have 3 build phases: copy, compress and manifest.

The copy build phase does exactly as it sounds, it copies files to a destination in the build directory.  Nothing more, nothing less.  In this case, I like to keep jQuery and jQuery’s template stuff separate and not mashed into all of the other files.

The compress build phase takes a list of files, joins them together and then runs them through yui-compressor.  Let’s take a look at that build phase again:

If you look at the files element, you’ll see a filename (in this case, js/glam.rock.min.{VERSION}.js) with a list of files associated with it.  These files are the ones that are joined together and compressed to generate js/glam.rock.min.{VERSION}.js.  So what’s the deal with the {VERSION} thing?  That tells makejs to replace {VERSION} with the newest build version, which makejs takes care of automatically for you.  For example, if you’re configuration says version: 0.0.81 – the next time you build, makejs will auto-increment the build #, re-save the conf file, and then when it generates the compressed files, you’ll end up with a file name js/glam.rock.min.0.0.82.js.

The manifest phase is what builds the HTML5 cache manifest, a definite must for mobile HTML5 apps.  For GlamRock, it won’t actually build a manifest (see below for why), but it is important to list what files that this build produces which can be included in the cache manifest.

Now, let’s turn our attention to the example build target.  This build target has a copy, compress, alter and manifest build phase.  But before we dive into those, you’ll see that this build phase has a pre-requisite for GlamRock.  When this build target is built, GlamRock will be built first and the output of that build will be put into whatever the build directory for example is.  This is nice because we treat each build target as independent projects and get some nice dependency functionality out of it.  Keeps things clean and relatively simple.

Back to the build phases for the example build target.  I won’t go over copy and compress because there is nothing different happening here then there was in the GlamRock target.  So let’s look at the alter build phase:

The alter build phase takes any input file and replaces any denoted blocks with the proper <script> and <link> tags that have been generated during the entire build process.  If you look at the <head> example at the top of this post, you’ll see that there are actually two blocks surrounded by <!– BEGIN {target} –> and <!– END {target} –> comments.  During the alter phase, makejs will replace these blocks with the output of the specified build target.  For example, after building, this is what our new <head> looks like:

Pretty nice, right?  Note, that this never alters the original, it simply transforms the input into the destination in the build output directory.

The example build phase has a manifest phase, like GlamRock, but with one important difference: it has a name setting.  When building a manifest phase, if there is a name specified, than a physical cache manifest is generated.  So running this phase on the example build target yields a cache manifest saved to example.manifest in the output directory.  The example.manifest looks like this:

Perfect-o.

Getting It

Head on over to GitHub and check out the project: http://github.com/jawngee/makejs

Hope someone finds this useful!

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]
1 Star2 Stars3 Stars4 Stars5 Stars (1 votes, average: 5.00 out of 5)
Loading ... Loading ...
  • Pingback: World Wide News Flash

  • http://nerd.sh olle

    Why not write it in js and have json as the configuration language, that would have been…more appropriate.

  • Anonymous

    I just pushed a version with json conf file support, but I think you’ll find yourself typing way more with json than you will with yaml, hence the choice to go with yaml.

    As for writing it in javascript … well I don’t know a good command line javascript engine that is as ubiquitous as php/ruby/python that supports shelling out, yaml and inotify.

    So no, writing it in javascript itself wouldn’t be appropriate at all because it increases the number and weight of dependencies.