Sep 18 2007

YUI Compressor Version 2.2 Now Available

Published by Julien Lecomte under Web Development

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:

  1. All informational and error messages are now printed to stderr.
  2. If no input file is specified, the YUI Compressor defaults to stdin. In that case, you must specify the --type 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)
  3. If no output file is specified, the YUI Compressor defaults to stdout (in prior versions, it used to create a file named after the input file, and appended the -min suffix)

The other main feature brought by this new version of the YUI Compressor is the support for JScript conditional comments:

/*@cc_on
   /*@if (@_win32)
      document.write("OS is 32-bit, browser is IE.");
   @else @*/
      document.write("Browser is not 32 bit IE.");
   /*@end
@*/

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 eval or with 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’s conditional comments is to be avoided.

Finally, a few improvements have been made to the CSS compressor.

Download version 2.2 of the YUI Compressor

11 responses so far

Sep 11 2007

Building Web Applications With Apache Ant

Published by Julien Lecomte under Web Development

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 do all the dirty and repetitive work of reliably putting all the pieces together.

Apache Ant

Apache Ant

Many tools (make, gnumake, nmake, jam, etc.) are available today to build applications. However, when it comes to building a web application, my personal favorite is definitely Apache Ant (here is a good explanation of Ant’s benefits over the other tools) This short tutorial will assume you already have some basic knowledge of Ant (if you don’t, you should flip through its user manual beforehand) This article will focus mainly on building front-end code using Ant.


Build types

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:

<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">
</target>

<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">
</target>

<target name="load.properties">
    <property file="ant.properties"/>
</target>

<target name="load.properties.dev" depends="load.properties">
    <property name="js.preprocess.switches" value="-P -DDEBUG_VERSION=1"/>
    <property name="js.compressor.switches" value="--nomunge --line-break"/>
</target>

<target name="load.properties.prod" depends="load.properties">
    <property name="js.preprocess.switches" value="-P -DDEBUG_VERSION=0"/>
    <property name="js.compressor.switches" value=""/>
</target>

Concatenate your JavaScript and CSS files

Concatenating JavaScript and CSS files contributes to making your site faster according to Yahoo!’s Exceptional Performance team. File concatenation using Ant is trivial using the concat task. However, it is often important to concatenate JavaScript and CSS files in a very specific order (If you are using YUI 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:

<target name="js.concatenate">
    <concat destfile="${build.dir}/concatenated/foo.js">
        <filelist dir="${src.dir}/js"
            files="a.js, b.js"/>
        <fileset dir="${src.dir}/js"
            includes="*.js"
            excludes="a.js, b.js"/>
    </concat>
</target>

It is also possible to prepend some comments to the destination file, which is often used for license and copyright information, using a nested header element (see the Apache Ant manual) 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.

Preprocess your JavaScript files using CPP

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 C preprocessor, which is usually installed by default on UNIX machines. It is available on Windows machines as well using cygwin. Here is a snippet of an Ant build.xml file illustrating the use of cpp to preprocess JavaScript files:

<target name="js.preprocess" depends="js.concatenate">
    <apply executable="cpp" dest="${build.dir}/preprocessed">
        <fileset dir="${build.dir}/concatenated"
            includes="foo.js"/>
        <arg line="${js.preprocess.switches}"/>
        <srcfile/>
        <targetfile/>
        <mapper type="identity"/>
    </apply>
</target>

You can now write JavaScript code that looks like the following:

include.js:

#if DEBUG_VERSION
function assert(condition, message) {
    ...
}
#define ASSERT(x, ...) assert(x, ## __VA_ARGS__)
#else
#define ASSERT(x, ...)
#endif

foobar.js:

#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
    ...
}

Just a word of caution here: make sure you use the UNIX EOL character before preprocessing your files. Otherwise, you’ll have some issues with multi-line macros. You may use the fixcrlf Ant task to automatically fix that for you.

Minify your JavaScript and CSS files

Minifying your JavaScript and CSS files will help make your application faster according to Yahoo!’s Exceptional Performance team. I warmly recommend you use the YUI Compressor, available for download on this site. There are two ways to call the YUI Compressor from Ant. Here is the first one using the java task:

<target name="js.minify" depends="js.preprocess">
    <java jar="yuicompressor.jar" fork="true">
        <arg value="foo.js"/>
    </java>
</target>

Here is another way using the apply task that allows you to pass several files to the compressor using a fileset:

<target name="js.minify" depends="js.preprocess">
    <apply executable="java" parallel="false">
        <fileset dir="." includes="foo.js, bar.js"/>
        <arg line="-jar"/>
        <arg path="yuicompressor.jar"/>
        <mapper type="glob" from="*.js" to="*-min.js"/>
    </apply>
</target>

Update: Starting with version 2.2.x of the YUI Compressor, the ant target described above needs to be slightly modified:

<target name="js.minify" depends="js.preprocess">
    <apply executable="java" parallel="false">
        <fileset dir="." includes="foo.js, bar.js"/>
        <arg line="-jar"/>
        <arg path="yuicompressor.jar"/>
        <srcfile/>
        <arg line="-o"/>
        <mapper type="glob" from="*.js" to="*-min.js"/>
        <targetfile/>
    </apply>
</target>

Also consider the following ant target to minify CSS files:

<target name="js.minify" depends="js.preprocess">
    <apply executable="java" parallel="false">
        <fileset dir="." includes="*.css"/>
        <arg line="-jar"/>
        <arg path="yuicompressor.jar"/>
        <arg line="--line-break 0"/>
        <srcfile/>
        <arg line="-o"/>
        <mapper type="glob" from="*.css" to="*-min.css"/>
        <targetfile/>
    </apply>
</target>

Work around caching issues

Adequate cache control can really enhance your users’ 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’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.

The copy and file name replacement will be handled by a custom Ant task named FileTransform (see FileTransform.java) The first step is to build the task from the source and define the custom task:

<target name="-setup.build.tools" depends="-load.properties">
    <mkdir dir="${build.dir}/tools/classes"/>
    <javac srcdir="tools/src"
           destdir="${build.dir}/tools/classes"
           includes="**/*.java">
        <classpath>
            <pathelement location="tools/lib/ant.jar"/>
        </classpath>
    </javac>
    <taskdef name="FileTransform"
        classname="com.yahoo.platform.build.ant.FileTransform"
        classpath="${build.dir}/tools/classes"/>
</target>

(Note the use of a “-” in front of the name of the target. This is used to make the target “private” 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:

<target name="-copy.js.files" depends="-setup.build.tools">
    <mkdir dir="${build.dir}/js"/>
    <FileTransform todir="${build.dir}/js"
        changefilenames="true"
        propertiesfile="${build.dir}/js.files.mapping.properties">
        <fileset dir="site/js" includes="*.js"/>
    </FileTransform>
</target>

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 copy task:

<target name="-copy.php.files" depends="-copy.js.files">
    <mkdir dir="${build.dir}/php"/>
    <copy todir="${build.dir}/php">
        <fileset dir="site/php" includes="*.php"/>
        <filterset>
            <filtersfile file="${build.dir}/js.files.mapping.properties"/>
        </filterset>
    </copy>
</target>

You can download an archive containing a very simple Ant project illustrating this advanced technique.

Deploy your application

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)

You have many options to copy files to remote servers with Apache Ant. You could use the copy task to copy files to a locally mounted file system, or you could use the optional FTP task. My personal preference is to use scp and rsync (both utilities are available on all major platforms) Here is a very simple example demonstrating the use of scp with Apache Ant:

<apply executable="scp" failonerror="true" parallel="true">
    <fileset dir="${build.dir}" includes="**/*"/>
    <srcfile/>
    <arg line="${live.server}:/var/www/html/"/>
</apply>

And here is an example showing how you can run remote commands:

<exec executable="ssh" failonerror="true">
    <arg line="${live.server}"/>
    <arg line="sudo webctl restart"/>
</exec>

Conclusion

I hope this article has given you some ideas of what’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.

22 responses so far

Sep 06 2007

The Rich Web Experience 2007

Published by Julien Lecomte under Web Development

I am currently attending the Rich Web Experience conference in San Jose. Lots of great topics are being covered by immensely talented speakers who are passionate about sharing their knowledge. Here are a few pictures I took with my iPhone (hover over the images to get a short description)

A panel of experts talking about the current state of affairs in rich Internet application development

Dean Saxe talking about secure application development with Ajax

Yahoos having lunch


Kevin Hoyt from Adobe having some problems with his Mac

Mark Meeker talking about accessibility

The master at work: Douglas Crockford talking about JavaScript


Update: Douglas Crockford’s keynote was absolutely brilliant as usual (I’m not just saying that because I happen to be sitting only a few feet away from him at Yahoo!) and I hope it will have made a lot of people think about some of the problems our industry is facing.

Update: I was very disappointed with Jesse James Garrett’s keynote on Friday. The beginning of his talk was irritating to say the least as it was focused mainly on his personality (Extract: “You may be wondering why I’m so famous”…) He then talked about the history of Ajax. According to him, Ajax started when he discovered it (2004?), but he completely forgot to mention that a lot of people were already doing Ajax back in the 90’s (OddPost, back in 2001, was already doing what would still be considered cutting edge Ajax by today’s standards) Finally, the rest of his talk was directed towards user experience designers, not engineers. I know UED had a strong presence at the conference, so I won’t blame him for that. I just found it extremely boring. Sorry Jesse!

2 responses so far

Sep 03 2007

Introducing Simplix, an Operating System Anybody Can Understand

Published by Julien Lecomte under System Programming

Back in university, I took a few classes dealing with operating system design. These classes were extremely theoretical and, in some ways, helped me throughout my curriculum and my career, serving as a solid base I could then build upon to gain new knowledge. However, after spending a few years working with high level languages in sandboxed environments, you tend to forget how things work at the lower level, and that sometimes leads to less than optimal higher level code. As a consequence, a few months ago, I decided it was time for me to brush up on my core CS skills. However, I needed a tangible goal. And then I thought: why not write an operating system? OK, not a full blown operating system of course, but the seed of a very basic one (calling Simplix an operating system is a bit of a stretch since it cannot be used for anything actually useful) One that other people could look at and actually understand (Even MINIX, which was designed to be easy to understand by students, is not that easy to grasp without spending a lot of time hunched over the code) Here are the high level characteristics of Simplix:


  • Target architecture: PC with a single Intel 386 or better CPU
  • Monolithic, interruptible, non preemptible kernel
  • Hardware interrupt handling using the Intel 8259 PIC
  • Software interrupt handling
  • Basic management of physical memory
  • Peripherals: keyboard, video screen
  • Support for kernel threads and user space processes
  • Support for virtual memory using segmentation
  • Support for system calls

Here is a screenshot showing Simplix running inside the Bochs emulator:

Over the next few months, I will be posting several articles on this blog in an attempt to explain how Simplix works, so please stay tuned! In the meantime, you can already take a look at the complete up to date source code and even download it. Also, if you are interested in the topic of operating system development, I warmly recommend reading the bible of system programming: Operating Systems: Design and Implementation (Second Edition) by Andrew S. Tanenbaum and Albert S. Woodhull. I got mine used on Amazon.com for $8… Cheers!

4 responses so far

Sep 01 2007

The Planets Of The Solar System

Published by Julien Lecomte under Astronomy

A few years ago, I was very active in the field of amateur astronomy. I used to take pictures of the planets and the moon using a MEADE ETX 105 telescope and a Philips TouCam Pro webcam. I have not been very involved with astronomy lately (I hope that will change in the next few years when I can finally move to a house with a backyard), but I thought I’d share a few of those pictures with my readers. The picture below features Mars (taken at three different times of the year - notice the ice cap progressively melting), Jupiter and Saturn. Also check out this time-lapse movie of Jupiter [200KB] showing the famous great red spot. Enjoy!

Mars, Jupiter and Saturn

2 responses so far

Aug 29 2007

YUI Compressor Version 2.1 Now Available

Published by Julien Lecomte under Web Development

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"
    + "&format=json"
    + "&api_key=02b6a73df2c4a33c282f3d02fe5724e3"
    + "&callback=jsonCallback";

will become ( marks a line continuation)

var url = "http://www.flickr.com/services/rest/
?method=flickr.test.echo&format=json
&api_key=02b6a73df2c4a33c282f3d02fe5724e3&callback=jsonCallback”;

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.

Download version 2.1 of the YUI Compressor

29 responses so far

Aug 27 2007

YUI Compressor Version 2.0 Now Available

Published by Julien Lecomte under Web Development

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’s regular expression based CSS minifier. Therefore, the YUI Compressor is now able to compress both JavaScript and CSS files (see the CHANGELOG for a full list of changes) And as always, keep the feedback coming!

Download version 2.0 of the YUI Compressor

36 responses so far

Aug 21 2007

Gzip Your Minified JavaScript Files

Published by Julien Lecomte under Web Development

Today, I found out that the good folks behind jQuery were using Packer, another great JavaScript compression utility by Dean Edwards, to distribute their compressed version of the library. The result: an amazingly small 21KB download! My first thought was: Wow, that is small! I then tried the YUI Compressor on the uncompressed version of the jQuery library and obtained a 31KB file. Not bad, but not nearly as good as Packer… I then decided to compare the gzipped version of these files. Here are my findings:

File File size Gzipped file size
Original jQuery library 62,885 bytes 19,758 bytes
jQuery minified with JSMin 36,391 bytes 11,541 bytes
jQuery minified with Packer 21,557 bytes 11,119 bytes
jQuery minified with the YUI Compressor 31,822 bytes 10,818 bytes

These results are amazing! The smallest file is the file obtained by minifying jQuery using the YUI Compressor and then gzipping. I would have thought that using Packer would have yielded the smallest file. In fact, it appears that Packer’s redundancy reduction algorithm is detrimental to gzip compression.

In addition to that, using Packer’s redundancy reduction algorithm adds a delay at the time the script gets executed (because the script needs to be unpacked and then eval’ed) On my laptop, this delay is about 200 msec. The conclusion is clear: for optimal performance, gzip your JavaScript code, and stay away from “advanced” JavaScript compression schemes that look attractive on paper, but end up degrading the performance of your site.

If your web hosting company does not offer HTTP compression, but gives you access to PHP (that’s the case of Yahoo! Web Hosting), I wrote a simple PHP script that will compress files and set the cache control headers so that the requested files actually get cached by the browser. I used this script with great success for a web site I worked on recently: http://www.okomis.com/

Note: yahoo-dom-event.js, minified with the YUI Compressor and gzipped only weighs 9,476 bytes. Not bad!

Update: Read this article by John Resig on JavaScript library Loading Speed.

51 responses so far

Aug 20 2007

YUI Compressor Version 1.1 Now Available

Published by Julien Lecomte under Web Development

The release of the YUI Compressor last week has generated a lot of buzz and excitement throughout the web development community. Actually, after receiving so much great feedback, I felt compelled to issue a minor update as soon as possible to fix the most important items that were brought to my attention (see the CHANGELOG file for a full list of changes) And please, keep the feedback coming!

Download version 1.1 of the YUI Compressor

10 responses so far

Aug 13 2007

Introducing the YUI Compressor

Published by Julien Lecomte under Web Development

Is there a need for a new JavaScript minifier?

Yahoo's YUI Compressor

According to Yahoo!’s Exceptional Performance Team, 40% to 60% of Yahoo!’s users have an empty cache experience and about 20% of all page views are done with an empty cache (see this article for more information on browser cache usage) This fact outlines the importance of keeping web pages as lightweight as possible. Improving the engineering design of a page or a web application usually yields the biggest savings. After that come many different techniques such as minification of the code, HTTP compression, etc. In terms of code minification, the most widely used tools to minify JavaScript code are Douglas Crockford’s JSMin and the Dojo compressor. Both tools however have pitfalls. 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 Dojo compressor, on the other hand, does a better job at compacting code (it obfuscates local variables) but is unsafe and potentially introduces bugs if you are unaware of its limitations.


What is the YUI Compressor?

The YUI Compressor is a new JavaScript minifier. Its level of compaction is higher than the Dojo compressor, and it is as safe as JSMin. Tests on the YUI library have shown savings of about 18% compared to JSMin and 10% compared to the Dojo compressor (these respectively become 10% and 5% after HTTP compression)

How does it work?

The YUI Compressor is written in Java (requires Java >= 1.4) and relies on Rhino to tokenize the source JavaScript file. It starts by analyzing the source JavaScript file to understand how it is structured. It then prints out the token stream, replacing all local symbols by a 1 (or 2, or 3) letter symbol wherever such a substitution is appropriate (in the face of evil features such as eval or with, the YUI Compressor takes a defensive approach by not obfuscating any of the scopes containing the evil statement). The YUI Compressor is open-source, so don’t hesitate to look at the code to understand exactly how it works.

Where can I get it?

An archive containing both source and binary is available for download on this site.

How do I run it?

java -jar yuicompressor-1.0.jar
    [-h, --help] [--warn] [--nomunge]
    [--charset character-set] [-o outfile] infile

The following command line for example:

java -jar yuicompressor-1.0.jar myfile.js

will minify the file myfile.js and output the file myfile-min.js. For more information on how to use the YUI Compressor, please refer to the documentation included in the archive.

Limitations

Unlike JSMin, the YUI Compressor is slow and cannot be used for on-the-fly code minification (see minify for a PHP implementation of JSMin by Ryan Grove, another Yahoo! engineer, that does on-the-fly JavaScript minification among other things)

Has Yahoo!’s official position on obfuscation changed?

Douglas Crockford wrote an interesting article last year on minification vs. obfuscation. While that article still holds true, the YUI Compressor actually represents a 3rd way, in which code compaction does not carry the risk of introducing new bugs. The YUI Compressor is currently considered as a replacement for JSMin to compact the entire YUI library.

Feedback appreciated

The YUI Compressor is still a fairly new tool, so your feedback is well appreciated. Don’t hesitate to drop me a line if you find a bug, or think an important feature is missing. I will make updates available on this site, so watch for posts related to the YUI Compressor on this blog. This software belongs to the community, so it’s up to the community to make it better!

Additional notes

  • Do not hesitate to use the --warn option. The YUI Compressor will warn you if it finds anything that seems abnormal with your code, or that might reduce the level of compression.
  • Keep as little of your code as possible in the global scope. This has 2 benefits:
    1. You’ll get a better level of compression since the YUI Compressor does not obfuscate global symbols (which would make it unsafe)
    2. You won’t pollute the global object (see this article)

69 responses so far

« Prev - Next »