Skip to main content

4 posts tagged with "cassette"

View All Tags

How I'm Using Cassette part 3:Cassette and TypeScript Integration

The modern web is JavaScript. There's no two ways about it. HTML 5 has new CSS, new HTML but the most important aspect of it from an application development point of view is JavaScript. It's the engine. Without it HTML 5 wouldn't be the exciting application platform that it is. Half the posts on Hacker News would vanish.

It's easy to break a JavaScript application. One false keypress and you can mysteriously turn a fully functioning app into toast. And not know why. There's tools you can use to help yourself - JSHint / JSLint but whilst these make error detection a little easier it remains very easy to shoot yourself in the foot with JavaScript. Because of this I've come to really rather love TypeScript. If you didn't already know, TypeScript can be summed up as JavaScript with optional static typing. It's a superset of JavaScript - JavaScript with go-faster stripes. When run through the compiler TypeScript is transpiled into JavaScript. And importantly, if you have bugs in your code, the compiler should catch them at this point and let you know.

Now very few of us are working on greenfield applications. Most of us have existing applications to maintain and support. Happily, TypeScript fits very well with this purely because TypeScript is a superset of JavaScript. That is to say: all JavaScript is valid TypeScript in the same way that all CSS is valid LESS. This means that you can take an existing .js file, rename it to have a .ts suffix, run the TypeScript compiler over it and out will pop your JavaScript file just as it was before. You're then free to enrich your TypeScript file with the relevant type annotations at your own pace. Increasing the robustness of your codebase is a choice left to you.

The project I am working on has recently started to incorporate TypeScript. It's an ASP.Net MVC 4 application which makes use of Knockout. The reason we started to incorporate TypeScript is because certain parts of the app, particularly the Knockout parts, were becoming more complex. This complexity wasn't really an issue when we were writing the relevant JavaScript. However, when it came to refactoring and handing files from one team member to another we realised it was very easy to introduce bugs into the codebase, particularly around the JavaScript. Hence TypeScript.

Cassette and TypeScript#

Enough of the pre-amble. The project was making use of Cassette for serving up its CSS and JavaScript. Because Cassette rocks. One of the reasons we use it is that we're making extensive use of Cassette's ability to serve scripts in dependency order. So if we were to move to using TypeScript it was important that TypeScript and Cassette would play well together.

I'm happy to report that Cassettes and TypeScript do work well together, but there are a few things that you need to get up and running. Or, to be a little clearer, if you want to make use of Cassette's in-file Asset Referencing then you'll need to follow these steps. If you don't need Asset Referencing then you'll be fine using Cassette with TypeScript generated JavaScript as is *provided* you ensure the TypeScript compiler is not preserving comments in the generated JavaScript.

The Fly in the Ointment: Asset References#

TypeScript is designed to allow you to break up your application into modules. However, the referencing mechanism which allows you to reference one TypeScript file / module from another is exactly the same as the existing Visual Studio XML reference comments mechanism that was originally introduced to drive JavaScript Intellisense in Visual Studio. To quote the TypeScript spec:

  • A comment of the form /// adds a dependency on the source file specified in the path argument. The path is resolved relative to the directory of the containing source file.
  • An external import declaration that specifies a relative external module name (section 11.2.1) resolves the name relative to the directory of the containing source file. If a source file with the resulting path and file extension ‘.ts’ exists, that file is added as a dependency. Otherwise, if a source file with the resulting path and file extension ‘.d.ts’ exists, that file is added as a dependency.

The problem is that Cassette *also* supports Visual Studio XML reference comments to drive Asset References. The upshot of this is, that Cassette will parse the /// <reference path="*.ts"/>s and will attempt to serve up the TypeScript files in the browser... Calamity!

Pulling the Fly from the Ointment#

Again I'm going to take the demo from last time (the References branch of my CassetteDemo project) and build on top of it. First of all, we need to update the Cassette package. This is because to get Cassette working with TypeScript you need to be running at least Cassette 2.1. So let's let NuGet do it's thing:

Update-Package Cassette.Aspnet

And whilst we're at it let's grab the jQuery TypeScript typings - we'll need them later:

Install-Package jquery.TypeScript.DefinitelyTyped

Now we need to add a couple of classes to the project. First of all this:

Which subclasses ParseJavaScriptReferences and ensures TypeScript files are excluded when JavaScript references are being parsed. And to make sure that Cassette makes use of ParseJavaScriptNotTypeScriptReferences in place of ParseJavaScriptReferences we need this:

Now we're in a position to use TypeScript with Cassette. To demonstrate this let's take the Index.js and rename it to Index.ts. And now it's TypeScript. However before it can compile it needs to know what jQuery is - so we drag in the jQuery typings from Definitely Typed. And now it can compile from this:

To this: (Please note that I get the TypeScript compiler to preserve my comments in order that I can continue to use Cassettes Asset Referencing)

As you can see the output JavaScript has both the TypeScript and the Cassette references in place. However thanks to ParseJavaScriptNotTypeScriptReferences those TypeScript references will be ignored by Cassette.

So that's it - we're home free. Before I finish off I'd like to say thanks to Cassette's Andrew Davey who set me on the right path when trying to work out how to do this. A thousand thank yous Andrew!

And finally, again as last time you can see what I've done in this post by just looking at the repository on GitHub. The changes I made are on the TypeScript branch of that particular repository.

How I'm Using Cassette part 2:Get Cassette to Serve Scripts in Dependency Order

Last time I wrote about Cassette I was talking about how to generally get up and running. How to use Cassette within an ASP.Net MVC project. What I want to write about now is (in my eyes) the most useful feature of Cassette by a country mile. This is Cassettes ability to ensure scripts are served in dependency order.

Why does this matter?#

You might well ask. If we go back 10 years or so then really this wasn't a problem. No-one was doing a great deal with JavaScript. And if they did anything it tended to be code snippets in amongst the HTML; nothing adventurous. But unless you've had your head in the sand for the last 3 years then you will have clearly noticed that JavaScript is in rude health and being used for all kinds of things you'd never have imagined. In fact some would have it that it's the assembly language of the web.

For my part, I've been doing more and more with JavaScript. And as I do more and more with it I seek to modularise my code; (like any good developer would) breaking it up into discrete areas of functionality. I aim to only serve up the JavaScript that I need on a given page. And that would be all well and good but for one of the languages shortcomings. Modules. JavaScript doesn't yet have a good module loading story to tell. (Apparently one's coming in EcmaScript 6). (I don't want to get diverted into this topic as it's a big area. But if you're interested then you can read up a little on different approaches being used here. The ongoing contest between RequireJS and CommonJS frankly makes me want to keep my distance for now.)

It Depends#

Back to my point, JavaScripts native handling of script dependencies is non-existent. It's real "here be dragons" territory. If you serve up, for example, Slave.js that depends on things set up in Master.js before you've actually served up Master.js, well it's not a delightful debugging experience. The errors tend be obscure and it's not always obvious what the correct ordering should be.

Naturally this creates something of a headache around my own JavaScript modules. A certain amount of jiggery-pokery is required to ensure that scripts are served in the correct order so that they run as expected. And as your application becomes more complicated / modular, the number of problems around this area increase exponentially. It's really tedious. I don't want to be thinking about managing that as I'm developing - I want to be focused on solving the problem at hand.

In short, what I want to do is reference a script file somewhere in my server-side pipeline. I could be in a view, a layout, a controller, a partial view, a HTML helper... - I just want to know that that script is going to turn up at the client in the right place in the HTML so it works. Always. And I don't want to have to think about it any further than that.

Enter Cassette, riding a white horse#

And this is where Cassette takes the pain away. To quote the documentation:

"Some assets must be included in a page before others. For example, your code may use jQuery, so the jQuery script must be included first. Cassette will sort all assets based on references they declare."

Just the ticket!

Declaring References Server-Side#

What does this look like in reality? Let's build on what I did last time to demonstrate how I make use of Asset References to ensure my scripts turn up in the order I require.

In my _Layout.cshtml file I'm going to remove the following reference from the head of the file:

Bundles.Reference("~/bundles/core");

I'm pulling this out of my layout page because it's presence means that every page MVC serves up is also serving up jQuery and jQuery UI (which is what ~/bundles/core is). If a page doesn't actually make use of jQuery and / or jQuery UI then there's no point in doing this.

"But wait!", I hear you cry, "Haven't you just caused a bug with your reckless action? I distinctly recall that the Login.cshtml page has the following code in place:"

Bundles.Reference("~/bundles/validate");

"And now with your foolhardy, nay, reckless attitude to the ~/bundles/core bundle you've broken your Login screen. How can jQuery Validation be expected to work if there's no jQuery there to extend?"

Well, I understand your concerns but really you needn't worry - Cassette's got my back. Look closely at the code below:

See it? The ~/bundles/validate bundle declares a reference to the ~/bundles/core bundle. The upshot of this is, that if you tell Cassette to reference ~/bundles/validate it will ensure that before it renders that bundle it first renders any bundles that bundle depends on (in this case the ~/bundles/core bundle).

This is a very simple demonstration of the feature but I can't underplay just how useful I find this.

Declaring References in your JavaScript itself#

And the good news doesn't stop there. Let's say you don't want to maintain your references in a separate file. You'd rather declare references inside your JavaScript files themselves. Well - you can. Cassette caters for this through the usage of Asset References.

Let's demo this. First of all add the following file at this location in the project: ~/Scripts/Views/Home/Index.js

The eagle-eyed amongst you will have noticed

  1. I'm mirroring the MVC folder structure inside the Scripts directory. (There's nothing special about that by the way - it's just a file structure I've come to find useful. It's very easy to find the script associated with a View if the scripts share the same organisational approach as the Views.).
  2. The purpose of the script is very simple, it fades out the main body of the screen, re-writes the HTML in that tag and then fades back in. It's purpose is just to do something that is obvious to the user - so they can see the evidence of JavaScript executing.
  3. Lastly and most importantly, do you notice that // @reference ~/bundles/core is the first line of the file? This is our script reference. It's this that Cassette will be reading to pick up references.

To make sure Cassette is picking up our brand new file let's take a look at CassetteConfiguration.cs and uncomment the line of code below:

bundles.AddPerIndividualFile<scriptbundle>("~/Scripts/Views");</scriptbundle>

With this in place Cassette will render out a bundle for each script in the Views subdirectory. Let's see if it works. Add the following reference to our new JavaScript file in ~/Views/Home/Index.cshtml:

Bundles.Reference("~/Scripts/Views/Home/Index.js");

If you browse to the home page of the application this is what you should now see:

What this means is, Index.js was served up by Cassette. And more importantly before Index.js was served the referenced ~/bundles/core was served too.

Avoiding the Gotcha#

There is a gotcha which I've discovered whilst using Cassette's Asset References. Strictly speaking it's a Visual Studio gotcha rather than a Cassette gotcha. It concerns Cassette's support for Visual Studio XML style reference comments. In the example above I could have written this:

/// &lt;reference path="~/bundles/core" /&gt;

Instead of this:

// @reference ~/bundles/core

It would fulfil exactly the same purpose and would work identically. But there's a problem. Using Visual Studio XML style reference comments to refer to Cassette bundles appears to trash the Visual Studios JavaScript Intellisense. You'll lose the Intellisense that's driven by ~/Scripts/_references.js in VS 2012. So if you value your Intellisense (and I do) my advice is to stick to using the standard Cassette references style instead.

Go Forth and Reference#

There is also support in Cassette for CSS referencing (as well as other types of referencing relating to LESS and even CoffeeScript). I haven't made use of CSS referencing myself as, in stark contrast to my JS, my CSS is generally one bundle of styles which I'm happy to be rendered on each page. But it's nice to know the option is there if I wanted it.

Finally, as last time you can see what I've done in this post by just looking at the repository on GitHub. The changes I made are on the References branch of that particular repository.

How I'm Using Cassette part 1:Getting Up and Running

Backing into the light#

For a while now, I've been seeking a bulletproof way to handle the following scenarios... all at the same time in the context of an ASP.Net MVC application:

  1. How to serve full-fat JavaScript in debug mode and minified in release mode
  2. When debugging, ensure that the full-fat JS being served is definitely the latest version; and *not* from the cache. (The time I've wasted due to 304's...)
  3. How to add Javascript assets that need to be served up from any point in an ASP.Net MVC application (including views, layouts, partial views... even controllers if so desired) whilst preventing duplicate scripts from being served.
  4. How to ensure that Javascript files are served up last to any web page to ensure a speedy feel to users (don't want JS blocking rendering).
  5. And last but certainly not least the need to load Javascript files in dependency order. If myView.js depends on jQuery then clearly jQuery-latest.js needs to be served before myView.js.

Now the best, most comprehensive and solid looking solution to this problem has for some time seemed to me to be Andrew Davey'sCassette. This addresses all my issues in one way or another, as well as bringing in a raft of other features (support for Coffeescript etc).

However, up until now I've slightly shied away from using Cassette as I was under the impression it had a large number of dependencies. That doesn't appear to be the case at all. I also had some vague notion that I could quite simply build my own solution to these problems making use of Microsoft's Web Optimization which nicely handles my #1 problem above. However, looking again at the documentation Cassette was promising to handle scenarios #1 - #5 without breaking sweat. How could I ignore that? I figured I should do the sensible thing and take another look at it. And, lo and behold, when I started evaluating it again it seemed to be just what I needed.

With the minumum of fuss I was able to get an ASP.Net MVC 4 solution up and running, integrated with Cassette, which dealt with all my scenarios very nicely indeed. I thought it might be good to write this up over a short series of posts and share what my finished code looks like. If you follow the steps I go through below it'll get you started using Cassette. Or you could skip to the end of this post and look at the repo on GitHub. Here we go...

Adding Cassette to a raw MVC 4 project#

Fire up Visual Studio and create a new MVC 4 project (I used the internet template to have some content in place).

Go to the Package Manager Console and key in "Install-Package Cassette.Aspnet". Cassette will install itself.

Now you've got Cassette in place you may as well pull out usage of Web Optimization as you're not going to need it any more.Be ruthless, delete App_Start/BundleConfig.cs and delete the line of code that references it in Global.asax.cs. If you take the time to run the app now you'll see you've miraculously lost your CSS and your JavaScript. The code referencing it is still in place but there's nothing for it to serve up. Don't worry about that - we're going to come back and Cassette-ify things later on...

You'll also notice you now have a CassetteConfiguration.cs file in your project. Open it. Replace the contents with this (I've just commented out the default code and implemented my own CSS and Script bundles based on what is available in the default template of an MVC 4 app):

In the script above I've created 4 bundles, 1 stylesheet bundle and 3 JavaScript bundles - each of these is roughly equivalent to Web Optimization bundles that are part of the MVC 4 template:

~/bundles/css
Our site CSS - this includes both our own CSS and the jQuery UI CSS as well. This is the rough equivalent of the Web Optimization bundles ~/Content/css and ~/Content/themes/base/css brought together.
~/bundles/head
What scripts we want served in the head tag - Modernizr basically. Do note the setting of the PageLocation property - the purpose of this will become apparent later. This is the direct equivalent of the Web Optimization bundle: ~/bundles/modernizr.
~/bundles/core
The scripts we want served on every page. For this example project I've picked jQuery and jQuery UI. This is the rough equivalent of the Web Optimization bundles ~/bundles/jquery and ~/bundles/jqueryui brought together.
~/bundles/validate
The validation scripts (that are dependent on the core scripts). This is the rough equivalent of the Web Optimization bundle: ~/bundles/jqueryval.

At this point we've set up Cassette in our project - although we're not making use of it yet. If you want to double check that everything is working properly then you can fire up your project and browse to "Cassette.axd" in the root. You should see something a bit like this:

How Web Optimization and Cassette Differ#

If you're more familiar with the workings of Web Optimization than Cassette then it's probably worth taking a moment to appreciate an important distinction between the slightly different ways each works.

Web Optimization

  1. Create bundles as desired.
  2. Serve up bundles and / or straight JavaScript files as you like within your MVC views / partial views / layouts.

Cassette

  1. Create bundles for *all* JavaScript files you wish to serve up. You may wish to create some bundles which consist of a number of a number of JavaScript files pushed together. But for each individual file you wish to serve you also need to create an individual bundle. (Failure to do so may mean you fall prey to the "Cannot find an asset bundle containing the path "~/Scripts/somePath.js".")
  2. Reference bundles and / or individual JavaScript files in their individual bundles as you like within your MVC views / partial views / layouts / controllers / HTML helpers... the list goes on!
  3. Render the referenced scripts to the page (typically just before the closing body tag)

Making use of our Bundles#

Now we've created our bundles let's get the project serving up CSS and JavaScript using Cassette. First the layout file. Take the _Layout.cshtml file from this:

To this:

And now let's take one of the views, Login.cshtml and take it from this:

To this:

So now you should be up and running with Cassette. If you want the code behind this then take I've put it on GitHub here.

Optimally Serving Up JavaScript

I have occasionally done some server-side JavaScript with Rhino and Node.js but this is the exception rather than the rule. Like most folk at the moment, almost all the JavaScript I write is in a web context.

Over time I've come to adopt a roughly standard approach to how I structure my JavaScript; both the JavaScript itself and how it is placed / rendered in the an HTML document. I wanted to write about the approach I'm using. Partly just to document the approach but also because I often find writing about something crystalises my feelings on the subject in one way or another. I think that most of what I'm doing is sensible and rational but maybe as I write about this I'll come to some firmer conclusions about my direction of travel.

What are you up to?#

Before I get started it's probably worth mentioning the sort of web development I'm generally called to do (as this has obviously influenced my decisions).

Most of my work tends to be on web applications used internally within a company. That is to say, web applications accessible on a Company intranet. Consequently, the user base for my applications tends to be smaller than the Amazons and Googles of this world. It almost invariably sits on the ASP.NET stack in some way. Either classic WebForms or MVC.

"Render first. JS second."#

I took 2 things away from Steve Souder's article:

  1. Async script loading is better than synchronous script loading
  2. Get your screen rendered and *then* execute your JavaScript

I'm not doing any async script loading as yet; although I am thinking of giving it a try at some point. In terms of choosing a loader I'll probably give RequireJS first crack of the whip (purely as it looks like most people are tending it's direction and that can't be without reason).

However - it seems that the concept of async script loading is kind of conflict with one of the other tenets of web wisdom: script bundling. Script bundling, if you're not already aware, is the idea that you should combine all your scripts into a single file and then just serve that. This prevents multiple HTTP requests as each script loads in. Async script loading is obviously okay with multiple HTTP requests, presumably because of the asynchronous non-blocking pattern of loading. So. 2 different ideas. And there's further movement on this front right now as Microsoft are baking in script bundling to .NET 4.5.

Rather than divide myself between these 2 horses I have at the moment tried to follow the "JS second" part of this advice in my own (perhaps slightly old fashioned) way...

I want to serve you...#

I have been making sure that scripts are the last thing served to the screen by using a customised version of Michael J. Ryan's HtmlHelper. This lovely helper allows you to add script references as required from a number of different sources (layout page, view, partial view etc - even the controller if you so desired). It's simple to control the ordering of scripts by allowing you to set a priority for each script which determines the render order.

Then as a final step before rendering the &lt;/body&gt; tag the scripts can be rendered in one block. By this point the web page is rendered visually and a marginal amount of blocking is, in my view, acceptable.

If anyone is curious - the class below is my own version of Michael's helper. My contribution is the go faster stripes relating to the caching suffix and the ability to specify dependancies using script references rather than using numeric priority mechanism):

Minification - I want to serve you less...#

Another tweak I made to the script helper meant that when compiling either the debug or production (minified) versions of common JS files will be included if available. This means in a production environment the users get minified JS files so faster loading. And in a development environment we get the full JS files which make debugging more straightforward.

What I haven't started doing is minifying my own JS files as yet. I know I'm being somewhat inconsistent here by sometimes serving minified files and sometimes not. I'm not proud. Part of my rationale for this that since most of my users use my apps on a daily basis they will for the most part be using cached JS files. Obviously there'll be slightly slower load times the first time they go to a page but nothing that significant I hope.

I have thought of starting to do my own minification as a build step but have held off for now. Again this is something being baked into .NET 4.5; another reason why I have held off doing this a different way for now.

Update

It now looks like this Microsofts optimisations have become this Nuget package. It's early days (well it was released on 15th August 2012 and I'm writing this on the 16th) but I think this looks not to be tied to MVC 4 or .NET 4.5 in which case I could use it in my current MVC 3 projects. I hope so...

By the way there's a nice rundown of how to use this by K. Scott Allen of Pluralsight. It's fantastic. Recommended.

Update 2

Having done a little asking around I now understand that this *can* be used with MVC 3 / .NET 4.0. Excellent!

One rather nice alternative script serving mechanism I've seen (but not yet used) is Andrew Davey's Cassette which I mean to take for a test drive soon. This looks fantastic (and is available as a Nuget package - 10 points!).

CDNs (they want to serve you)#

I've never professionally made use of CDNs at all. There are clearly good reasons why you should but most of those good reasons relate most to public facing web apps.

As I've said, the applications I tend to work on sit behind firewalls and it's not always guaranteed what my users can see from the grand old world of web beyond. (Indeed what they see can change on hour by hour basis sometimes...) Combined with that, because my apps are only accessible by a select few I don't face the pressure to reduce load on the server that public web apps can face.

So while CDN's are clearly a good thing. I don't use them at present. And that's unlikely to change in the short term.

TL:DR#

  1. I don't use CDNs - they're clearly useful but they don't suit my particular needs
  2. I serve each JavaScript file individually just before the body tag. I don't bundle.
  3. I don't minify my own scripts (though clearly it wouldn't be hard) but I do serve the minified versions of 3rd party libraries (eg jQuery) in a Production environment.
  4. I don't use async script loaders at present. I may in future; we shall see.

I expect some of the above may change (well, possibly not point #1) but this general approach is working well for me at present.

I haven't touched at all on how I'm structuring my JavaScript code itself. Perhaps next time.