How to minimize and combine your JavaScript on Compile using Visual Studio

Last night I had the pleasure of presenting at the Orlando Dotnetnuke user group on this subject. This post is a follow up to that presentation.

I haven’t presented in a while and I have to admit I was a bit nervous, and to make matters worse the projector was not wanting to cooperate with me. Suddenly the room got really hot and I started sweating… I’m sure my sweating had nothing to do with the silence in the room while people waited for the technical problem to be resolved :)

It turned out that when I closed my machine at the office, it was connected to multiple monitors, so when I hibernated it remembered those settings and I could only get to projector to work as an extension of my desktop, like a second monitor.

Anyways… great learning opportunity, and I can’t wait to try it again. On to the technical stuff…

Goal:

I want the JavaScript file references in my pages to load the debug version of the JavaScript files when my visual studio solution is in debug mode. When Visual Studio is in release mode, I want a single compressed JavaScript file to be loaded.

Solution: (download)

Step 1: Download jsmin.exe from http://www.crockford.com/javascript/jsmin.html

Add it to your scripts directly in your project. You should not deploy this with your project, it is only needed during compile time to minimize and combine your JS files.

I use the following structure to store my javascript files:

captured_Image.png[4] 

Step 2: Add a post build command

Right click on your project, click properties. Select the compile tab and click on the build events on the bottom right of the screen.

captured_Image.png[6]

Enter the following command in the post-build event command line field:

 type “$(ProjectDir)content\js\libraries\*.debug.js” | “$(ProjectDir)content\js\libraries\jsmin” > “$(ProjectDir)content\js\libraries.min.js” 

captured_Image.png

This command does two things. First it looks for all the javascript files in your “content/js/libararies” directory ending with .debug.js and pipes it into the jsmin executable as one long string. Second it tells jsmin to output the compressed and combined JavaScript code to a single file content/js/libraries.min.js

Step 3: Add a debug flag

We need a way to figure out if we are in debug mode or release mode so to do this we are going to add a shared function to a helper library that will return true if in debug mode, and false if in release mode. In this function we use a compiler statement to compile “return true” when in debug mode and “return false” otherwise.

Public Shared Function IsInDebugMode() As Boolean
#If DEBUG Then
        Return True
#Else
        Return False
#End If
End Function

Step 4: Add a conditional statement to your pages

To your page you simply add this:

<% If jsmin.Helpers.IsInDebugMode Then%>
    <script src=”content/js/libraries/01-jquery-1.3.2.debug-vsdoc2.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/01-jquery-1.3.2.debug.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/02-jquery-ui-1.7.2.custom.debug.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/03-jquery.autocomplete.debug.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/04-jquery.blockUI.debug.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/05-jquery.cluetip.debug.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/06-jquery.form.debug.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/07-jquery.validate.debug.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/08-jquery.values.debug.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/09-json2.debug.js” type=”text/javascript”></script>
    <script src=”content/js/libraries/10-app.debug.js” type=”text/javascript”></script>
<% Else%>
    <script src=”content/js/libraries.min.js” type=”text/javascript”></script>
<% End If%>

This tells your page that when IsInDebugMode is true, reference all the debug scripts, otherwise reference only the libraries.min.js script

Making it better

This is great, but I dislike having to add these conditional statements to every page, so created another simple helper function that goes through my libraries directory, grabs all my debug files and creates the html string to be included in the page. following the same rules, if in debug mode all the scripts, if in release mode only libraries.min.js

Public Shared Function JSReferences() As String
    Dim key = “JSReferences”
    Dim context = HttpContext.Current

    If context.Application(key) = “” Then
        If IsInDebugMode() Then
            Dim data = New StringBuilder
            For Each f In Directory.GetFiles(context.Request.MapPath(“~/content/js/libraries/”))
                f = f.ToLowerInvariant
                If Path.GetExtension(f).ToLowerInvariant = “.js” AndAlso _
                        f.EndsWith(“vsdoc2.js”) = False AndAlso _
                        f.EndsWith(“vsdoc.js”) = False Then
                    data.AppendLine(String.Format(“<script src=’{0}’ type=’text/javascript’></script>”, “content/js/libraries/” & Path.GetFileName(f)))
                End If
            Next
            context.Application.Add(key, data.ToString)
        Else

            context.Application.Add(key, “<script src=’content/js/libraries.min.js’ type=’text/javascript’></script>”)
        End If
    End If

    Return context.Application(key)
End Function

now I can replace the code in my html pages with this single line statement.

<%=jsmin.Helpers.JSReferences%>

That’s it. Enjoy!

Thanks to Dave Ward for the original idea http://encosia.com/2009/05/20/automatically-minify-and-combine-javascript-in-visual-studio/

14 responses to this post.

  1. Excellent presentation last night, it was easily my favorite of the night. I will definitely be making use of this in the project I am currently working on. I’ll probably start wiring it up this evening….

    Reply

  2. For all its worth, I took a slightly different tack on the references. Rather than using a StringBuilder to emit references on the page, I created a common method that registers the correct scripts using the Page.ClientScript.RegisterClientScriptInclude() method and then call my common method on the initial page load for my view controls.

    Reply

    • That’s a good idea Ron. I’d love to see your code.

    • I also use helper methods in a bunch of other places to output common html bits. The idea is to keep it DRY.

      Helper methods is the control story for ASP.NET MVC and other MVC implementations.

      I have a library of helper controls that allow me to do something like this:
      Html.Text("textbox1").label("First Name").Value(ModelData.Value).ValRequired

      This will create a textbox it’s label, assign the value and add a required validator, all in one line of code. I use it for doing hover image tricks, AJAX submit etc.

      Another example this one an AJAX call:
      Html.Link("LinkName").onclick(JS.SubmitAjax('url").Post.UpdatePanel('panel1')

      The posibilities are endless. Specially when you couple helper methods with the power jQuery.

  3. I am getting an error code of 225 when trying to use jsmin.exe – can you tell me what that code means?

    thanks
    Michael

    Reply

    • Hi Michael. This is most likely caused by jsmin being unable to minify one of the files being passed into it. What I would do is use the command prompt and run jsmin on each file individually so you can norrow it down to which script is causing the problem. This will give you a starting point to troubleshoot it.

      Hope this helps.

  4. sorry error 255

    Reply

  5. if I run this from the command prompt it looks like it is trying to run the js

    “home.debug.js” | jsmin > test.js

    I get a windows script host error

    Reply

    • the syntax for the command prompt is like this:

      jsmin test.js

      The: “type ‘xyz.js’ | ….” command is used by the compiler to read a text file and pipe it into another program in this case jsmin.exe

    • When I read your instructions I thought the “type” part was a human instruction – not a computer command – when I added type to the start fothe command it worked – DOH – thanks for your help – nice program, saved me tons of manual combining!

    • my pleasure. cheers!

    • The blog comment engine keeps messing up my comment. Let’s try it this way:

      the syntax for the command prompt is like this: jsmin test.js

      The: “type ‘xyz.js’ | ….” command is used by the build system to read a text file and pipe it into another program in this case jsmin.exe

      -Mitch

  6. Posted by runatServer on July 22, 2011 at 2:45 am

    This Solution currently worked for ASP.NET Web Application only! Not for ASP.NET Web Site Template + Web Deploymnet Project! This limits the possibilities.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.