SquishIt – The Friendly ASP.NET JavaScript and CSS Squisher

Writing

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.

Loved the article? Hated it? Didn’t even read it?

We’d love to hear from you.

Reach Out

Comments (146)

  1. @Richard SquishIt is just a front end for other compression libraries, making it a bit easier and more friendly to integrate it into your ASP.NET website. In fact, you can pick from a few of them. By default, the JavaScript and CSS compress are both performed by the YUI libraries. You can also use js-min or if you have Java installed, you can use the Google Closure compiler.

  2. @Michael Hmmm, doubt it. I’ve never used ASP.NET Themes all that much, so I’m not entirely familiar with their inner workings. I’m sure you could detect the current theme and then render different bundles accordingly, but I doubt it would play nice with the normal way that ASP.NET does themes.

  3. Hey Justin, I’ve seen your posts about Bundler/SquishIt and just got a chance to finally try it out today – great work!

    I’ve run into a bit of a problem, and wanted to see if you’d thought about it yet…

    1 Lets say I have a directory structure like so:

    ~/Content
    –Css
    —-site.css
    –Js
    —-SomePlugin
    ——Images
    ——–blah.png
    ——somePlugin.js
    ——somePlugin.css

    2. Now lets say "somePlugin.css" has a relative reference to blah.png:

    background-image: url(images/blah.png);

    3. I want to render site.css and somePlugin.css together, and I decide to put "combined_#.css" into the ~/content/css directory.

    4. The portion of "combined_#.css" that contains the relative URI to blah.png is now broken, as the relative URI resolves to "~/content/css/images/blah.png" instead of "~/content/js/somePlugin/images/blah.png".

    It would be ideal if SquishIt could rewrite the relative URIs to be relative to the destination of "combined_#.css".

  4. @Troy Yeah, someone commented on that issue before, and I thought about it… but at this point I’m not ready to start parsing the css in order to fix it. I’m going to put it in the issue list for potential future fixes, but don’t hold your breath. 🙂

  5. Hmm, well that is unfortunate, as you’ll likely run into this with most sufficiently complex sites. Currently SquishIt requires that you either a) keep all CSS files in the same directory or b) use absolute URLs when referencing images from your CSS – neither of which is ideal (especially since many jQuery plugins come prepackaged with css files using relative paths).

    I actually think the parsing problem is the minor bit of work here – every URI in a CSS file that I can think of should be matched on "url(.+)". It seems to me the hard part would be calculating what the correct relative path for each one should be.

  6. @Troy Yeah yeah yeah 🙂 I’m looking into it. I don’t usually store my js in a heirarchy, and so I don’t really experience the issue. I do however see how it could be a problem. Perhaps my first response was a bit hasty.

  7. @Troy Thanks for doing that, unfortunately I also implemented an algorithm to perform the same task. We took very different paths to the same end. I am getting ready to check my change in, please test it if you get a chance, I’m sure we will find a few bugs.

  8. Looks like a really easy to use and useful tool. Is there any support for serving the [i]squished[/i] files from different a domain from the main site? This would be to allow the user to maximize parallel downloading ability of browsers.

  9. Awesome 🙂 I love (and i’m still so shocked) that people are using the port of YUIC I did on codeplex 🙂 Never thought anyone would really known about it, let alone use it 🙂

    Now, I wish I could find someone to help me figure out how to intergrate the YUIC.NET dll into a TFS _2010_ build workflow thingy … (i’ve already doc’d about how to do it for 2008).. but i digress *blush*

    Now … i need to keep working on getting my REST MVCContrib stuff done.

    Kick ass work Justin 🙂

    -from another Justin / PK-

  10. @Justin It is great work! Thanks for putting the time into it.

    I wish I could help you out with the build, but unfortunately I don’t use TFS, so I couldn’t really help you out there very much.

  11. @Phil I’ve actually thought about that a bit myself… you know… having the release mode reference a different domain. Or at least having some way to tell it to use a different domain.

    I’m thinking that it might make sense to pull it from a web.config setting or something. But anyways, I’ll put a bit more thought into it, I’m going to need this functionality as well.

  12. Justin – really cool utility! I had it up and running in minutes thanks to this brief tutorial. It seems like only yesterday you were showing me the joys of a high contrast theme in Visual Studio.

    Question for you though – any recommendation on the minimum permission settings for the ASPNET user for generating the bundled CSS / JS file?

  13. @Brandon The ASPNET user will need read access to wherever the css and js is stored… which should always be the case.

    It will also need write access to the output folder where the compressed css and js is being written out to. This is usually the case though, as even in medium trust you should have access to read and write in your application’s directory structure.

  14. I’m running into a DirectoryNotFound exception when I use this in an ASP.NET MVC project.

    The error message says: Could not find a part of the path ‘c:sourcecrewWebcssglobal_1687CDDE6FAD4DA91F481F480CB774DE.js’.

    This path does exist, but the file obviously doesn’t. Is there something I’m missing?

  15. Great, I am glad to see multiple domain functionality is something you are looking at.

    The other issue aside from configuration I guess is the mechanism to get the squished file to the other domain which could be on a different machine or set of machines…

  16. @Phil Agreed, but I’m not sure if that is something that should be handled by Bundler. I would think of that more as a deployment step. Trying to put something like that into Bundler could get really messy and complicated. I will look into it however, as it is something that I am going to need in the future.

  17. Hey Justin, great tool. I generally only reference one .css file in my apps and the use @import to call any other css files my app needs. This keeps things DRY if I have multiple files that need a reference to the css. Will SquishIt ever be able to read the @import url("file.css") and include the content of file.css in the compressed file generated?

  18. @Paul Thanks! I want to understand a bit more what you need… so you are saying that you use the @import statement in your linked style sheets? If this is the case, could you open an issue on GitHub so that I can look into implementing it in the future.

  19. Hey Justin, this looks like a great tool! I’m wondering if the CSS bundler supports setting the "media" property of the generated "link" tag? For example, we are using blueprint and one of the files needs "media = screen" and the other file needs "media = print". Am I overlooking something?

    Thanks!

  20. Thanks Justin! I don’t know why I didn’t see that in Intellisense.

    BTW, is it intended that the app should cache not only the compressed CSS but also the generated "link" tags? Thus the cache must be cleared (via ClearCache or app restart) so that changes to WithMedia are applied.

    p.s. Is this the best forum to ask questions about SquishIt? If not, kindly point me in the right direction.

    Thanks again! Brad

  21. Hi Justin,

    Thank you for the library.
    I spotted one problem though : When the bundle is called, System.Threading.Thread.CurrentThread.CurrentUICulture is changed. I don’t think it is the expected behavior.

    Thank you for the useful tool!

    W3Max

  22. It works great, thanks a lot for this tool!. Is it possible to bundle files in CodeFile
    Like
    string jstext="<%= Bundle.javascript()
    .Add("~/script/abc.js")
    .Add("~/script/cde.js")
    .Add("~/script/xyz.js")
    .ForceRelease()
    .Render("~/script/combined_#.js")
    %>
    In abc.cs
    and
    <%=jstext.text%>
    in abc.ascx

    is there any solution to do like that

    Regards
    Rajasekhar Reddy Adam

  23. @Justin,

    The CSSPathRewriter does not work in conjunction with the dotLess handler. The url(…) in the processed files wraps the url string in quotes i.e. url("../../images"), something the regex in rewriter does not seem to check for.

  24. Hi Justin,
    if i change one of js files that are combined new combine file is not created on next request. New file is created only when i build project and then make request. Is this expected behaviour ?

  25. I love the work you’ve done, but when I launch to medium trust I can’t get past a "That assembly does not allow partially trusted callers." Any thoughts on how I could get around that?

  26. @Dave It is likely that we do have some issues with medium trust, and especially the AllowPartiallyTrustedCallersAttribute. Could you please log this issue in the GitHub issue tracker if you haven’t done so already?

  27. Hi,
    One thing I can very well see is that the security. Hackers will find it difficult to read those JS files and hack the site.

    Very nice job .

    Thanks,
    Thani

  28. this the rror i get any idea?

    [InvalidOperationException: [ERROR] invalid property id]
    Yahoo.Yui.Compressor.CustomErrorReporter.Error(String message, String sourceName, Int32 line, String lineSource, Int32 lineOffset) +61
    EcmaScript.NET.Parser.AddError(String messageId) +94
    EcmaScript.NET.Parser.ReportError(String messageId) +9

  29. Hi!

    I have a bunch of JS files that are loaded dinamically as a page requires. So for example, page1.aspx may load script1.js and script2.js but page2.aspx may load just script2.js

    Each script is passed to the view as an IList<string>

    Is it possible to squiz them?

  30. @Pablo Probably not, but most often you are better to put all of your js together in one bundle and require only a single download for your users. After that one download they will have all of the javascript they need, made only one request (think latency), and it will be cached.

  31. Great TOOL Justin. I am still trying to figure out how to use this with ASP.NET Themes. One way is to not include the .CSS files within your Theme folder but that only works when you have only one theme. However, if you have more than one theme and if users have the option of changing the themes then… how can you include them on the fly using SquishIt is something that I am not sure about?

  32. @Srameh I’m not entirely sure how you would integrate SquishIt with themes. It is something that I would have to do some research on. I haven’t used themes extensively in the past, so I’m not really the expert on whether or not there is a way to circumvent them or work with then.

  33. Justin, does squishit do the compression server side on every request? I have been doing some work in getting asset_packager (ruby) to work for fubumvc, it does a lot of stuff similar to squishit, but it does it at build time, so no server resources to compress and merge on the fly.

    Was just curious, squishit looks really good!

  34. Hi!

    It seems to have problems squishing javascript with UTF-8 strings in it. The resulting .js file has those characters all mixed up.

    Any ideas how this could be resolved?

  35. @stefanb Can you pull the latest source and give that a shot? I haven’t made a release yet, but it did resolve a few issues around internationalization. I have a few other small issues that need to be addressed as well, but I am working on getting those fixed.

  36. @Justin: yes I did pull latest sources from http://github.com/valmont/SquishIt (linked from this site somewhere) and tried quckyl adding utf-8 encoding to the file writer, to no avail.

    However, later on I noticed there is another repository (presumably yours) at
    http://github.com/jetheredge/SquishIt
    This one unfortunately still has the sasme problem.

    I can have a look at it, but any hints or even fixes will be appreciated.

    Test case could be a simple js with a line:
    alert(‘test ČŽŠĐćčžšđć’);

  37. JsMin has other problems with my js files ("JSMIN unterminated string literal: 10"). I’ve added exception handling to MinifyJavaScript() so that at least it also says which is the problematic file.

    Another improvement i have in there is to not re-minify files whose names end with ".min.js" (for jquery, plugins…)

    code below, feel free to include it.

    [quote]private StringBuilder MinifyJavaScript(List<string> files, IJavaScriptCompressor minifier)
    {
    var outputJavaScript = new StringBuilder();
    foreach (string file in files)
    {
    try
    {
    string content = ReadFile(file);
    if (file.EndsWith(".min.js"))
    {
    outputJavaScript.Append(content);
    }
    else
    {
    outputJavaScript.Append(minifier.CompressContent(content));
    }
    }
    catch (Exception e)
    {
    throw new Exception(string.Format("Error processing {0}", file), e);
    }

    }
    return outputJavaScript;
    }
    [/quote]

  38. I lazy load many of my scripts. Is there a way to use SquishIt in Application Start to generate a compressed script that can then be referenced as a local javascript file later on?

    thanks for your hard work!

  39. How about minimizing also inline javascript on the fly? Eg:
    [quote]<squishit:minimize runat="server" compressor="JsMin">
    alert("Hello, <%=Html.Encode(Model.firstname)%>!");
    </squishit:minimize>[/quote]
    (with a more complex script of course :))

    Btw, congrats to your soccer team 😀 !

  40. I noticed in the web config you have a trust level of "full" – for most live deployments that’s not really an option. Do you have more granular solution?

  41. @stefan Interesting idea. I’ll look into it.

    @Paul We have a few issues with some of the libraries we are using not supporting medium trust. Once we get a few of those worked out we will support medium trust.

  42. @Justin: I’m using YUI compressor with no problems fro UTF-8 scripts after defining the encoding in FileWriter.cs:
    public FileWriter(string file)
    {
    sw = new StreamWriter(file, false, System.Text.Encoding.UTF8);
    }

    and in YuiMinifier.cs:
    public string CompressContent(string content)
    {
    return JavaScriptCompressor.Compress(content, true, true, false, false, -1, Encoding.UTF8, CultureInfo.InvariantCulture, false);
    }

    (full patch is in your mailbox)

    greets,
    Stefan

  43. Have you tested this in a website with multiple worker processes? For example, using the web garden feature in IIS.

    My gut feeling is there needs to be an ICacheProvider so an out-of-process cache can be used.

    BTW-> The ease in which this can integrate into an existing site is amazing. Thanks!

  44. Justin – absolutely brilliant piece of code. Had it setup, tested and live in under 30 minutes. Works great and brought my request load down significantly. Extra points for handling cache invalidation!

  45. Great solution, thumbs up !

    For anyone having this error :

    [ERROR] identifier is a reserved word

    Make sure there is no debugger keyword in your javascript file.

    Good Job again.

    Thanks u sir

  46. Justin, it’s great and simple in use. Thanks u.
    I have one questions.
    What should I do if I use ‘conditional comments’ with css. For example:
    <!–[if IE 7]>
    <link href="css/ie7.css" rel="stylesheet" type="text/css" />
    <![endif]–>

    Thanks

  47. Okay, I apologise now for being a complete newb. I am a front end dev with no .NET knowledge so please bear with me 😛

    I followed the instructions above but when I try to load the website (locally in debug mode) the "<%= Bundle.Css().." code causes the site to redirect to a custom error page. If I remove the "<%= Bundle.Css()…" code it loads the site fine.

    The Bundle code appears to have been hooked up correctly as I get the intellisense etc.

    There are no build errors and if I put a breakpoint at Session_Start in Global.asax.cs or at Page_Load in the master page, it doesn’t hit it.

    Any idea why I’m having problems? Or does it sound like it may be something custom at our end that’s causing it to fall over?

  48. Oopsie, I’m an idiot. I mistakenly added a semi colon after the Render(). Removing that fixed the issue…. doh 😛

    Thank you for replying so quickly!

  49. i fond a problem in the Bundle.Css after everyting is done and a new file is created someting importent is missing the boundle changed background-image: url(‘../../Resources/paper-background.gif’); to background-image: url(‘/Resources/paper-background.gif’); as you can see the "../../" is gone and when linked to the page no images is found becuse it needs the "../../" any solution for this ?

  50. The CSS bundler rewrite paths relative to the output file. It appears that either there is a bug, or your original path was wrong.

    Can you put the hierarchy of the css files and images relative to the output css file?

  51. Im only using the script with one external css
    based on the user agent

    ~/stilmallar/paper/paperChrome.css
    ~/stilmallar/paper/paperSafari.css
    ~/stilmallar/paper/paperStandard.css

    the output file is named paperStandard-min.css

    The image in the orginal css
    img1 ../../Resources/paper-background.gif
    img2 ../../Resources/oscarclean-kontakt.png
    img3 ../../Resources/paper_02.gif
    etc

    the css is located in
    stilmallar/formular/FormStandard.css
    stilmallar/paper/paperStandard.css

    the images is located in Resources/images/some image

    the map stilmallar and Resources is in the root

    do you need any more specific info?

  52. Hmm, that looks like it is rewriting correctly then. The image urls in the css file as relative to the css file itself. So you have two css files that are two directory levels down and you are writing out a file in the root. If your image paths were ../../image.png when your css files were two directory levels down, then when you write the output css two directories up, those paths will change to just /image.png.

    As to why you aren’t seeing them in your html, I’m still not sure.

  53. I found SquishIt this week, and it’s been a huge help to me. I just have a question about the best way to use it. I currently have seven .aspx pages (expecting to add more in the future), each using a combination of javascript files. As you mention earlier, it would be best to just have them all combined into one file so no matter which page loads it will all be cached. That’s fine, but if I add a new javascript file to my project I don’t really want to have to remember to go add the reference to each .aspx page individually.

    I have a warm-up page that is triggered on each iisreset/app pool recycle/etc, so I was thinking it would be nice if I could just do the squish there and then just have the other pages reference the combined file. Is this advisable, and if so what would be the best way to accomplish that so if the javascript changes then the other pages will be assured to reference the correct combined file?

    Thank you.

  54. @robert You can do what is called a named bundle. Just put the code to create your bundle in your Global.asax, or in a warmup page as you said, and called "AsNamed("NameOfBundle", "Outputfile.whatever");

    Then later on, just called Bundle.Css().RenderNamed("NameOfBundle")

    Will that work for you?

  55. I see. I had misunderstood the usage of AsNamed and RenderNamed while reading the other comments. Thanks, that appears to be perfect.

  56. Hey Justin,
    Saw 0.6 was released. I noticed that in your commit notes you replaced Yahoo minifier with Microsoft’s. Do we still need those Yahoo dll’s for something?

  57. Just wanted to say thanks for the very useful library. We’ve put it into production on a few sites and the usefulness to time invested ratio is very high. Kudos!

  58. Hello, I’m having some issues putting the website into production with the library.

    i followed all the steps outline, and works fine locally, but when we try it live, it tells me the following error

    [quote]Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

    Compiler Error Message: CS0246: The type or namespace name ‘SquishIt’ could not be found (are you missing a using directive or an assembly reference?)
    [/quote]

    I see that vs creates the .refresh file for the dll, and im sure we uploaded that into the server.

    I’m thinking of adding it into the assemblies section of the webconfig, im not sure if that would be correct, since if i do

    [quote]sn -T SquishIt.Framework.dll[/quote]

    it tells me

    [quote]SquishIt.Framework.dll does not represent a strongly named assembly[/quote]

    can i add it without a public key? or am I’m going in a wrong path here? please help 🙂

  59. @Justin, suggestions, more like what do think of these ?

    As a best practice the app’s wont have write permission to the directory on the web server. To overcome this, can we store the bundled files in the memory ?

    I think the bundled files will be hardly more than 1MB. The other advantage will be serving the files from the memory might be a little faster ( may be very little ) than serving from the disk.

  60. @biswanth Well, first I don’t think it is necessarily a bad thing for the library to have write permissions into a css or js folder, but that isn’t really important.

    In the dev version I have done some work to enable storing the compressed files in memory. I am working on a project now where we are rendering the files from MVC actions. If you pull the dev version then you’ll see that you can create a bundle with the method "AsCached" and then you can later render that bundle out with "RenderCached" passing it the same name.

    The new version of SquishIt with this feature should hopefully be out in the next few weeks.

  61. Using SquishIt with Ext.NET

    This is not a problem with SquishIt but rather with Ext.NET, but since Ext.NET tend to be quite slow in replying, I thought I’d post this on here in the hope that someone has resolved this issue.

    I’m using Ext.NET 1.0, ASP.NET MVC 2.0 and .NET 4.0.

    When I try to run SquishIt with Ext.NET I get the following error message:

    "The Controls collection cannot be modified because the control contains code blocks (i.e. <% … %>)."

    From my testing, it is caused by:

    <ext:ResourceManager ID="SiteRM" runat="server"></ext:ResourceManager>
    and a fuller code snippet is:

    <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
    <%@ Import Namespace="SquishIt.Framework" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
    <html xmlns="http://www.w3.org/1999/xhtml"&gt;
    <head runat="server">
    <title>
    <asp:ContentPlaceHolder ID="TitleContent" runat="server" />
    </title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

    <%: Bundle.Css()
    .Add("~/Content/style.css")
    .Add("~/Content/Theme/Original.css")
    .Render("~/Content/combined_#.css")
    %>

    <ext:ResourcePlaceHolder ID="GlobalResourcePlaceHolder" runat="server" />
    <asp:ContentPlaceHolder ID="HeadContent" runat="server" />
    </head>
    <body>
    <ext:ResourceManager ID="SiteRM" runat="server">
    </ext:ResourceManager>
    </body>

    Any help would be appreciated

    TIA

    David

  62. @David This is always the case with ASP.NET. If you have controls in your header then you won’t be able to write a string directly into the response. To test that, put SquishIt temporarily outside of your head tag. Check out this post http://www.west-wind.com/weblog/posts/5758.aspx on Rick Strahl’s blog for a few possible solutions.

    Also, please post additional questions in the SquishIt Google group: http://groups.google.com/group/squishit

  63. Hi Justin,

    Thanks for getting back to me. I’ll make sure to put any questions in the right group. Now, having said that, by commenting out

    <ext:ResourceManager ID="SiteRM" runat="server">
    </ext:ResourceManager>

    Squishit does work. 🙂

  64. @David Yep, because it is trying to manipulate your head tag. It is a common problem with ASP.NET that doesn’t really have a great workaround. You can try putting the SquishIt reference in a user control and then placing that user control in the head. That might work, I haven’t dealt with this issue in a long time. 🙂

  65. Hi Justin,

    Thanks for a great component – just what I was looking for!

    I have a question though – how can I compress files from embedded resources within a DLL? I notice there’s an "AddEmbeddedResource" method, but it doesn’t appear to do anything. Please can you give me an example of the syntax for specifying the location of the embedded resource?

    Cheers.

  66. Hi Justin,

    First, thanks so much for putting this out. Amazing work.

    Quick question. Does SquishIt support conditional CSS? For example, if I only want a CSS file to be included if the browser is IE6. Thanks in advance for your reply.

  67. i want to know
    1> is file merging and compression is done for each unique visitor’s request or its done just for the first time(first request) and for later requests generated file is used.
    2> Is is possible to include a folder by using wild card like "*".
    3> Is there a tutorials where few more things are specified the just getting started thing.

  68. Suggestions

    1> if possible generate files on build up.
    2> suppose somewhere in our project we have this may in a partial.ascx(for mvc) or userControl.ascx(for webform)

    <some html>
    html
    </some html>

    <squish type="css" packageName="p1" order="1">
    some css
    </squish>

    <squish type="js" packageName="p1" order="1">
    some js
    </squish>

    –this way we can test individual components easily

    –in some some other file we do: same package different order
    <squish type="js" packageName="p1" order="2">
    some js
    </squish>

    On dedug = true css/js inside <squish> tags should be injected simply b/w "style" and "script" tags respectively
    on debug=false
    now may be on build or on runtime files are generated and may be referenced as below

    now some where else on the project may be on a view(for mvc) or on a page(for web form)
    we do like this, which includes all
    <%= Squish.Js().GetPackage("p1") %>// this looks inside whole project for scripts inside packageName=1, merge them according to order tag, minify them and then add a link for it
    <%= Squish.Css().GetPackage("p1") %>

  69. for any of you want to integrate the squishit to auto-build process in command line, in order to let program to run successfully in the command line, you need to get the source code and change following line:
    BundleBase.cs:
    protected string
    ResolveAppRelativePathToFileSystem(string file)
    {
    from:
    return @"C:" + file.Replace("/", "\");

    to:
    return System.IO.Path.Combine( System.IO.Directory.GetCurrentDirectory() , file.Replace("/", "\"));

    Regards

  70. @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.

  71. 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;

  72. Hey Justin,

    Amazing work! SquishIt has been really useful.

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

  73. @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.

  74. @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
    ==>
    .ApplyingDDD5c2egif

    Any idea how to fix this?

  75. @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.

  76. @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?

  77. 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

  78. 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.

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

  79. 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.

  80. 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?

    1. 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.

  81. 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.

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

  83. @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!

  84. 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 !

  85. 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!

  86. 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.

    1. @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.

  87. 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.

  88. 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?

    1. 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.

  89. 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

  90. 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

  91. Hi Justin, I have an issue, I use SquishIt in a ASCX control, any time the controler is loaded, the libraries inside are loaded too. what I want is load the libraries inside just once. I did it a “Temporary” fix with a flag, but this is not a good pratice… Any advice?

  92. @Carlos_DUX: that is the way controllers work, so you need better structure.

    What we do is just create a separate controller, say Head.ascx, and then reference that in your MasterPage. That way it gets included just once per page.

Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

More Insights

View All