May 18th, 2008

How to create a YUI Compressor MSBuild Task

Recently for IdeaPipe I have been looking for ways to deliver my content more quickly and reduce unnecessary bandwidth use.

According to Yahoo’s Performance Team more than half of the viewers of the Yahoo websites start with an empty cache, which means the browser has to download all the resources for the first time. This combined with a high traffic website and unneeded white space and comments can really add up to a significant bandwidth use. There are many popular ways to minify your static content tax on your bandwidth, using many popular tools, as described in this excerpt from Yahoo:

In terms of code minification, the most widely used tools to minify JavaScript code are Douglas Crockford’s JSMIN, the Dojo compressor and Dean Edwards’ Packer. Each of these tools, however, has drawbacks. JSMIN, for example, does not yield optimal savings (due to its simple algorithm, it must leave many line feed characters in the code in order not to introduce any new bugs).

The goal of JavaScript and CSS minification is always to preserve the operational qualities of the code while reducing its overall byte footprint (both in raw terms and after gzipping, as most JavaScript and CSS served from production web servers is gzipped as part of the HTTP protocol).

The cream of the crop seems to be a tool Yahoo developed to deliver its own static text content scripts and styles, the YUI Compressor:

The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher compression ratio than most other tools. Tests on the YUI Library have shown savings of over 20% compared to JSMin (becoming 10% after HTTP compression). Starting with version 2.0, the YUI Compressor is also able to compress CSS files by using a port of Isaac Schlueter’s regular-expression-based CSS minifier.

The YUI Compressor is a Java JAR file that can be download from Julien Lecomte Blog.

The YUI Compressor yielded exceptional results, however it was missing one thing. Integration in to my build and deployment process. In IdeaPipe I use a MSBuild script to compile, manipulate, and prepare for publishing. So naturally I built a MSBuild Task to minimize my JavaScript and CSS files.

The magic actually happens by invoking Java in an external process for each file passed in to the task.

Process process = new Process();
process.StartInfo = new ProcessStartInfo {
	FileName = @"c:\program files\java\jdk1.6.0_06\bin\java.exe",
	Arguments = String.Format(
		@"-jar ""C:\development\tools\yuicompressor-2.3.5.jar"" --type {0} --charset utf8 {1} -o ""{2}"" ""{3}""",
		type,
		ShowWarnings ? "--verbose" : String.Empty,
		newFile,
		oldFile
		),
	UseShellExecute = false,
	CreateNoWindow = true,
	RedirectStandardOutput = true,
	RedirectStandardError = true
};
process.Start();
process.WaitForExit(5000);

Then I read the warning from the standard error output and send them back to Visual Studio as a compile warning if the ShowWarning property is true.

string[] warnings = process.StandardError.ReadToEnd()
	.Replace("\r", String.Empty)
	.Split(new string[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries);

foreach(string warning in warnings)
	Log.LogWarning(null, null, null, oldFile, 1, 1, 1, 1, FormatWarning(warning), null);

To integrate this in to my MSBuild script I had to first register my task:

<UsingTask TaskName="ManagedFusion.Build.YuiCompress" AssemblyFile="$(ProjectDir)..\ManagedFusion.Build\bin\$(ConfigurationName)\ManagedFusion.Build.dll"/>

Then setup my ItemGroup for the files:

<ItemGroup>
	<JavaScriptContent Include="$(SourceWebPhysicalPath)\**\*.js" />
	<CssContent Include="$(SourceWebPhysicalPath)\**\*.css" />
</ItemGroup>

Then finally I setup my task to perform the minimization against the JavaScript and CSS files seperately:

<Target Name="AfterBuild">
	<!-- do other stuff to prepare for publishing -->
	<YuiCompress Files="@(JavaScriptContent)" Type="JS" />
	<YuiCompress Files="@(CssContent)" Type="CSS" />
</Target>

You can easily incorporate this in to your own MSBuild scripts or even your Visual Studio Project which is just an MSBuild file for compiling your source code for the project. I have included my source code below:

Download: YUI Compressor MSBuild Task Source

Note: There are a couple of static paths to be on the look out for and modify as necessary for your own code. In my code the Java runtime is loaded at c:\program files\java\jdk1.6.0_06\bin\java.exe and the YUI JAR is located at C:\development\tools\yuicompressor-2.3.5.jar.

Update (2008-5-21): Thanks George, apparently IIS doesn’t like serving straight C# files. So I added the code to my Coder Journal Source Control, so that it can be downloaded from there.

Tags: , , , , ,

Social: kick it on DotNetKicks.com

This entry was posted on Sunday, May 18th, 2008 at 6:29 pm and is filed under ASP.NET, How To, Programming. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

18 Responses to “How to create a YUI Compressor MSBuild Task”

  1. DotNetKicks.com Says:

    How to create a YUI Compressor MSBuild Task…

    You’ve been kicked (a good thing) – Trackback from DotNetKicks.com…

  2. Sayed Ibrahim Hashimi Says:

    There is a JSCompress task at the MSBuild Community Tasks Project (http://msbuildtasks.tigris.org).
    This is based on JSMin (http://javascript.crockford.com/jsmin.html) which is actually available now in several languages, including C#.

    Sayed Ibrahim Hashimi
    http://www.sedodream.com

  3. Nick Berardi Says:

    Sayed,

    Thanks for the tip. I actually prefer YUI Compress over JSMin. I will be doing a future article on the differences in the compression using a couple of the popular tools. Plus YUI Compress also does CSS compression.

  4. Daniel Says:

    Great work, Nick!

    I’ve been using my own C# port of the CssMin inside YUI (http://www.dimebrain.com/2008/03/a-better-css-mi.html), but haven’t had the time to port the Javascript parser aspects of the YUI to perform the analog for JS files.

    Daniel

  5. Pure Krome Says:

    Good post .. but it has one serious flaw IMO. It requires JAVA to be on the build server :( Ouch.

    I downloaded the YUI Compressor a few days ago (before i found this article) to see if it could be converted to C# .. so msbuild can then run it nicely … but that’s WAAAYYYY over my head :(

    We really need a codeplex project that does this -> converts the YUI Compress to c#. can be done ….

    i do agree that YUI Compress has the best compression for both css and js.

    -PK-

  6. Nick Berardi Says:

    I looked at the YUI Compressor code. It is definitely doable in C# with out much rewriting. But definitely more time than I wanted to spend on the thing. However you might want to try running the Java to C# converter over the source code and see how close you get.

  7. In the Wild for May 30 » Yahoo! User Interface Blog Says:

    [...] YUI Compressor MSBuild task: Nick Berardi at Coder Journal put together a nice tutorial on using YUI compressor as part of his MSBuild workflow. [...]

  8. Andrei Ignat Blog Says:

    MSBuild tasks si Poor man backup…

  9. Ken Says:

    This got me close, but since I’ve never written an MSBuild script before it was just a tease. Have no clue how to make use of this. Scoured the internet too and found nothing very helpful about MSBuild.

  10. Eric Says:

    Fine great article !
    How do you add this into VS Project ? Can do this be done after Publish website task ?

  11. Nick Berardi Says:

    What you need to do is open the VS Project in a text editor, and edit the necessary code as outlined above. Or you can right click on the project, click Unload Project, then right click on the grayed out project and click edit. This will bring up the project’s XML MSBuild script, and you can edit it from there. Or alternatively you can use this in the Microsoft Web Deployment Build Script, which is personally what I do.

    http://www.microsoft.com/downloads/details.aspx?FamilyId=0AA30AE8-C73B-4BDD-BB1B-FE697256C459&displaylang=en

  12. Matthew Says:

    There is a port if YUI for .NET in C# on codeplex. So far, so good. No need for Java.

    http://www.codeplex.com/YUICompressor

  13. Andre Says:

    Hi,

    I’m trying to implement this and I’m having some trouble. Where do I want to place the YuiCompress.cs file? Should this be in its own project then linked into the project I need it for? Also I’m not sure I understand the AssmeblyFile property of the UsingTask tag should be set to.

    Thanks

    Andre

  14. PK Says:

    Andre -> use the .dll available from: http://www.codeplex.com/YUICompressor

    it does everything u want AND doesn’t require java (cringe). It’s all good.

  15. Nick Berardi Says:

    PK, I tried it and it didn’t compress my JavaScript in the same way as the YUI compressor. It caused a couple of errors in the JavaScript too. I will try again in a couple of months maybe you will have the problems fixed.

  16. JIRA: Scout - Revenue Recovery Project Says:

    [DW-794] Java Scipt – minify the files…

    From email:
    I looked at the .js files in the collector’s C:\_aScout\Src\Scout\CollectionSite\js root. There are 26 files weighing in at 562K on my machine right now. After running them through YUI the 26 files became 297K. Not quite 50% but obvi…

  17. Building minification into MSBuild scripts - Helephant.com Says:

    [...] compressor is another good option for minifying javascript and CSS. There’s also an example MSBuild task for [...]

  18. Yahoo YUI Compressor vs. Microsoft AJAX Minifier vs. Google Closure Compiler - Nick Berardi's Coder Journal Says:

    [...] little more than a year and half ago I created a MSBuild Task for the YUI Compressor that was very well received, and even highlighted on the YUI Compressor site.  At the time of [...]

Leave a Reply