MVC - Selectively Loading jQuery Debug or Release Scripts

Download Project Source

Page load times are critical to a satisfying user experience.  One of the simplest ways to reduce load times is to Minify your jQuery and Javascript files.  I won't go into detail on how to Minify those files in this post (hint: http://yui.2clics.net/).  Instead, this article deals with the headaches of debugging Minified files.


For example, here's a typical Javascript error:




However, its impossible to debug this issue because I'm referencing the Minified version of jquery-1.5.1.  I'd have an easier time defusing a small nuclear device.  On the other hand, I don't want to go referencing debug versions of Javascript files throughout my code only to have to do a search and replace every time I want to release.


The solution is in MVC's Html Helper classes.


The @Html and @HtmlHelper methods are provided to render html controls on the view in a code-centric way.  However, their functionality isn't limited to the methods built into .NET.  We can easily add additional functionality to these classes via Extension Methods.

Extension methods are used to ehnance and extend classes without the need to modify, inherit or subclass the original base class.  In our example, we will be writing an Extention Method for the HtmlHelper class called LoadScript.  This method will return an html string with the correct Javascript tag for the current release mode.

First, we need to create a new class called CustomHelper.  The name isn't important, however, all Extension Methods must reside in a static class by nature.


  1. public static class CustomHelper
  2. {
  3.  
  4. }


The extension method will take in an enumeration and the HtmlHelper class.  Note we use the keyword this to pass on the HtmlHelper.  This is the heart of the extension method.


  1. public static MvcHtmlString LoadScript(this HtmlHelper helper, JavaScript script)
  2. {
  3.     // Instantiate a UrlHelper
  4.     var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
  5.  
  6.     string scriptHtml = "<script src='{0}{1}' type='text/javascript'></script>";
  7.  
  8.     #if DEBUG
  9.         scriptHtml = string.Format(scriptHtml, urlHelper.Content("~/Scripts/"), _debugScripts[script]);
  10.     #else
  11.         scriptHtml = string.Format(scriptHtml, urlHelper.Content("~/Scripts/"), _releaseScripts[script]);
  12.     #endif
  13.  
  14.     return new MvcHtmlString(scriptHtml);
  15. }


LoadScript is responsible for creating a script tag that will be returned to the view.  The compiler directive #if DEBUG is used to determine the release type, and the appropriate file name is returned from a Dictionary.  We use the UrlHelper class to get the relative path to the scripts.  This is important in case you domain root changes.

Finally, to call the new helper method.  Anywhere you reference a Javascript file, you can now replace with the helper method.  Generally this is done in the <head> tag on your site (_Layout.cshtml in MVC3's case).  Simply add the following code:


  1. <head>
  2.     <title>@ViewBag.Title</title>
  3.     <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
  4.  
  5.     @*<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>*@
  6.     @Html.LoadScript(JavaScript.Jquery)
  7.  
  8. </head>


Note that line 5 produces the same Html as line 6 in Release mode, however while in Debug, the debug version of jquery is loaded.

The source code above has all the details not described here.

There are some limitations to this method however.

  1. If scripts are added or script names are changed, the code needs to be re-compiled.  This could be overcome by loading the scripts into the dictionary at runtime.
  2. Scripts with Visual Studio Intellisense documentation, such as jquery-1.5.1-vsdoc.js, won't be read in by the IDE as the script tag doesn't exist at design time.  To get around this limitation, one trick is to use the following code. Because it is rendered in a block that will never execute, it will never write the line to the Html, however the IDE will use the script to enhance Intellisense.
  1. <head>
  2.     <title>@ViewBag.Title</title>
  3.     <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
  4.  
  5.     @if (false) { <script src="~/Scripts/jquery-1.5.1-vsdoc.js" type="text/javascript"></script> }
  6.  
  7.     @Html.LoadScript(JavaScript.Jquery)
  8.  
  9. </head>

Comments

Popular posts from this blog

SQL Reporting Services - Viewer broken in Non-IE Browsers: FIX

Dynamics AX SysFileDeployment Framework - Deploy files automatically (using resources) to the client on login

Dynamics AX 2012 - Visual Studio Team Services Custom Work Item Fields Break Version Control (Error TF237121)