How do you automate Javascript minification for your Java web applications?

Round-up post

If you post something new in this thread, edit this post to link to yours.

  • Ant apply task (using YUI Compressor)
  • Custom YUI Compressor Ant task
  • Maven YUI Compressor plugin
  • Granule (for JSP, JSF, Grails, Ant)
  • Ant macros for Google Closure compiler
  • wro4j (Maven, servlet filters, plain Java, etc)
  • ant-yui-compressor (ant task for compressing JS+CSS)
  • JAWR
  • Minify Maven Plugin
  • humpty
  • Ant exec task using Terser

We are using Ant task to minify js files with YUICompressor during production build and put result into a separated folder. Then we upload those files to a web server.

Here is an example:

<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>

I think one of the best and right tool for the job is wro4j Check out https://github.com/wro4j/wro4j

It does everything you need:

  • Keep project web resources (js & css) well organized
  • Merge & minify them at run-time (using a simple filter) or build-time (using maven plugin)
  • Free and open source: Released under an Apache 2.0 license
  • several minification tools supported by wro4j: JsMin, Google Closure compressor, YUI etc
  • Very easy to use. Supports Servlet Filter, Plain Java or Spring Configuration
  • Javascript and CSS Meta Frameworks Support: CoffeeScript, Less, Sass etc
  • Validation: JSLint, CSSLint etc

Can run in debug as well as production modes. Just specify all the files it should handle/pre-process and it does the rest.

You can simply include merged, minified and compressed resource like this:

<script type="text/javascript" src="wro/all.js"></script>

I have written ant macros for Google Closure compiler and Yahoo compressor and include this file in different web projects.

<?xml version="1.0" encoding="UTF-8"?>
<!-- CSS and JS minifier. -->
<!DOCTYPE project>
<project name="minifier" basedir=".">

  <property name="gc" value="compiler-r1592.jar" />
  <property name="yc" value="yuicompressor-2.4.6.jar" />

  <!-- Compress single js with Google Closure compiler -->
  <macrodef name="gc-js">
    <attribute name="dir" />
    <attribute name="src" />
    <sequential>
      <java jar="${gc}" fork="true">
        <!--
        - - compilation_level WHITESPACE_ONLY | SIMPLE_OPTIMIZATIONS | ADVANCED_OPTIMIZATIONS
        Specifies the compilation level to use. Default: SIMPLE_OPTIMIZATIONS
        - - warning_level QUIET | DEFAULT | VERBOSE
        Specifies the warning level to use.
        -->
        <arg line="--js=@{dir}/@{src}.js" />
        <arg line="--js_output_file=@{dir}/@{src}-min-gc.js" />
      </java>
    </sequential>
  </macrodef>

  <!-- Compress single js with Yahoo compressor -->
  <macrodef name="yc-js">
    <attribute name="dir" />
    <attribute name="src" />
    <sequential>
      <java jar="${yc}" fork="true">
        <arg value="@{dir}/@{src}.js" />
        <arg line="-o" />
        <arg value="@{dir}/@{src}-min-yc.js" />
      </java>
    </sequential>
  </macrodef>

  <!-- Compress all js in directory with Yahoo compressor -->
  <macrodef name="yc-js-all">
    <attribute name="dir" />
    <sequential>
      <apply executable="java" parallel="false">
        <fileset dir="@{dir}" includes="*.js" excludes="*-min*.js" />
        <arg line="-jar" />
        <arg path="${yc}" />
        <srcfile />
        <arg line="-o" />
        <mapper type="glob" from="*.js" to="@{dir}/*-min-yc.js" />
        <targetfile />
      </apply>
    </sequential>
  </macrodef>

  <!-- Compress all css in directory with Yahoo compressor -->
  <macrodef name="yc-css-all">
    <attribute name="dir" default="${build.css.dir}" />
    <sequential>
      <apply executable="java" parallel="false">
        <fileset dir="@{dir}" includes="*.css" excludes="*-min*.css" />
        <arg line="-jar" />
        <arg path="${yc}" />
        <arg line="-v --line-break 0" />
        <srcfile />
        <arg line="-o" />
        <mapper type="glob" from="*.css" to="@{dir}/*-min.css" />
        <targetfile />
      </apply>
    </sequential>
  </macrodef>
</project>
  • Integration: <import file="build-minifier.xml" /> in your build.xml, then invoke as usual ant tasks: <gc-js dir="${build.js.dir}" src="prototype" /> <yc-js-all dir="${build.js.dir}" />

  • Choice of two minifiers: Google Closure compiler and Yahoo compressor, you should download them manually and place near the xml file

  • Minifiers skip already compressed files (ending with -min*)

  • Usually I make three versions of script: uncompressed (e.g. prototype.js) for debugging, compressed with closure compiler (prototype-min-gc.js) for production server, compressed with Yahoo (prototype-min-yc.js) for troubleshooting because closure compiler uses risky optimizations and sometimes produces invalid compressed file and Yahoo compressor is more safe

  • Yahoo compressor can minify all files in a dir with single macro, Closure compiler cannot