Tuesday, October 11, 2011

Introducing MinCat for MSBuild / Visual Studio

I am happy to release a new project today. Introducing MinCat: the JavaScript and CSS minimizer and concatenation utility for MSBuild and (optionally) Microsoft MVC.

The Problem

JavaScript presents an interesting problem to many web developers. As a client-side scripting language, it is very forgiving about how it is used, and how it is included in the context of a larger web document. There is a sloppy way to serve JavaScript, and a professional way to serve JavaScript.

The "sloppy" method covers many possibilities: inline amongst the HTML, buried inside the href of an anchor, or heaped into the <head> in a stack of script-tags that comes up to your eyeballs. All of these methods work, but they also have issues.

The current best practice recommends a different approach. Instead of including HTML inline, we should serve it as external files. Moreover, these files should be minimized to reduce the page load time. If multiple files are necessary, we should concatenate them to reduce the number of HTTP requests required to load them.

However beneficial this is to the end-user, the act of minimizing and concatenating script files adds an additional burden to the developer. Fortunately, it is quite possible to automate this process, and numerous tools exist to facilitate this. MinCat is such a tool.

The Solution

MinCat exists to address exactly the problem described above. It is a small, simple tool that lets you control the minimization and concatenation of your JavaScript files. It is designed to integrate directly with MSBuild. Because Visual Studio uses MSBuild under the hood, this means it provides easy integration with your existing Visual Studio web projects.

It's usage is simple and straightforward. By adding <Minimize> or <Concatenate> commands to your project file, you can control how your JavaScript is prepared for your source files. For instance, this command would minimize all of the JavaScript files in your "Scripts" folder, placing the resulting files in "Scripts\min":

<Minimize Input="Scripts\*.js" Outpath="Scripts\min\" />

For MVC projects, MinCat also provides an MVC Script helper extension. At a basic level, this extension will facilitate the switch between the minimized or development version of a particular file. However, it really begins to shine when combined with the new "directives" that MinCat offers (more on those later!)

@Html.Script(Url.Content("~/Scripts/MyScript.js"))

Since minimizing JavaScript is not always a quick operation, MinCat will only re-minimize files if they have changed since the last time they were minimized. It accomplishes this by comparing the last modified date of the source files with the corresponding date on the minimized files. This helps keep the overall build time down to a minimum.

MinCat comes bundled with the excellent YUICompressor. However, it is designed so that the compressor is a modular component, and it could easily be reworked to use a different compression engine.

New JavaScript Directives

As if all that weren't enough, MinCat additionally provides support for a number of directives, designed to be placed in the actual source of individual JavaScript files. These provide further control over how each file is treated by the minimization process. Because these directives are fully supported by the (optional) MinCat MVC Script helper extension, they provide some exciting new ways to organize and structure your JavaScript.

/* @skip minimize */
This directive will cause the source file to never be minimized, even if it is otherwise included by a wildcard in the input path. This has no effect when used with the MVC helper extension.
/* @require "filename.js" */
This directive instructs the minimizer that the current file depends on code from another file. When this file is minimized, all required external files will be collected (recursively, so a required file can also require a file), sorted into the correct order, reduced to a distinct list, and concatenated in front of the file that specifies them. Therefore, the resulting minimized file will contain everything it needs to function. When used with the MVC Script helper extension, each required file will be loaded in its own <script /> tag, in the correct order, before the <script /> tag that contains your target file.
/* @include "filename.js" */
This directives causes the minimizer to include the complete contents of the specified file directly inline, wherever that directive is found. When used with the MVC Script helper extension, the loaded <script /> file will also include the desired content directly inline.

Note the differences between @require and @include. The @include directive is primarily exciting because it allows you to create assembly-like structures:


var Global = (function () {
  "use strict";

  var internal = {};

  function Global() {
    var instance = {};

    /* @include "Access to Internal, Instance, and Global Variables.js" */
  }

  /* @include "Access to Internal and Global Variables.js" */

  /* @require "Access to Global Variables Only.js" */
  return Global;
}());

Learn More!

MinCat is open source software, released under a BSD License. It is available on BitBucket, and as a NuGet package.

Complete documentation is available on its wiki page.

As always, I am excited to learn how people are using my tools. If you try this out, please feel free to drop me a note with your impressions. And of course, always let me know if you find a bug!