How do you automate Javascript minification for yo

2019-01-20 21:13发布

问题:

I'm interested in hearing how you prefer to automate Javascript minification for your Java web apps. Here are a few aspects I'm particularly interested in:

  • How does it integrate? Is it part of your build tool, a servlet filter, a standalone program post-processing the WAR file, or something else?
  • Is it easy to enable and disable? It's very unfunny to try and debug a minified script, but it's also useful for a developer to be able to test that the minification doesn't break anything.
  • Does it work transparently, or does it have any side effects (apart from the ones inherent in minification) that I have to consider in my day-to-day work?
  • Which minifier does it use?
  • Does it lack any features that you can think of?
  • What do you like about it?
  • What don't you like about it?

This will mostly serve as a reference for my future projects (and hopefully other SOer's will find it informative, too), so all kinds of tools are interesting.

(Note that this is not a question about which minifier is best. We have plenty of those around already.)

回答1:

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


回答2:

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. You can find some good examples for YUI+Ant integration in this blog.

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>


回答3:

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>


回答4:

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



回答5:

I tried two ways:

  1. using a servlet filter. When in production mode, the filter is activated and it compress any data bounded to URL like *.css or *.js
  2. using maven and yuicompressor-maven-plugin; the compression is perfomed una-tantum, (when assembling the production war)

Of course the latter solution is better since it does not consume resources at runtime (my webapp is using google app engine) and it doesn't complicate your application code. So assume this latter case in the following answers:

How does it integrate? Is it part of your build tool, a servlet filter, a standalone program post-processing the WAR file, or something else?

using maven

Is it easy to enable and disable? It's very unfunny to try and debug a minified script, but it's also useful for a developer to be able to test that the minification doesn't break anything.

you activate it only when assemblying the final war; in development mode you see the uncompressed version of your resources

Does it work transparently, or does it have any side effects (apart from the ones inherent in minification) that I have to consider in my day-to-day work?

absolutely

Which minifier does it use?

YUI compressor

Does it lack any features that you can think of?

no, it is very complete and easy to use

What do you like about it?

it is integrated with my favourite tool (maven) and the plugin is in the central repository (a good maven citizen)



回答6:

I think you need a compression library, for example Granule tag.

http://code.google.com/p/granule/

It gzip and combine javascripts wrapped by g:compress tag using different methods, also has Ant task as well

code sample is:

<g:compress>
  <script type="text/javascript" src="common.js"/>
  <script type="text/javascript" src="closure/goog/base.js"/>
  <script>
       goog.require('goog.dom');
       goog.require('goog.date');
       goog.require('goog.ui.DatePicker');
  </script>
  <script type="text/javascript">
      var dp = new goog.ui.DatePicker();
      dp.render(document.getElementById('datepicker'));
  </script>
</g:compress>
...



回答7:

I'm really surprised no one mentioned JAWR - https://j-a-w-r.github.io

It's pretty mature and supports all standard features that are to be expected, and a bit more. Here is how it holds against the OP's excellent criteria.

How does it integrate? Is it part of your build tool, a servlet filter, a standalone program post-processing the WAR file, or something else?

It originally did the processing/heavy-lifting at application startup and serving was based on a servlet. Starting with 3.x they added support for integrating at build time.

Support for JSP and Facelets is provided through a custom JSP tag library to import processed resources. In addition to that, a JS resources loader is implemented which supports loading the resources from static HTML pages.

Is it easy to enable and disable? It's very unfunny to try and debug a minified script, but it's also useful for a developer to be able to test that the minification doesn't break anything.

A debug=on option is available to use before application startup, and a custom GET parameter can be specified at individual requests in production to toggle debug mode selectively at runtime for said request.

Which minifier does it use?

For JS it supports YUI Compressor and JSMin, for CSS I'm not sure.

Does it lack any features that you can think of?

SASS support comes to mind. That said, it does support LESS.



回答8:

Our project has handled it a number of ways but we have continued to use the YUI Compressor through our different iterations.

We initially had a servlet handle the compression for JavaScript the first time that particular file was accessed; it was then cached. We already had a system in place to handle custom property files so we simply updated our configuration files to support enabling or disabling the compressor depending on the environment we were working in.

Now the development environments never use compressed JavaScript for debugging purposes. Instead we handle the compression in our build process when exporting our application to a WAR file.

Our client has never raised concerns about the compression and the developers don't notice it until they decide to debug JavaScript. So I'd say it's rather transparent with minimal, if any, side affects.



回答9:

This worked for me: https://bitbucket.org/m6_russell_francis/yui-compressor-ant-task/wiki/Home

<!-- minimize all static *.css & *.js content -->
<target name="static-content-minify">

    <taskdef name="yuicompressor"
             classname="com.metrosix.yuicompressor.anttask.YuiCompressorTask">
        <classpath>
            <pathelement location="${jar.yui.compressor}"/>
            <pathelement location="${jar.yui.anttask.compressor}" />
        </classpath>
    </taskdef>

    <yuicompressor todir="${build.static.content.min}" charset="utf-8" 
        preserveallsemicolons="true" munge="true" >
        <fileset dir="${src.static.content}">
            <include name="**/*.css"/>
            <include name="**/*.js"/>
        </fileset>
    </yuicompressor>
</target>


回答10:

I'm writing a framework for managing web assets, called humpty. It aims to be simpler and more modern than jawr or wro4j by using WebJars and ServiceLoaders.

How does it integrate? Is it part of your build tool, a servlet filter, a standalone program post-processing the WAR file, or something else?

In development, a servlet processes the assets as necessary. The assets would then be pre-compiled before production and placed in a public folder, so that the only part that is used is generating the correct includes in the HTML.

Is it easy to enable and disable? It's very unfunny to try and debug a minified script, but it's also useful for a developer to be able to test that the minification doesn't break anything.

That would be done by switching between development and production modes.

Does it work transparently, or does it have any side effects (apart from the ones inherent in minification) that I have to consider in my day-to-day work?

I believe it is transparent, but does strongly favour the use of WebJars.

Which minifier does it use?

Whichever one the plugin you put on your classpath uses. Currently looking at writing a plugin for the Google Closure Compiler.

Does it lack any features that you can think of?

Still pre-release, though I'm using it in production. The maven plugin still needs a lot of work.

What do you like about it?

The simplicity of just adding a dependency to configure the framework

What don't you like about it?

It's my baby, I love it all ;)