<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Julien Lecomte&#039;s Blog &#187; Search Results  &#187;  YUI Compressor</title>
	<atom:link href="http://www.julienlecomte.net/blog/?s=YUI+Compressor&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.julienlecomte.net/blog</link>
	<description>Web Development, Operating System Programming and Amateur Astronomy</description>
	<lastBuildDate>Sun, 15 Aug 2010 19:25:28 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>YUI Compressor now hosted on GitHub</title>
		<link>http://www.julienlecomte.net/blog/2009/07/273/</link>
		<comments>http://www.julienlecomte.net/blog/2009/07/273/#comments</comments>
		<pubDate>Fri, 10 Jul 2009 17:09:57 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/?p=273</guid>
		<description><![CDATA[I am pleased to announce that the YUI Compressor is now hosted on GitHub. Hopefully, this move will make the external contribution process more streamlined. Have fun coding!
]]></description>
			<content:encoded><![CDATA[<p>I am pleased to announce that the YUI Compressor is now <a href="http://github.com/yui/yuicompressor/tree/master">hosted on GitHub</a>. Hopefully, this move will make the external contribution process more streamlined. Have fun coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2009/07/273/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The YUI library source code is now hosted on GitHub</title>
		<link>http://www.julienlecomte.net/blog/2009/01/156/</link>
		<comments>http://www.julienlecomte.net/blog/2009/01/156/#comments</comments>
		<pubDate>Thu, 15 Jan 2009 06:09:30 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/?p=156</guid>
		<description><![CDATA[If you haven&#8217;t done so already, head over to the YUI Blog for the official announcement. I am proud to have made a (very modest) recent contribution to the library by porting the browser history utility to YUI3 (take a look at the source code) By the way, this new version of the browser history [...]]]></description>
			<content:encoded><![CDATA[<p>If you haven&#8217;t done so already, head over to the YUI Blog for the <a href="http://yuiblog.com/blog/2009/01/14/github/">official announcement</a>. I am proud to have made a (very modest) recent contribution to the library by porting the browser history utility to YUI3 (take a look at the <a href="http://github.com/yui/yui3/blob/master/src/history/js/history.js">source code</a>) By the way, this new version of the browser history utility supports Opera and IE8 (in both quirks mode and IE7 standards mode) Moreover, it has more features than the YUI2 version, should be easier to use, and weighs a few hundred bytes less (after minification with the YUI Compressor) I&#8217;ll try to find some time in the next few weeks/months to write a bit more about YUI3 in general, and the new browser history utility and the YUI Compressor. Stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2009/01/156/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>YUI Compressor and Java Class Loader</title>
		<link>http://www.julienlecomte.net/blog/2008/10/80/</link>
		<comments>http://www.julienlecomte.net/blog/2008/10/80/#comments</comments>
		<pubDate>Wed, 22 Oct 2008 00:16:32 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/?p=80</guid>
		<description><![CDATA[The YUI Compressor uses a slightly modified version of the parser used in the Rhino JavaScript engine. The reason for modifying the parser came from the need to support JScript conditional comments, unescaped forward slashes in regular expressions &#8212; which all browsers support and many people use &#8212; and a few micro optimizations. The problem [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.julienlecomte.net/blog/2007/08/11/">YUI Compressor</a> uses a slightly modified version of the parser used in the <a href="http://www.mozilla.org/rhino/">Rhino</a> JavaScript engine. The reason for modifying the parser came from the need to support JScript conditional comments, unescaped forward slashes in regular expressions &#8212; which all browsers support and many people use &#8212; and a few micro optimizations. The problem is that many users had the original Rhino Jar file somewhere on their system, either in their classpath, or in their JRE extension directory (&lt;JRE_HOME&gt;/lib/ext) This caused many headaches because the wrong classes were being loaded, leading to many weird bugs.</p>
<p>Today, I finally decided to do something about it. This meant writing a custom class loader to load the modified classes directly from the YUI Compressor Jar file. You can download the source and binary package here:</p>
<p style="margin:30px 0;text-align:center;"><a href="/yuicompressor/" target="_blank" style="padding:8px;border:1px solid #bbb;font-weight:bold;text-decoration:underline;">Download version 2.4 of the YUI Compressor</a></p>
<p>The skeleton of the custom class loader is pretty straightforward:</p>
<pre class="prettyprint">
package com.yahoo.platform.yui.compressor;

public class JarClassLoader extends ClassLoader
{
    public Class loadClass(String name) throws ClassNotFoundException
    {
        // First check if the class is already loaded
        Class c = findLoadedClass(name);
        if (c == null) {
            // Try to load the class ourselves
            c = findClass(name);
        }

        if (c == null) {
            // Fall back to the system class loader
            c = ClassLoader.getSystemClassLoader().loadClass(name);
        }

        return c;
    }

    protected Class findClass(String name)
    {
        // Most of the heavy lifting takes place here
    }
}
</pre>
<p>The role of the <code>findClass</code> method is to first locate the YUI Compressor Jar file. To do that, we look in the classpath for a Jar file that contains the <code>com.yahoo.platform.yui.compressor.JarClassLoader</code> class:</p>
<pre class="prettyprint">
private static String jarPath;

private static String getJarPath()
{
    if (jarPath != null) {
        return jarPath;
    }

    String classname = JarClassLoader.class.getName().replace('.', '/') + ".class";
    String classpath = System.getProperty("java.class.path");
    String classpaths[] = classpath.split(System.getProperty("path.separator"));
    for (int i = 0; i < classpaths.length; i++) {
        String path = classpaths[i];
        JarFile jarFile = new JarFile(path);
        JarEntry jarEntry = findJarEntry(jarFile, classname);
        if (jarEntry != null) {
            jarPath = path;
            break;
        }
    }

    return jarPath;
}

private static JarEntry findJarEntry(JarFile jarFile, String entryName)
{
    Enumeration entries = jarFile.entries();
    while (entries.hasMoreElements()) {
        JarEntry entry = (JarEntry) entries.nextElement();
        if (entry.getName().equals(entryName)) {
            return entry;
        }
    }
    return null;
}
</pre>
<p>Once we know where the YUI Compressor Jar file is, we can load the appropriate class from that file. Note the need to define the package the class belongs to before calling <code>defineClass</code>!</p>
<pre class="prettyprint">
protected Class findClass(String name)
{
    Class c = null;
    String jarPath = getJarPath();
    if (jarPath != null) {
        JarFile jarFile = new JarFile(jarPath);
        c = loadClassData(jarFile, name);
    }
    return c;
}

private Class loadClassData(JarFile jarFile, String className)
{
    String entryName = className.replace('.', '/') + ".class";
    JarEntry jarEntry = findJarEntry(jarFile, entryName);
    if (jarEntry == null) {
        return null;
    }

    // Create the necessary package if needed...
    int index = className.lastIndexOf('.');
    if (index >= 0) {
        String packageName = className.substring(0, index);
        if (getPackage(packageName) == null) {
            definePackage(packageName, "", "", "", "", "", "", null);
        }
    }

    // Read the Jar File entry and define the class...
    InputStream is = jarFile.getInputStream(jarEntry);
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    copy(is, os);
    byte[] bytes = os.toByteArray();
    return defineClass(className, bytes, 0, bytes.length);
}

private void copy(InputStream in, OutputStream out)
{
    byte[] buf = new byte[1024];
    while (true) {
        int len = in.read(buf);
        if (len < 0) break;
        out.write(buf, 0, len);
    }
}
</pre>
<p>The last thing we need to do is bootstrap the application. In order to do that, we simply load the main class (<code>YUICompressor</code>) using our new custom class loader. All the classes that will be needed at runtime will use the same class loader:</p>
<pre class="prettyprint">
package com.yahoo.platform.yui.compressor;

public class Bootstrap
{
    public static void main(String args[]) throws Exception
    {
        ClassLoader loader = new JarClassLoader();
        Thread.currentThread().setContextClassLoader(loader);
        Class c = loader.loadClass(YUICompressor.class.getName());
        Method main = c.getMethod("main", new Class[]{String[].class});
        main.invoke(null, new Object[]{args});
    }
}
</pre>
<p>As you can see, it's not terribly complicated to write a custom class loader. Note: I left out all the exception handling code and the import statements for clarity. The final code can be found in the downloadable archive. Cheers!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2008/10/80/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>YUI Compressor Version 2.3 Now Available</title>
		<link>http://www.julienlecomte.net/blog/2008/01/42/</link>
		<comments>http://www.julienlecomte.net/blog/2008/01/42/#comments</comments>
		<pubDate>Mon, 28 Jan 2008 22:17:30 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2008/01/42/</guid>
		<description><![CDATA[This new version of the compressor fixes a few bugs and implements a few additional micro optimizations. Please refer to the CHANGELOG file for a complete list of changes, and don&#8217;t hesitate to report any issue you may experience with this version of the YUI Compressor.
Download version 2.3 of the YUI Compressor
]]></description>
			<content:encoded><![CDATA[<p>This new version of the compressor fixes a few bugs and implements a few additional micro optimizations. Please refer to the <a href="/yuicompressor/CHANGELOG" target="_blank">CHANGELOG</a> file for a complete list of changes, and don&#8217;t hesitate to report any issue you may experience with this version of the YUI Compressor.</p>
<p style="margin:30px 0;text-align:center;"><a href="/yuicompressor/" target="_blank" style="padding:8px;border:1px solid #bbb;font-weight:bold;text-decoration:underline;">Download version 2.3 of the YUI Compressor</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2008/01/42/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>About The Author</title>
		<link>http://www.julienlecomte.net/blog/about-the-author/</link>
		<comments>http://www.julienlecomte.net/blog/about-the-author/#comments</comments>
		<pubDate>Mon, 03 Dec 2007 22:08:55 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/about-the-author/</guid>
		<description><![CDATA[My name is Julien Lecomte, and this is my personal weblog. I write mainly about my passion, amateur astronomy, as well as my technical interests, including operating system development and web technologies.
I am currently a senior software engineer in the Yahoo! Search frontend team. Prior to working on web search, I was part of Yahoo!&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://www.julienlecomte.net/blogfiles/images/author.jpg' alt='Picture of the author in London'  style="float:left;margin-right:10px;width:105px;height:120px;"/>My name is Julien Lecomte, and this is my personal weblog. I write mainly about my passion, amateur astronomy, as well as my technical interests, including operating system development and web technologies.</p>
<p>I am currently a senior software engineer in the Yahoo! Search frontend team. Prior to working on web search, I was part of Yahoo!&#8217;s client evangelism team, a group that provides architectural assistance to Yahoo! developers on the design and implementation of rich interactions in the browser, working alongside <a href="http://www.crockford.com/" target="_blank">Douglas Crockford</a>, <a href="http://www.looksgoodworkswell.com/">Bill Scott</a> and Iain Lamb (co-founder of OddPost). Among other things, I worked extensively on <a href="http://mail.yahoo.com" target="_blank">Yahoo! Mail</a>, wrote the <a href="http://developer.yahoo.com/yui/history/" target="_blank">YUI Browser History Manager</a> and the <a href="http://www.julienlecomte.net/blog/2007/08/13/introducing-the-yui-compressor/">YUI Compressor</a>, and contributed to many different projects throughout the company.</p>
<p>Prior to working at Yahoo, I was a senior software engineer at <a href="http://www.scalix.com" target="_blank">Scalix</a> (now part of <a href="http://www.xandros.com" target="_blank">Xandros</a>), where I spent a couple of years developing their <a href="http://www.scalix.com/community/communityedition/swa_screenshots.php" target="_blank">web client</a>. Prior to joining <a href="http://www.scalix.com" target="_blank">Scalix</a>, I was a software engineer at <a href="http://www.easyplanet.com/" target="_blank">easyplanet</a> where I worked on a consumer VoIP application based on the <a href="http://www.openh323.org/" target="_blank">OpenH323 library</a>.</p>
<p>During my spare time, I like to go hiking in the hills surrounding the Santa Clara valley, observe the night sky, build furniture in my woodshop, work on my hobby operating system &#8212; <a href="http://www.julienlecomte.net/blog/2007/09/03/introducing-simplix-an-operating-system-anybody-can-understand/" target="_blank">Simplix</a> &#8212; enjoy some good wine and foods, and travel to exotic destinations with my beautiful wife.</p>
<p>In 2001, I obtained a Master&#8217;s degree in computer science from <a href="http://www.supelec.fr/Welcome.html" target="_blank">Supelec</a>, a leading engineering institute in France.</p>
<p>My resume can be found at <a href="/resume.html" target="_blank">http://www.julienlecomte.net/resume.html</a>.</p>
<p>Additionally, you may contact me at julien [dot] lecomte [at] gmail [dot] com</p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/about-the-author/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>YUI Compressor Version 2.2.1 Now Available</title>
		<link>http://www.julienlecomte.net/blog/2007/09/24/</link>
		<comments>http://www.julienlecomte.net/blog/2007/09/24/#comments</comments>
		<pubDate>Fri, 28 Sep 2007 18:56:29 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2007/09/25/yui-compressor-version-221-now-available/</guid>
		<description><![CDATA[I implemented a few enhancement requests and fixed a bug in this new version of the YUI Compressor. Let me know if you encounter any issue with it.
Update (9/27/07):  YUI Compressor version 2.2.2 is now available. It fixes a lot of bugs that have been reported recently. By the way, I really appreciate all [...]]]></description>
			<content:encoded><![CDATA[<p>I implemented a few enhancement requests and fixed a bug in this new version of the YUI Compressor. Let me know if you encounter any issue with it.</p>
<p><strong>Update (9/27/07): </strong> YUI Compressor version 2.2.2 is now available. It fixes a lot of bugs that have been reported recently. By the way, I really appreciate all the bug reports, so keep them coming!</p>
<p><strong>Update (9/28/07): </strong> New bugs have been reported and fixed in version 2.2.3 now available for download (check out the CHANGELOG file in the download page) And keep these bug reports coming!</p>
<p><strong>Update (10/1/07): </strong> A few more minor bugs have been fixed in version 2.2.4. Thanks for the bug reports!</p>
<p style="margin:30px 0;text-align:center;"><a href="/yuicompressor/" target="_blank" style="padding:8px;border:1px solid #bbb;font-weight:bold;text-decoration:underline;">Download version 2.2.4 of the YUI Compressor</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2007/09/24/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>YUI Compressor Version 2.2 Now Available</title>
		<link>http://www.julienlecomte.net/blog/2007/09/22/</link>
		<comments>http://www.julienlecomte.net/blog/2007/09/22/#comments</comments>
		<pubDate>Tue, 18 Sep 2007 23:15:46 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2007/09/18/yui-compressor-version-22-now-available/</guid>
		<description><![CDATA[This new version of the YUI Compressor supports stdin and stdout. This means that you can now call the YUI Compressor using the following command line:

java -jar yuicompressor-2.2.jar --type js < input.js > output.js

You can still use the following syntax as well:

java -jar yuicompressor-2.2.jar -o output.js input.js

This has three main consequences:

All informational and error messages [...]]]></description>
			<content:encoded><![CDATA[<p>This new version of the YUI Compressor supports <code>stdin</code> and <code>stdout</code>. This means that you can now call the YUI Compressor using the following command line:</p>
<pre>
java -jar yuicompressor-2.2.jar --type js < input.js > output.js
</pre>
<p>You can still use the following syntax as well:</p>
<pre>
java -jar yuicompressor-2.2.jar -o output.js input.js
</pre>
<p>This has three main consequences:</p>
<ol>
<li>All informational and error messages are now printed to <code>stderr</code>.</li>
<li>If no input file is specified, the YUI Compressor defaults to <code>stdin</code>. In that case, you <em>must</em> specify the <code>--type</code> option because the YUI compressor has no way of knowing whether it should invoke the JavaScript or CSS compressor (there is no file extension to look at)</li>
<li>If no output file is specified, the YUI Compressor defaults to <code>stdout</code> (in prior versions, it used to create a file named after the input file, and appended the <code>-min</code> suffix)</li>
</ol>
<p>The other main feature brought by this new version of the YUI Compressor is the support for <a href="http://www.javascriptkit.com/javatutors/conditionalcompile.shtml" target="_blank">JScript conditional comments</a>:</p>
<pre class="prettyprint">
/*@cc_on
   /*@if (@_win32)
      document.write("OS is 32-bit, browser is IE.");
   @else @*/
      document.write("Browser is not 32 bit IE.");
   /*@end
@*/
</pre>
<p>Note that the presence of a conditional comment inside a function (i.e. not in the global scope) will reduce the level of compression for the same reason  the use of <code>eval</code> or <code>with</code> reduces the level of compression (conditional comments, which do not get parsed, may refer to local variables, which get obfuscated) In any case, the use of Internet Explorer&#8217;s conditional comments is to be avoided.</p>
<p>Finally, a few improvements have been made to the CSS compressor.</p>
<p style="margin:30px 0;text-align:center;"><a href="/yuicompressor/" target="_blank" style="padding:8px;border:1px solid #bbb;font-weight:bold;text-decoration:underline;">Download version 2.2 of the YUI Compressor</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2007/09/22/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Building Web Applications With Apache Ant</title>
		<link>http://www.julienlecomte.net/blog/2007/09/16/</link>
		<comments>http://www.julienlecomte.net/blog/2007/09/16/#comments</comments>
		<pubDate>Tue, 11 Sep 2007 20:37:31 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2007/09/11/building-web-applications-with-apache-ant/</guid>
		<description><![CDATA[The importance of having a solid build process
Modern web applications are large and complicated pieces of engineering, using many different technologies, sometimes deployed on hundreds (or even thousands) of servers throughout the world, and used by people from dozens of locales. Such applications cannot efficiently be developed without relying on a solid build process to [...]]]></description>
			<content:encoded><![CDATA[<h4>The importance of having a solid build process</h4>
<p>Modern web applications are large and complicated pieces of engineering, using many different technologies, sometimes deployed on hundreds (or even thousands) of servers throughout the world, and used by people from dozens of locales. Such applications cannot efficiently be developed without relying on a solid build process to do all the dirty and repetitive work of reliably putting all the pieces together.</p>
<h4>Apache Ant</h4>
<p><img src="/blogfiles/images/apache-ant-logo.png" style="width:120px;height:35px;border:none;float:right;margin-left:10px;" alt="Apache Ant"></p>
<p>Many tools (make, gnumake, nmake, jam, etc.) are available today to build applications. However, when it comes to building a <em>web</em> application, my personal favorite is definitely <a href="http://ant.apache.org/" target="_blank">Apache Ant</a> (here is a <a href="http://ant.apache.org/manual/intro.html" target="_blank">good explanation</a> of Ant&#8217;s benefits over the other tools) This short tutorial will assume you already have some basic knowledge of Ant (if you don&#8217;t, you should flip through its <a href="http://ant.apache.org/manual/index.html" target="_blank">user manual</a> beforehand) This article will focus mainly on building front-end code using Ant.</p>
<p><br style="clear:both;line-height:0;"/></p>
<h4>Build types</h4>
<p>It is often useful to build an application differently at different stages of its life cycle. For instance, a development build will have assertions and tons of logging code, while a production version will be stripped of all that. You may also need some intermediate build to hand off to QA, and still be able to debug things easily while running actual production code. With Ant, you can create one target per build type, and have a different dependency list for each target. Properties can also be used to customize specific build types. Here is an example:</p>
<pre class="prettyprint" style="overflow:auto;overflow-y:hidden;">
&#60;target name="dev" depends="load.properties.dev, js.preprocess, js.check.syntax, copy.jsp, copy.image.files, copy.css.files, copy.js.files, compile.jsp, copy.properties.files, compile.webapps, copy.libs"
    description="Development build"&#62;
&#60;/target&#62;

&#60;target name="prod" depends="load.properties.prod, js.preprocess, js.check.syntax, js.concatenate, js.minify, copy.jsp, copy.image.files, copy.css.files, copy.js.files, compile.jsp, copy.properties.files, compile.webapps, copy.libs"
    description="Full production build"&#62;
&#60;/target&#62;

&#60;target name="load.properties"&#62;
    &#60;property file="ant.properties"/&#62;
&#60;/target&#62;

&#60;target name="load.properties.dev" depends="load.properties"&#62;
    &#60;property name="js.preprocess.switches" value="-P -DDEBUG_VERSION=1"/&#62;
    &#60;property name="js.compressor.switches" value="--nomunge --line-break"/&#62;
&#60;/target&#62;

&#60;target name="load.properties.prod" depends="load.properties"&#62;
    &#60;property name="js.preprocess.switches" value="-P -DDEBUG_VERSION=0"/&#62;
    &#60;property name="js.compressor.switches" value=""/&#62;
&#60;/target&#62;
</pre>
<h4>Concatenate your JavaScript and CSS files</h4>
<p><div class="blog-post-ad"><script type="text/javascript"><!--
google_ad_client = "pub-3574095397411323";
google_ad_slot = "4476010593";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</div></p>
<p>Concatenating JavaScript and CSS files contributes to making your site faster <a href="http://developer.yahoo.com/performance/rules.html#num_http" target="_blank">according to Yahoo!&#8217;s Exceptional Performance team</a>. File concatenation using Ant is trivial using the <code>concat</code> task. However, it is often important to concatenate JavaScript and CSS files in a very specific order (If you are using <a href="http://developer.yahoo.com/yui/" target="_blank">YUI</a> for example, you want yahoo.js to appear first, and then dom.js/event.js, and then animation.js, etc. in order to respect module dependencies) This can be accomplished using a filelist, or a combination of filesets. Here is an example:</p>
<pre class="prettyprint">
&#60;target name="js.concatenate"&#62;
    &#60;concat destfile="${build.dir}/concatenated/foo.js"&#62;
        &#60;filelist dir="${src.dir}/js"
            files="a.js, b.js"/&#62;
        &#60;fileset dir="${src.dir}/js"
            includes="*.js"
            excludes="a.js, b.js"/&#62;
    &#60;/concat&#62;
&#60;/target&#62;
</pre>
<p>It is also possible to prepend some comments to the destination file, which is often used for license and copyright information, using a nested <code>header</code> element (see the <a href="http://ant.apache.org/manual/CoreTasks/concat.html" target="_blank">Apache Ant manual</a>) Just keep in mind that minifying your code will make these comments go away, so you may want to do this later in the build process.</p>
<h4>Preprocess your JavaScript files using CPP</h4>
<p>Preprocessing JavaScript code is very useful to facilitate the development process. It allows you to define your own macros, and conditionally compile blocks of code. One easy way to preprocess JavaScript code is to use the <a href="http://en.wikipedia.org/wiki/C_preprocessor" target="_blank">C preprocessor</a>, which is usually installed by default on UNIX machines. It is available on Windows machines as well using <a href="http://www.cygwin.com/" target="_blank">cygwin</a>. Here is a snippet of an Ant build.xml file illustrating the use of cpp to preprocess JavaScript files:</p>
<pre class="prettyprint">
&#60;target name="js.preprocess" depends="js.concatenate"&#62;
    &#60;apply executable="cpp" dest="${build.dir}/preprocessed"&#62;
        &#60;fileset dir="${build.dir}/concatenated"
            includes="foo.js"/&#62;
        &#60;arg line="${js.preprocess.switches}"/&#62;
        &#60;srcfile/&#62;
        &#60;targetfile/&#62;
        &#60;mapper type="identity"/&#62;
    &#60;/apply&#62;
&#60;/target&#62;
</pre>
<p>You can now write JavaScript code that looks like the following:</p>
<p><em>include.js</em>:</p>
<pre class="prettyprint">
#if DEBUG_VERSION
function assert(condition, message) {
    ...
}
#define ASSERT(x, ...) assert(x, ## __VA_ARGS__)
#else
#define ASSERT(x, ...)
#endif
</pre>
<p><em>foobar.js</em>:</p>
<pre class="prettyprint">
#include "include.js"

function myFunction(arg) {
    ASSERT(YAHOO.lang.isString(argvar), "arg should be a string");
    ...
#if DEBUG_VERSION
    YAHOO.log("Log this in debug mode only");
#endif
    ...
}
</pre>
<p>Just a word of caution here: make sure you use the UNIX EOL character before preprocessing your files. Otherwise, you&#8217;ll have some issues with multi-line macros. You may use the <code>fixcrlf</code> Ant task to automatically fix that for you.</p>
<h4>Minify your JavaScript and CSS files</h4>
<p><div class="blog-post-ad"><script type="text/javascript"><!--
google_ad_client = "pub-3574095397411323";
google_ad_slot = "4476010593";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</div></p>
<p>Minifying your JavaScript and CSS files will help make your application faster <a href="http://developer.yahoo.com/performance/rules.html#minify" target="_blank">according to Yahoo!&#8217;s Exceptional Performance team</a>. I warmly recommend you use the YUI Compressor, available for <a href="/yuicompressor/" target="_blank">download</a> on this site. There are two ways to call the YUI Compressor from Ant. Here is the first one using the <code>java</code> task:</p>
<pre class="prettyprint">
&#60;target name="js.minify" depends="js.preprocess"&#62;
    &#60;java jar="yuicompressor.jar" fork="true"&#62;
        &#60;arg value="foo.js"/&#62;
    &#60;/java&#62;
&#60;/target&#62;
</pre>
<p>Here is another way using the <code>apply</code> task that allows you to pass several files to the compressor using a <code>fileset</code>:</p>
<pre class="prettyprint">
&#60;target name="js.minify" depends="js.preprocess"&#62;
    &#60;apply executable="java" parallel="false"&#62;
        &#60;fileset dir="." includes="foo.js, bar.js"/&#62;
        &#60;arg line="-jar"/&#62;
        &#60;arg path="yuicompressor.jar"/&#62;
        &#60;mapper type="glob" from="*.js" to="*-min.js"/&#62;
    &#60;/apply&#62;
&#60;/target&#62;
</pre>
<p><strong>Update:</strong> Starting with version 2.2.x of the YUI Compressor, the ant target described above needs to be slightly modified:</p>
<pre class="prettyprint">
&#60;target name="js.minify" depends="js.preprocess"&#62;
    &#60;apply executable="java" parallel="false"&#62;
        &#60;fileset dir="." includes="foo.js, bar.js"/&#62;
        &#60;arg line="-jar"/&#62;
        &#60;arg path="yuicompressor.jar"/&#62;
        &#60;srcfile/&#62;
        &#60;arg line="-o"/&#62;
        &#60;mapper type="glob" from="*.js" to="*-min.js"/&#62;
        &#60;targetfile/&#62;
    &#60;/apply&#62;
&#60;/target&#62;
</pre>
<p>Also consider the following ant target to minify CSS files:</p>
<pre class="prettyprint">
&#60;target name="js.minify" depends="js.preprocess"&#62;
    &#60;apply executable="java" parallel="false"&#62;
        &#60;fileset dir="." includes="*.css"/&#62;
        &#60;arg line="-jar"/&#62;
        &#60;arg path="yuicompressor.jar"/&#62;
        &#60;arg line="--line-break 0"/&#62;
        &#60;srcfile/&#62;
        &#60;arg line="-o"/&#62;
        &#60;mapper type="glob" from="*.css" to="*-min.css"/&#62;
        &#60;targetfile/&#62;
    &#60;/apply&#62;
&#60;/target&#62;
</pre>
<h4>Work around caching issues</h4>
<p><a href="http://developer.yahoo.com/performance/rules.html#expires" target="_blank">Adequate cache control</a> can really enhance your users&#8217; experience by not having them re-download static content (usually JavaScript, CSS, HTML and images) when coming back to your site. This has a downside however: when rev&#8217;ing your application, you want to make sure your users get the latest static content. The only way to do that is to change the name of these files (for example by adding a time stamp to their file name, or using their checksum as their file name) You must also propagate that change to all the files that refer to them.</p>
<p>The copy and file name replacement will be handled by a custom Ant task named FileTransform (see <a href="/blogfiles/apache-ant/FileTransform.java" target="_blank">FileTransform.java</a>) The first step is to build the task from the source and define the custom task:</p>
<pre class="prettyprint">
&#60;target name="-setup.build.tools" depends="-load.properties"&#62;
    &#60;mkdir dir="${build.dir}/tools/classes"/&#62;
    &#60;javac srcdir="tools/src"
           destdir="${build.dir}/tools/classes"
           includes="**/*.java"&#62;
        &#60;classpath&#62;
            &#60;pathelement location="tools/lib/ant.jar"/&#62;
        &#60;/classpath&#62;
    &#60;/javac&#62;
    &#60;taskdef name="FileTransform"
        classname="com.yahoo.platform.build.ant.FileTransform"
        classpath="${build.dir}/tools/classes"/&#62;
&#60;/target&#62;
</pre>
<p>(Note the use of a &#8220;-&#8221; in front of the name of the target. This is used to make the target &#8220;private&#8221; i.e. not invokable directly) The second part is the copy of the static content that is going to be cached using the newly defined FileTransform task:</p>
<pre class="prettyprint">
&#60;target name="-copy.js.files" depends="-setup.build.tools"&#62;
    &#60;mkdir dir="${build.dir}/js"/&#62;
    &#60;FileTransform todir="${build.dir}/js"
        changefilenames="true"
        propertiesfile="${build.dir}/js.files.mapping.properties"&#62;
        &#60;fileset dir="site/js" includes="*.js"/&#62;
    &#60;/FileTransform&#62;
&#60;/target&#62;
</pre>
<p>The mapping between the old names and the new names is stored in a properties file. The final step is the copy of the files that refer to files which name was changed in the previous step. For this, we use the <code>copy</code> task:</p>
<pre class="prettyprint">
&#60;target name="-copy.php.files" depends="-copy.js.files"&#62;
    &#60;mkdir dir="${build.dir}/php"/&#62;
    &#60;copy todir="${build.dir}/php"&#62;
        &#60;fileset dir="site/php" includes="*.php"/&#62;
        &#60;filterset&#62;
            &#60;filtersfile file="${build.dir}/js.files.mapping.properties"/&#62;
        &#60;/filterset&#62;
    &#60;/copy&#62;
&#60;/target&#62;
</pre>
<p>You can <a href="/blogfiles/apache-ant/ant-filetransform-project.zip">download</a> an archive containing a very simple Ant project illustrating this advanced technique.</p>
<h4>Deploy your application</h4>
<p>Deploying a web application is usually done by copying a set of files over to the production servers and running a list of commands on those servers (stop the services, run a few shell commands, and finally restart the services)</p>
<p>You have many options to copy files to remote servers with Apache Ant. You could use the <code>copy</code> task to copy files to a locally mounted file system, or you could use the optional <code>FTP</code> task. My personal preference is to use <code>scp</code> and <code>rsync</code> (both utilities are available on all major platforms) Here is a very simple example demonstrating the use of <code>scp</code> with Apache Ant:</p>
<pre class="prettyprint">
&#60;apply executable="scp" failonerror="true" parallel="true"&#62;
    &#60;fileset dir="${build.dir}" includes="**/*"/&#62;
    &#60;srcfile/&#62;
    &#60;arg line="${live.server}:/var/www/html/"/&#62;
&#60;/apply&#62;
</pre>
<p>And here is an example showing how you can run remote commands:</p>
<pre class="prettyprint">
&#60;exec executable="ssh" failonerror="true"&#62;
    &#60;arg line="${live.server}"/&#62;
    &#60;arg line="sudo webctl restart"/&#62;
&#60;/exec&#62;
</pre>
<h4>Conclusion</h4>
<p>I hope this article has given you some ideas of what&#8217;s possible to automate with modern build tools such as Apache Ant (other cool things include automatic generation of documentation, source control integration, packaging using rpm and such, etc.) My professional experience has taught me that the build process cannot be an afterthought. Just like performance, it should be part of your project from the very beginning. The second lesson is that all web developers need to be active participants in creating and maintaining the build process (with maybe one build engineer to centralize all the information) instead of relying on somebody else to build their component. Finally, keep your build process alive and maintain it actively as your needs will change during your project life cycle.</p>
<p><div class="blog-post-ad"><script type="text/javascript"><!--
google_ad_client = "pub-3574095397411323";
google_ad_slot = "4476010593";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</div></p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2007/09/16/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>YUI Compressor Version 2.1 Now Available</title>
		<link>http://www.julienlecomte.net/blog/2007/08/15/</link>
		<comments>http://www.julienlecomte.net/blog/2007/08/15/#comments</comments>
		<pubDate>Wed, 29 Aug 2007 19:34:51 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2007/08/29/yui-compressor-version-21-now-available/</guid>
		<description><![CDATA[This new version of the compressor fixes a few bugs and optimizes string concatenations. You can now keep your code nicely formatted by concatenating string literals, but not suffer any performance hit. For example, the following code:

var url = "http://www.flickr.com/services/rest/"
    + "?method=flickr.test.echo"
    + "&#038;format=json"
    + "&#038;api_key=02b6a73df2c4a33c282f3d02fe5724e3"
 [...]]]></description>
			<content:encoded><![CDATA[<p>This new version of the compressor fixes a few bugs and optimizes string concatenations. You can now keep your code nicely formatted by concatenating string literals, but not suffer any performance hit. For example, the following code:</p>
<pre class="prettyprint">
var url = "http://www.flickr.com/services/rest/"
    + "?method=flickr.test.echo"
    + "&#038;format=json"
    + "&#038;api_key=02b6a73df2c4a33c282f3d02fe5724e3"
    + "&#038;callback=jsonCallback";
</pre>
<p>will become (<span class="cr">&crarr;</span> marks a line continuation)</p>
<pre class="prettyprint">
var url = "http://www.flickr.com/services/rest/<span class="cr">&crarr;</span>
?method=flickr.test.echo&#038;format=json<span class="cr">&crarr;</span>
&#038;api_key=02b6a73df2c4a33c282f3d02fe5724e3&#038;callback=jsonCallback";
</pre>
<p>Also, note that, from now on, all YUI Compressor-related downloads will be done from a separate download page and not directly from this blog.</p>
<p style="margin:30px 0;text-align:center;"><a href="/yuicompressor/" target="_blank" style="padding:8px;border:1px solid #bbb;font-weight:bold;text-decoration:underline;">Download version 2.1 of the YUI Compressor</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2007/08/15/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>YUI Compressor Version 2.0 Now Available</title>
		<link>http://www.julienlecomte.net/blog/2007/08/14/</link>
		<comments>http://www.julienlecomte.net/blog/2007/08/14/#comments</comments>
		<pubDate>Mon, 27 Aug 2007 18:09:35 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2007/08/27/yui-compressor-version-20-now-available/</guid>
		<description><![CDATA[I am very pleased to announce the release of version 2.0 of the YUI Compressor. In addition to fixing several bugs and implementing a few enhancements suggested by the community, I also integrated Isaac Schlueter&#8217;s regular expression based CSS minifier. Therefore, the YUI Compressor is now able to compress both JavaScript and CSS files (see [...]]]></description>
			<content:encoded><![CDATA[<p>I am very pleased to announce the release of version 2.0 of the YUI Compressor. In addition to fixing several bugs and implementing a few enhancements suggested by the community, I also integrated <a href="http://foohack.com/" target="_blank">Isaac Schlueter</a>&#8217;s regular expression based CSS minifier. Therefore, the YUI Compressor is now able to compress both JavaScript and CSS files (see the <a href="/blogfiles/yuicompressor/CHANGELOG" target="_blank">CHANGELOG</a> for a full list of changes) And as always, keep the feedback coming!</p>
<p style="margin:30px 0;text-align:center;"><a href="/yuicompressor/" target="_blank" style="padding:8px;border:1px solid #bbb;font-weight:bold;text-decoration:underline;">Download version 2.0 of the YUI Compressor</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2007/08/14/feed/</wfw:commentRss>
		<slash:comments>36</slash:comments>
		</item>
	</channel>
</rss>
