Jawr Postprocessors

Postprocessors are filters that Jawr applies to resources and bundles during startup. These filters provide such things as minification (removal of unneeded whitespace and comments), URL rewriting, and the like. There are two types: file and bundle postprocessors. The file postprocessors are applied to resources before adding them to the bundle. On the other hand, bundle postprocessors are applied to a whole bundle once all the files have been joined into it.  

Normally, you won't need to worry about postprocessors, since Jawr will use them automatically: javascript will be minified using JSMin, and the lincense comments (if any) will be added afterwards. CSS files will also be minified ,license comments will be added and their image URLs will be rewritten so they keep working from within a bundle. But there are countless combinations you can use, plus you may create and use your own postprocessors, so here is how to configure the filter chain applied to files and bundles.

For configuration purposes, every postprocessor has a unique name key, which you use in a comma-separated property in the descriptor, for instance:

        jawr.js.bundle.factory.bundlepostprocessors=JSMin,license
                
        jawr.css.bundle.factory.bundlepostprocessors=cssminify,license
        jawr.css.bundle.factory.filepostprocessors=csspathrewriter

As you see, we specify a couple of bundle posprocessors for both js and css resources, plus a file postprocessor for css files. We didn't specify any file postprocessor for javascript because, at the time of writing, there is none available yet.   Note that the previous example configuration matches the default behavior os Jawr, so it actually makes no difference wether you include it in your descriptor or not. You would set these parameters only to change the default behavior, like for example, to remove minification:

        jawr.js.bundle.factory.bundlepostprocessors=license             
        jawr.css.bundle.factory.bundlepostprocessors=license

Optionally, you may specify a different set of postprocessors for any given bundle, so you can mix and match different schemes within your application. In order to do that, you specify similar attributes for a particular bundle:

        jawr.js.bundle.foo.bundlepostprocessors=license
        jawr.js.bundle.foo.fileprocessors=none
        

In this example, the bundle postprocessor for the foo bundle is set to license, meaning no minification will occur. And for the file-by-file postprocessor, it is specified that none will be used.

Jawr allows you to define the postprocessors for composite bundles. The format of the postprocessor properties is :

  • jawr.resourceType.bundle.bundleName.composite.bundlepostprocessors
  • jawr.resourceType.bundle.bundleName.composite.filepostprocessors

Custom postprocessors

You can also implement your own postprocessor components (for js, css, or both) to perform any functionality not offered by the included ones. To do that, you must create a class with a no-params constructor that implements the interface net.jawr.web.resource.bundle.postprocess.ResourceBundlePostProcessor. This interface defines a single method:

        /**
         * Postprocess a bundle of resources. 
         * @param StringBuffer Joined resources. 
         * @return StringBuffer a buffer containing the postprocessed bundle. 
         */
        public StringBuffer postProcessBundle(BundleProcessingStatus status,StringBuffer bundleString);

The first parameter is an object which encapsulates the status of a bundling process and also gives you acces to Jawr configuration plus other data which may be useful under certain circumstances. Most of the time, though, you won't need to use it at all.

The bundleString StringBuffer will contain different data depending on wether the postprocessor is used as a bundle postprocessor or a file postprocessor. In the first case, it will contain the text for the whole bundle, while in the latter case it will contain the text for just a single item in the bundle.

Finally, the return StringBuffer should contain the bundleString data after it is modified by the postprocessor. As an example, here is an implementation of a postprocessor which we would use to wrap all our scripts in a function that is inmediately executed:

package net.jawr.test;
// [import statements...]

public class FunctionWrapperPostProcessor implements ResourceBundlePostProcessor {
        
        public StringBuffer postProcessBundle(BundleProcessingStatus status,StringBuffer bundleString) {
                StringBuffer ret = new StringBuffer();
                ret.append("function(){");
                ret.append(bundleString);
                ret.append("}()");
                return ret;
        }
}

To use this postprocessor with our application, we need to declare it in the properties configuration, by giving it a name and declaring the class so that Jawr may create an instance when starting up. The name you give to your postprocessor can then be used to define the bundlepostprocessors and filepostprocessors properties, thus allowing you to create a chain that combines your postprocessors with those of Jawr.

The name and class are defined by declaring a property in the form jawr.custom.postprocessors.[name].class=[class]. For example, the following configuration would add two custom postprocessors named func and sample and map them in different postprocessing chains:

jawr.custom.postprocessors.func.class=net.jawr.test.FunctionWrapperPostProcessor
jawr.custom.postprocessors.sample.class=net.jawr.test.SamplePostProcessor

jawr.js.bundle.factory.bundlepostprocessors=JSMin,func,sample,license
jawr.js.bundle.foo.bundlepostprocessors=license=func,license


Custom postprocessors for composite bundle

For a composite bundle, you can define the child bundle associated to it using the child.names property like follow.

jawr.css.bundle.myCompositeBundle.child.names=child_1,child_2

When you define a filepostprocessor on a composite bundle, this postprocessor will be applied on the child bundle content. The child bundle content will be treated as a single file. If you define a bundle postprocessor on a composite bundle, the postprocessor will be applied on the whole bundle.

To disable postprocessing on the composite bundle, you just need to configure you composite bundle as such :

jawr.css.bundle.myCompositeBundle.fileprocessors=none
jawr.css.bundle.myCompositeBundle.bundlepostprocessors=none

Jawr included postprocessors reference

Css and Js common postprocessors

Licenses includer
  • Type: Bundle
  • Properties Key: license

The licenses includer will add the content of .license files at the top of a bundle. That way you will be able to add open source mandatory licenses or any other comment to the top of your resources. Check the license files page for more info.


Note that licenses are themselves code comments, so you should be careful to always use this processor after any minification or compression processor has executed and not before. Otherwise, the license might be deleted from the bundle right after it was inserted.


YUI compressor
  • Type: Bundle
  • Properties Key: YUI, YUIobf

This processor uses Julien Lecomte's YUI compressor. This is a javascript and CSS minification tool that can also perform code obfuscation in the case of javascript bundles. If you want obfuscation, you should use the YUIobf key when defining postprocessors, but remember that this is only valid for javascript bundles. The YUI compressor has an advantage over JSMin and Jawr's custom CSS compressor in that it will achieve better minification (although in the case of CSS the difference is minimal). On the other hand it will add a dependency to the YUI compressor and Rhino libraries. You can get YUI here, and rhino here. Maven users can get both by adding a single dependency, like this:

        <dependency>
            <groupId>com.yahoo.platform.yui</groupId>
            <artifactId>yuicompressor</artifactId>
            <version>2.2.5</version>
        </dependency>

Unfortunately, this is the only way I know to get YUI from maven, and it is somewhat ugly since it will include both the YUI compressor and rhino, which might be problematic if you already have rhino on your server's classpath. YUI overwrites some of Rhino's classes also, so keep in mind that having another copy of Rhino.jar in your classpath might cause class loading issues.

Javascript-specific postprocessors

JSMin
  • Type: Bundle
  • Properties Key: JSMin

This processor uses Douglas Crockford's JSMin minificator. It will remove any comments in code and unnecesary whitespace in a very safe manner.

CSS-specific postprocessors

CSS Minificator
  • Type: Bundle
  • Properties Key: cssminify

This processor removes comments and unneeded whitespace using search and replace with regular expressions. It is on by default and is almost as efficient as the YUI compressor.

CSS combine Media
  • Type: Bundle
  • Properties Key: cssCombineMedia

This processor will wrap the content of the bundle with the "media" value defined in the Jawr configuration file associated to this bundle.
Jawr will search for th value associated to : jawr.css.bundle.bundleName.media to find the media value to set. If no media value is found, Jawr will set the media to screen.

For example, if your bundle is define like this :

        jawr.css.bundle.combine_print.id=/bundles/combine_print.css
        jawr.css.bundle.combine_print.mappings=/resources/css/combine/print_1.css,/resources/css/combine/print_2.css
        jawr.css.bundle.combine_print.bundlepostprocessors=cssCombineMedia
        jawr.css.bundle.combine_print.media=print

The content of the bundle will be wrap around a media rule declaration set to "print".

@media print {

        ... /* Content of the bundle goes here */
}        
CSS Path rewriter
  • Type: File
  • Properties Key: csspathrewriter

This processor rewrites relative paths in URLs for each file that is added to a bundle. A bundle will have a different URL to that of its contained resources, so in order for relative paths to image files and the like to keep working, URLs must be rewritten accordingly.

CSS Import resolver
  • Type: File
  • Properties Key: cssimport

This processor imports the CSS resources referenced by @import url(...) statement. These resources are included in the generated CSS bundle.

CSS base64 postprocessor
  • Type: Bundle
  • Properties Key: base64ImageEncoder

This processor encodes the CSS images in base64 except for the images which has as annotation /** jawr:base64-skip */ statement. This postprocessor should not be used with the csspathrewriter, because they are doing the same job rewriting the image URL. WARNING : It is also important to set the base64ImageEncoder not only as a bundle post processor but as a file post processor AND a bundle post processor, because this post processor needs to prepend the MHTML part to the bundle and also to rewrite the URL for each file.
So never use this post processor only as a bundle post processor or only as a file post processor.

User submitted postprocessors

Some users are so kind as to submit their own custom postprocessors. If you have one that you think may be useful to others, please post it at the support forum and they will be shared among the Jawr community of users. To use any of these, download the source file and add it to your project source. Then declare the class and a mapping key as described at the custom postprocessors section above and you are ready to go. You can even go ahead and customize the class to suit your own needs.

Console Log Statement Remover

This postprocessor uses a regular expression to find and remove all the statements that write to the Firebug/Safari console. Specifically, it removes statements with the form window.console.log([...]). If you use a different form you can change the regular expression in the source file.

Thanks to Ryan Wilson for posting this work.