Thursday, November 1, 2012

NancyFx and bundling with Cassette

Working on a new side project built using NancyFx, I wanted to bundle and minify my css and script resources. Looking into the options, Cassette (*) seemed the most obvious option.

Since I struggled with the implementation a little bit, I documented the process below.

1. Cassette.Nancy package

Add the Cassette.Nancy package to the project.
PM> Install-Package Cassette.Nancy
Attempting to resolve dependency 'Cassette'.
Attempting to resolve dependency 'AjaxMin (= 4.60)'.
Attempting to resolve dependency 'Nancy'.
Attempting to resolve dependency 'Nancy.ViewEngines.Razor'.
Attempting to resolve dependency 'NLog'.
Successfully installed 'AjaxMin 4.60.4609.17023'.
Successfully installed 'Cassette 2.0.0'.
Successfully installed 'NLog 2.0.0.2000'.
Successfully installed 'Cassette.Nancy 2.0.0'.
Successfully added 'AjaxMin 4.60.4609.17023' to Project.
Successfully added 'Cassette 2.0.0' to Project.
Successfully added 'NLog 2.0.0.2000' to Project.
Successfully added 'Cassette.Nancy 2.0.0' to Project.
2. Bundle configuration

The Nuget package adds the CassetteBundleConfiguration class to the root of your project.

I'm lucky to have my assets structured rather simply, which makes setting up the bundles take little to no effort.

public class CassetteBundleConfiguration : IConfiguration<BundleCollection>
{
    public void Configure(BundleCollection bundles)
    {
        bundles.AddPerSubDirectory<StylesheetBundle>("Content");
        bundles.AddPerSubDirectory<ScriptBundle>("Content");
    }
}
Each sub-directory now becomes a bundle.

To arrange the files in the bundles, I added a bundle.txt file that defines the order to each sub-directory. For the css sub-directory it looks like this.
bootstrap.css
bootstrap-responsive.css
docs.css
3. Using bundles

To use these bundles in my view, I first reference them, for then to render them in their optimal location - css in the head section, and scripts just before the closing body tag.
@using Cassette.Nancy

@{
    Bundles.Reference("Content/css");
    Bundles.Reference("Content/scripts");
}

@Bundles.RenderStylesheets()
@Bundles.RenderScripts()
4. First try

When you now browse to your application, and view the source, you'll notice that Cassette is already in play, yet the assets are not bundled nor minified.



5. Enable optimization

Apparently when using NancyFx, you need to explicitly enable optimization.
By default, the output from Cassette is not optimized. When output is optimized, Cassette modules are combined (bundled) based on the configuration and sent to the client as a single lump per bundle instead of lots of individual files.
When you're using ASP.NET MVC, this is dependant on the compilation debug switch.

The best place to enable this, is probably in your bootstrapper.
public class Bootstrapper : DefaultNancyBootstrapper
{
    public Bootstrapper()
    {
        Cassette.Nancy.CassetteNancyStartup.OptimizeOutput = true;
    }
}
6. Second try

This time around, the assets do get bundled and minified.



* It wasn't until today that I noticed the asset in Cassette. 

4 comments:

  1. great article to get started.

    You might want to optimize only when in release mode. this will make it easier to debug javascript during debug mode.

    #if !DEBUG
    Cassette.Nancy.CassetteNancyStartup.OptimizeOutput = true;
    #endif

    Here the discusion about putting assets in different folder besides Content and its advantages. https://github.com/NancyFx/DinnerParty/pull/6

    ReplyDelete
    Replies
    1. Thanks for your comment.

      I actually never considered moving assets to another folder than Content. I do understand your reasoning, but it's not something that I've come across myself so far.

      Delete
  2. Thomas Van MachelenNovember 1, 2012 at 8:40 PM

    Just so you know: Cassette also has CSS in it.

    ReplyDelete