Thursday, January 17, 2013

PackScript – An Example - Freedom From Script Tags!

*UPDATE* Check out http://packscript.com/ for a complete reference and examples.

We’re guessing you got here from the last post. If not, it’s probably worth reading for a quick intro, but hey, you’re smart, you’ll probably pick it up as we go along.

This example demonstrates how to use configuration files to define script and stylesheet outputs in both debug and production forms, create reusable functions and use templates.

As promised, we’re going to show you how we can work on our code in separate files and be able to edit, create, move etc. these files on the fly and have full debugging experience without needing to ever manage script or stylesheet references.

Chrome is currently the only browser that supports this technique using the sourceURL tag. FireBug claims to, but I haven’t been successful. You do use Chrome for web development, right?

The Sample

We’re going to build a silly little text animation thing. Head on over to the github repository and have a quick squiz at what’s there… Oh. Couldn’t be bothered? OK, well, it looks something like this.

PackScriptSample-files

At least that’s what it looks like in VS2012.

The Build folder is where our combined files are going to end up. They’re not included in the solution, otherwise search operations in Visual Studio return duplicate results. It will get generated as part of your build process, anyway!

The Tools folder contains a copy of the PackScript assemblies.

The Source folder isn’t really that interesting either. It’s got jQuery, some CSS, a controller file that handles a button click and a simple animate function. Enough to demonstrate what we’re trying to get at.

The html files contain a simple page from which to trigger our animation. They contain duplicate markup, the solution to which lies with our friend knockout.composite.

The Interesting Bits

Firstly, let’s have a look at the PackScript config file, pack.js.

pack({
    to: 'Build/site.js',
    include: 'Source/*.js',
    prioritise: 'jquery.js',
    template: 'debug'
});

pack({
    to: 'Build/site.min.js',
    include: 'Source/*.js',
    prioritise: 'jquery.js',
    minify: true
});

pack({
    to: 'Build/site.css',
    include: 'Source/*.css'
});

A little bit going on here, but pretty easy to follow.

First up, build site.js from all the JavaScript in the Source folder, put jQuery first and apply some template called ‘debug’ to them. Didn’t I see some debug template thingy before?

The production version, site.min.js, is pretty similar, except rather than applying the template, minify it all. We could have minified the CSS too, but you get the idea.

The Template

So it looks like there are two parts to the template. Since you’ve read the first part, you can already guess what each file is for. debug.template.js:

window.eval("<%= prepareContent(content, pathRelativeToConfig) %>");

Looks suspiciously like a very short template. What’s this prepareContent stuff?

this.prepareContent = function (content, path) {
    return content
        .replace(/\r/g, "")                 // exclude windows linefeeds
        .replace(/\\/g, "\\\\")             // double escape
        .replace(/\n/g, "\\n")              // replace literal newlines with control characters
        .replace(/\"/g, "\\\"")             // escape double quotes
        + "\\n\/\/@ sourceURL="             // append sourceURL tag
        + path.toString().replace(/\\/g, '/');
}

Ahh. Cool, we can put reusable functions into these “configuration” files, like debug.pack.js.

Note we attach our prepareContent function to the “this” object. PackScript restricts the scope of the execution of each file to help avoid conflicts, so to make something available globally, we need to explicitly attach it to the global object. Having said this, when you write them, organise these sorts of functions into pseudo-namespaces. Do it. Thank me later.

So what is actually going on here? The template is wrapping the script content in a call to window.eval. This gives us the chance to inject some content, in this case, a neat little tag that Chrome will interpret. There’s some other stuff in there to make it play nicely with an eval statement, pretty straightforward stuff.

The other magic variables used in the template are passed to the template engine by PackScript. Check out the github readme for an up to date list of the built in variables.

The Result?

You can see the “debug” version here and the “production” version here. Open DevTools for the debug version and you can see our scripts nicely in the source list.

PackScriptSample-debugger

The lack of an ‘S’ on Source is a tad conspicuous (DevTools bug?), but other than that, everything looks as expected. This might seem trivial with only three files (one of which you should probably load from a CDN anyway), but when you have hundreds of source files, it is sweetness to see them arrayed out in neat organisation.

Let’s add a file without adding a script reference.

PackScriptSample-debugger2

Cool. Looks like it works. Breakpoints even play the game. The production version works pretty much as you would expect.

So there you have it! Nicely separated code that you can mess with to your heart’s content, debug and production versions, combined CSS, and all without ever having to touch a script tag again*. Feels good.

* - OK, maybe occasionally.

Just To Make It Perfectly Clear…

None of this sample is necessarily “best practice”. It is presented purely to demonstrate some of the power of PackScript. knockout.composite does use a similar technique for this issue, but has a relatively sophisticated resource management system that takes all sorts of pain away.

PackScript is fully functional and under active development. I already have a list of planned enhancements as long as my arm (did someone say “source maps”?), so dip your toes in, give it a try, we think you’ll love it!

In the not-too-distant future, we will cobble together some sort of reference site that shows how to get some serious power out of knockout.composite and PackScript and how it fits very nicely with a SOA flavoured system.

In the meantime, we will be putting together some more posts on how it’s built (JavaScript core running in a Windows console), extensibility and some other advanced stuff.

What would you like to hear about most?

Labels: , , , , , , , , , , , ,

0 Comments:

Post a Comment

<< Home