up

Zoompf's Web Performance Blog

Note: Archived Content

This is the archived version of the Zoompf blog. Since our acquisition by Rigor, all our new research and posts on web performance are being published on The Rigor Blog

JSMin, Important Comments, and Copyright Violations

 Billy Hoffman on November 6, 2009. Category: Uncategorized

Since launching Zoompf last Friday I’ve performed dozens of free web performance scans. A few users reported to me what they thought was a bug. Zoompf was reporting that certain JavaScript files could be further minified. The issue was that these websites used already minified versions of well known JavaScript frameworks like jQuery . These frameworks had a JavaScript comment at the top of the file that included the copyright information and licensing information. Zoompf uses JSMin under the covers to determine which JavaScript files or inline JavaScript blocks can be minified. JSMin would see this comment and remove it. While this is a certainly a performance improvement it is also a copyright infringement violation! That’s not good. We need to solve this.

This is actually a broader problem then just Zoompf. It exists with all of the dozens of ports of JSMin out there as well as many other minifiers. It turns out YUI compressor does not have this issue because YUI supports so-called “important comments.” Important comments are special code comments that will not be removed by the minifier. Ajax libraries like jQuery and SWFObject use them around their copyright comments so important comment aware minifiers will leave them intact. They look like this:

/*!
    Somthing very important
*/

Important comments are an excellent idea. They provide a way to minify files while retaining copyright and licensing information. All minifiers should support this! So how can we achieve that? We must solve 2 challenges:

  1. Add support for important comments to existing JavaScript minifers
  2. Get JavaScript frameworks to start using important comments appropriately

Since JSMin is the canonical example, I went ahead and added support for important comments to the JavaScript port of JSMin written by Franck Marcia. You can download the updated version of JSMin with Important Comments support or download the JSMin Important Comments patch. (For tips on apply the patch read this article).

The change was made to the next() function, which is supposed to return the next character to be inserted into the minified output. This is the code that detects // and /* */ based comments and silently consumes them. I simply modified the code to check if the comment is important and if so return the entire comment to be written to the minified output stream instead of a single character. The main part of the patch is shown here:

case '*':
//this is a comment. What kind?
get();
if(peek() == '!') {
	//important comment
	var d = '/*!';
	for (;;) {
		c = get();
		switch (c) {
			case '*':
				if (peek() == '/') {
					get();
					return d+'*/';
				}
				break;
			case EOF:
				throw 'Error: Unterminated comment.';
			default:
				d+=c;
		}
	}
} else {
	//unimportant comment	gobbling here ...
}

This solution is easily added to any port of JSMin written in a weakly typed language. This is because the next() function is supposed to return only a single character. This patch makes it return a string containing the important comment block. In JSMin ports to JavaScript or PHP this is not a problem. In JSMin ports written in strongly typed languages like C, C#, or Java, the next() function returns an integer.

Now JSMin is like a Swiss-made watch. It is as elegant as it is compact. It is a good example of how state machines can be small and powerful. Unfortunately, like a Swiss watch, you cannot easily add a new feature without a significant amount of work. I toyed with a few very small patches. I tried modifying the next() function to simply not longer detect or silently consume comments that were important. This caused important comments to be are processed as if they were JavaScript source code. Not bad, but it minifies the comment’s content and could puke on things in the comment like unmatched quotes or by thinking a slash is an unclosed Regex literal. I’m going to continue to try and patch JSMin in a way that works with both weakly typed and strongly typed languages that retains the elegance of Douglas Crockford’s design. Stay tuned. For now the weakly typed solution is available.

I would say that minifiers that support important comments should not convert a /*! … */ comment to a /* … */ comment. This would allow minifiers to run on text that could have already been minified without removing anything important. The extra character per important comment cost is well worth the ability to chain together multiple tools without having to worry about losing anything.

The second challenge is getting JavaScript frameworks to start using important comments appropriately. Notice I said appropriately. We don’t want to just go adding a ! to the first comment or anything. Some frameworks, such as Mootools, include all sorts of content in there initial comment that should not be included in a minified version with important content. Ideally frameworks should use a important comment block the way SWFObject did. A simple, single, important comment that contains the name of the library, a URL to the framework’s web page, the license it uses, and a link to the license. Yahoo’s User Interface Library is another example of an appropriate comment block, though they are not using important comment syntax for their copyright and licensing declaration.

Know any other JavaScript minifiers that support important comments? Working on a JavaScript Framework and want to add important comments? Drop me a message and share all about it.

Comments

Have some thoughts, a comment, or some feedback? Talk to us on Twitter @zoompf or use our contact us form.