SquishIt – The Friendly ASP.NET JavaScript and CSS Squisher

Please don’t post support questions into the comments on this post! If you have questions, please post them to the SquishIt Google Group.

I’ve received more feedback via e-mail on SquishIt than on pretty much any other post or project I’ve ever worked on in the past. I appreciate it! Most all of the feedback has been extremely positive, with people thanking me for creating such a great tool. Well, I don’t know how great it is, but people seem to like it!

Anyways, the one complain that I keep hearing over and over again is that I need to create a better guide to using it. And I agree, even though SquishIt is a breeze to use, I still need to provide a better "getting started" document.

But before I start rambling, let’s get on with the tutorial….


Getting Setup With SquishIt

As a side note, there are quite a few more options that SquishIt provides to tweak the squishing experience, but this post just covers the basic options for squishing your CSS and JavaScript.

The first thing that you need to do is head over to the SquishIt download page on GitHub and grab the zip file for the latest build of SquishIt. If you want, you could also grab the source and build it from there. Your choice!

The next step is to grab a current ASP.NET or ASP.NET MVC project. You could also create a new one, like I am going to do for this post. I’m first going to create a folder for my project, and inside of that folder I am going to create my usual “src” and “lib” folders, like this:

project folder

In the “src” folder I just have my project source, and in my “lib” folder is where I am going to drop any third party libraries that my project uses. Inside of my “lib” folder I am going to create a “SquishIt” folder:

image

And then put the contents of the zip file I downloaded from GitHub in there:

image

Now we are ready to get started in our website!

Getting Your JavaScript And CSS Setup

Now that we have the SquishIt binaries in the site, we can go over into Visual Studio and start getting everything wired up. The first thing we need to do is to get some CSS and JavaScript into our project. I’m going to pull in the uncompressed CSS from the 960 Grid System project, and then an unminified copy of jQuery and jQuery UI:

image

Note: Here I am using a Web Forms project, because I want to show that even though this was originally designed with ASP.NET MVC in mind, it works just the same in Web Forms!

Let’s first integrate the CSS and JavaScript into the website in the normal fashion, this will let those who are migrating their sites do it a bit easier.

First we will add tags to reference both the CSS and JavaScript in the page:

<head runat="server">
    <title></title>
    <link type="text/css" rel="stylesheet" href="/css/reset.css" />
    <link type="text/css" rel="stylesheet" href="/css/text.css" />
    <link type="text/css" rel="stylesheet" href="/css/960.css" />
</head>
<body>
    <form id="form1" runat="server">
    </form>
    <script type="text/javascript" src="/js/jquery-1.4.2.js"></script>
    <script type="text/javascript" src="/js/jquery-ui-1.8.1.js"></script>
</body>

Next, we will look in the Chrome developer tools to see just how much CSS and JavaScript that we are passing across the wire:

image

So, 11KB of CSS and 560KB of JavaScript, that is a ton! Let’s go ahead and see if we can do something about that.

Integrating SquishIt Into Your Website

The next thing we need to do is add a reference to the SquishIt.Framework.dll from the web project:

image

After we have created a reference, now we are ready to squish some Css and JavaScript! The first thing you are going to want to do is to import the SquishIt namespace at the top of the page:

<%@ Import Namespace="SquishIt.Framework" %>

Now we can create a Bundle. A Bundle is a single group of files that will be compressed into a single file. In this first example we are going to create a CSS bundle:

<%= Bundle.Css()
        .Add("~/css/reset.css")
        .Add("~/css/text.css")
        .Add("~/css/960.css")
        .Render("~/css/combined_#.css")
%>

In this code we are starting with the Bundle class, and then calling the "Css" method which lets us start a CSS bundle. Next we just call the "Add" method over and over with each file we want to add. Notice that I have put the tildes (~) on the front of each path, SquishIt will automatically expand app relative paths in websites. And finally we call the "Render" method which writes the bundle out to a particular file.

Also notice that we have the "_#" in the output file name. This will cause bundler to render a hash of the file contents into the filename. This allows us to invalidate the file if a change is made to one of our CSS files. If you don’t include that in there, then the hash is appended as a querystring parameter. This will also work for invalidating the file, but could cause some caching proxies not to cache the file. On the flip side though, if you keep changing files a lot, you could build up a bunch of combined CSS files in your folder since the file name keeps changing. You’ll have to manually clean them out.

Now that we have squished our css, we can do the same thing for the JavaScript:

<%= Bundle.JavaScript()
        .Add("~/js/jquery-1.4.2.js")
        .Add("~/js/jquery-ui-1.8.1.js")
        .Render("~/js/combined_#.js")
%>

Looks very similar, right? We just do the exact same thing.

WAIT YOU’RE NOT DONE YET!

I have one little catch that you need to know about. If you are like me, then you probably have your web.config set to debug="true" most of the time. And if you do, then when you run it, you are going to see the references to the JavaScript and CSS files spit out normally and they won’t be compressed. This is because trying to debug and develop with compressed CSS and JavaScript is a HUGE pain in the butt. In fact, it is practically impossible. So when you are operating in debug mode in your website, SquishIt keeps the files uncompressed and separated.

If you set to debug="false" you will get the combined and compressed JavaScript and CSS, or you can call the "ForceRelease" method like this:

<%= Bundle.Css()
        .Add("~/css/reset.css")
        .Add("~/css/text.css")
        .Add("~/css/960.css")
        .ForceRelease()
        .Render("~/css/combined_#.css")
%>

Great! Just remember since SquishIt caches everything, if you make a change like this, you’ll need to restart your site by poking the web.config or some other method.

Now you’re ready to squish some CSS and JavaScript!

When we run the website, we will now see only a single CSS and JavaScript reference, and when we look in the Chrome developer tools to see how much JavaScript and CSS we are passing, we get a much better picture:

image

Phew. We got almost a 50% reduction in size! PLUS, just as importantly, we got three less http requests. Not bad for 5 minutes of work! If we had a production site, which might have dozens of JavaScript files, this could be an enormous time saver.

Finally

I hope you see how easy it is to integrate SquishIt into your website. In only a few minutes you can be up and running with all of your JavaScript and CSS being combined and compressed. It makes your life much easier, and your users will thank you!

Please don’t post support questions into the comments on this post! If you have questions, please post them to the SquishIt Google Group.

Be Sociable, Share!

143 comments

  1. Thank you Justin! It is so amazing useful cool!

  2. That has to be one of the COOLEST things I’ve seen for MVC so far :)

    How does it fair with Razor?

  3. Justin Etheredge

    @Glyn It works fine with Razor. You can either put it in a @{ } block or you can use the MVC assembly that comes with it which includes an extension method that spits out an MvcHtmlString.

  4. Excellent! Keep up the good work :)

  5. How do I handle this?

  6. background: transparent url( ‘leftmenu_seperator_bg.jpg’ ) repeat-x 0 0;
    background: #bfdbff url( ‘top_page_right.png’ ) no-repeat 100% 0;

    –> after using SquishIt:

    background: transparent’leftmenu_seperator_bg.jpg’ ) repeat-x 0 0;
    background: #bfdbf’top_page_right.png’ ) no-repeat 100% 0;

  7. Justin Etheredge

    @cuongnt Could you please post your issue to http://groups.google.com/group/squishit Also, please give a bit more info about your file locations and configurations.

  8. Dear SquishIt users, I’ve published on NuGet (http://www.nuget.org/List/Packages/SquishIt.Contrib.Mvc) a contribution package for SquishIt. Read more on: http://www.dev-one.com/Blog/Details/13. Feel free to comment!

    Fabian

  9. Just added squishit to a MVC3/Net4/Razor projects, working great.

  10. Justin Etheredge

    @Alex Awesome, glad to hear it!

  11. Cufon doesn’t seem to play nice when placed as part of SquishIt minifier. Some odd character in Cufon rejected.
    (http://cufon.shoqolate.com/generate/)

    Everything else is working sweet.

  12. Hey Justin,

    Amazing work! SquishIt has been really useful.

    Is it possible to pass a directory path to SquishIt instead of each JS path?

  13. Great stuff! Used to minify css and js as part of a build script, this is a lot easier.

  14. Justin Etheredge

    @Amin Sorry for the delay, no you cannot pass a folder, but that is mainly due to the fact that JavaScript includes have a dependency on ordering. So you probably need certain files (like jQuery) included first, then your other dependencies following that. If we included entire directories, then we would still need some way to specify ordering. It is something that we could look into, but all the ways that have been suggested seem kludgy.

  15. @Justin: Awesome, this is great!
    @Fabian This makes it perfect!

    1 problem though:
    AspNetSprites (via NuGet) creates some css to include images. The names of the css classes are the names of the files. After using Squishit, the names are no longer valid:

    .ApplyingDDD\.gif
    ==>
    .ApplyingDDD\5c\2egif

    Any idea how to fix this?

  16. Justin Etheredge

    @Michael Yeah, we have had some bug reports with the CSS path rewriter. Unfortunately I haven’t had any time to go in and sort it out. If you head over to the SquishIt google group and post some more detail I can try to help you out.

  17. @Justin thank you. I will do that ;)

  18. @Justin I am trying to add this to the pre-compiled web application based on .Net Framework 3.5. I added squishit assemblies to the site bin folder and added Import tag and Bundle calls to an aspx file. I get a runtime error: “Could not load file or assembly ‘SquishIt.Mvc’ or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.” Is squishit built on .Net 4? Does a previosu version for .Net 3.5 or 2.0 exist?

  19. Nice.
    If I intend to place the resulting CSS and JS on a CDN but need to minify from local assets, can I specify a hostname that will be rendered in front of the resulting minified filename?
    Cheers, Steve

  20. I think SquishIt is an excellent tool but I’d like to make a suggestion: Instead of having to include “~/js” or “~/css” for each Add method call, you could set this value in the JavaScript and Css method calls. If a particular file was located elsewhere, you could have a second parameter, in the Add method (and also in the Render method), that overrides the files location.

  21. Justin Etheredge

    Steve, I agree that it would be a good idea to let the user set the root paths for CSS and JavaScript files. Thanks!

  22. I like the this library. But is it possible to use them in the ASP.NET 2.0. I tried it. But i get “default parameter” error.

  23. Hm… This will have to be tested with SharePoint farms, in order to tag is at “SharePoint” applicable.
    Last thing one want’s to do is to play with cache, form C#, which is behind SharePoint pages.
    At worst this might provoke the need to re-start the farm.
    http://latenightsp.wordpress.com/2011/03/16/sharepoint-config-cache/

    For othe scenarios this might be good. What is the API to use ti from “code behind” ?

  24. Nice! I have an issue though. Nowadays, the JS librairies tend to load JS files on the fly, when required. Is there a way to use SquishIt to automatically squish the requested JS files?

  25. Enjoyed using SquishIt in one of my projects. However, it will be nice to have support for uglify and Google closure along with YUI compresion as alternatives.

    Also a great thing will be to have separate configuration where i can define the mappings like its possible in JammIt (http://documentcloud.github.com/jammit/) to do via YAML

    Cheers
    Mehfuz

  26. The problem with Google Closure is that you either need the Java runtime on your box, or you need to pass the files through a web service. Neither really works well with the “compress at runtime” use of SquishIt. If you have an alternative to this, then I’d happily include the Google Closure compiler. In fact, SquishIt had it early on, but it was a pain to get setup and working, which was the whole point of SquishIt.

    And yeah, the config file abilities of Jammit would be cool.

  27. Fantastic tool. I’ve been looking for a solution that offers pretty much everything SquishIt does for months, with no luck. My main issues were only minifying and compressing when in production and source control friendly. I don’t know why it took me so long to find this. But I’m very happy I have! Thanks.

  28. Any plans to fix the Cufon problem that Brandon mentioned way back on May 10? I’m getting bitten by it, also.

  29. Justin Etheredge

    @Tim The minifiers are powered by the YUI minifier, the MS Ajax Minifier, or JsMin. Any errors that occur during minification are a product of one (or all) of those libraries. There are some configuration options for them, but minification is not a perfect science, and there are definitely places where minifiers can screw up some JavaScript files. If you’re having trouble, try switching minifiers or removing the file from your bundle. Sorry!

  30. anyone else having problems with Razor MVC3 I had two which I sorted so just to help anyone else who’s thick :

    1) System.IO.IOException
    Unable to open file

    Think this was to do with perms on the folder or some such, seemed to fix by moving dlls into the project folder (were outside before)

    2) Nothing being rendered onto resulting html page

    This was a razor thing, escaping strings, simply do :

    @{
    MvcHtmlString.Create(Bundle.Css()
    .Add(“~/Content/Reset.css”)
    .Add(“~/Content/Site.css”)
    .Render(“~/Content/combined_#.css”));
    }

    And now – thank you all – fantastic !

  31. This is great! Super simple to use. I think the chainable methods really captured the spirit of it.

    Question – Is it possible to render just the path to the CSS or JS file without the HTML tags?

    head.js({“label-for-files” : “” };

    While the way it operates makes sense, I’d love to be able to inject these compressed files into some async or module loading frameworks like HeadJS or RequireJS.

    Thanks for the work!

  32. I’d caution against this approach. The architecture of this codebase processes files during runtime. That means for every page view this code must execute. It would easily become your bottleneck on the server taxing cpu and memory degrading performance and increasing response queue times. It would be much more advantageous if the code was re-written as an msbuild task or a powershell cmdlet that can be executed during build time on the developers machine and also in an official automated build process. This way when the code is released to production the “squished” files are already generated and do not have to be created on the fly during runtime.

  33. Justin Etheredge

    @StrandedPirate I appreciate the concern, but SquishIt does not re-minify the files on each request. The output is cached and used on subsequent requests. This causes very little overhead.

  34. I’m a UI Developer and love this! The only issue I have is that I have to rebuild my app to see the changes in my .CSS and .JS files. As a UI dev, I’m constantly making changes to those files so having to re-build to see the changes kind of sucks. Is there any way to allow the js and css to squish without having to rebuild? Ideally, this would only happen when in debug mode.

  35. Andrea Williams

    When dealing with a server farm, if one wants to generate the squished files in advance as part of the build and deploy process, do you have a recommendation for the best approach for doing this when using MS deploy?

  36. Well done! Very useful tool! Thanks for sharing it!

  37. How is SquishIt related to the new bundling/minification features of .NET 4.5? The usage is a bit similar don’t you think?

  38. Justin Etheredge

    Similar, yes. But there are quite a few things you can do with SquishIt that you cannot with the bundling/minification features of .NET 4.5. I need to put together a list of them.

  39. I have gotten this setup but SquishIt is not outputting a or a tag. It has created the js and css files. Am I missing something?

    An example of bundling the Css files is:

    This creates a css file called Combined_28F85915A28BB113491A45552453A87D.css but SquishIt is not adding

    Am I missing something?
    I’ve also tried every combination of debug=”true”/”false” in the web.config along with calling ForceRelease before Render in the SquishIt call.

    I am running VS2010 .NET 4.0 standard Website (Not MVC)

    Jason

  40. SquishIt is awesome: good api and a charm to use. Many thx!

  41. It looks like Squishit does not support CSS3 keyframe animations in it’s minification process. Is this a known shortcoming? If so, are there plans to fix it?

  42. Vladimir Korukov

    Hey, I was using just the js minifier (I needed one an this was the first link I found) and ran into a bug.
    I was minifying the following code:
    ….
    var a = Math.min(…)
    / Math.max(….);
    ….
    When I got an exception “Error: JSMIN unterminated Regular Expression literal : 10.”.
    The “/” symbol on a new line was causing the problem. Moving it to the previous line fixed it.

    Otherwise works great.

    Vladimir

  43. Justin , that was a quick and painless integration!! Thank you very much!

Leave a comment