001 /* 002 * Copyright © 2008, 2012 Pedro Agulló Soliveres. 003 * 004 * This file is part of DirectJNgine. 005 * 006 * DirectJNgine is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU Lesser General Public License as published by 008 * the Free Software Foundation, either version 3 of the License. 009 * 010 * Commercial use is permitted to the extent that the code/component(s) 011 * do NOT become part of another Open Source or Commercially developed 012 * licensed development library or toolkit without explicit permission. 013 * 014 * DirectJNgine is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU Lesser General Public License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public License 020 * along with DirectJNgine. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * This software uses the ExtJs library (http://extjs.com), which is 023 * distributed under the GPL v3 license (see http://extjs.com/license). 024 */ 025 026 package com.softwarementors.extjs.djn.jscodegen; 027 028 import java.io.IOException; 029 import java.io.Reader; 030 import java.io.StringReader; 031 import java.io.StringWriter; 032 import java.io.UnsupportedEncodingException; 033 import java.io.Writer; 034 035 import org.apache.log4j.Logger; 036 import org.mozilla.javascript.ErrorReporter; 037 import org.mozilla.javascript.EvaluatorException; 038 039 import com.softwarementors.extjs.djn.StringUtils; 040 import com.softwarementors.extjs.djn.Timer; 041 import com.yahoo.platform.yui.compressor.JavaScriptCompressor; 042 043 import edu.umd.cs.findbugs.annotations.CheckForNull; 044 import edu.umd.cs.findbugs.annotations.NonNull; 045 046 public class Minifier { 047 048 @NonNull 049 private static final Logger logger = Logger.getLogger( Minifier.class); 050 051 private Minifier() { 052 // Avoid instantation 053 } 054 055 public static String getMinifiedFileName(String file) { 056 assert !StringUtils.isEmpty(file); 057 058 String result = file.replace( ".js", "-min.js" ); 059 return result; 060 } 061 062 @CheckForNull public static final String minify( String input, String inputFilename, int debugCodeLength ) { 063 assert input != null; 064 assert !StringUtils.isEmpty(inputFilename); 065 assert debugCodeLength > 0; 066 067 try { 068 Timer timer = new Timer(); 069 // logger.debug( "Starting minification for '" + inputFilename + "'..."); 070 Reader in = new StringReader( input ); 071 JavaScriptCompressor compressor = new JavaScriptCompressor(in, new ErrorReporter() { 072 public void warning(String message, String sourceName, 073 int line, String lineSource, int lineOffset) { 074 if (line < 0) { 075 logger.warn("Minifier Warning: " + message); 076 } else { 077 logger.warn("Minifier Warning, " + line + ':' + lineOffset + ':' + message); 078 } 079 } 080 081 public void error(String message, String sourceName, 082 int line, String lineSource, int lineOffset) { 083 if (line < 0) { 084 logger.warn("Minifier Error: " + message); 085 } else { 086 logger.warn("Minifier Error, " + line + ':' + lineOffset + ':' + message); 087 } 088 } 089 090 public EvaluatorException runtimeError(String message, String sourceName, 091 int line, String lineSource, int lineOffset) { 092 error(message, sourceName, line, lineSource, lineOffset); 093 return new EvaluatorException(message); 094 } 095 }); 096 097 // Close the input stream first, and then open the output stream, 098 // in case the output file should override the input file. 099 in.close(); 100 101 try { 102 Writer out = new StringWriter(); 103 boolean munge = true; 104 boolean preserveAllSemiColons = false; 105 boolean disableOptimizations = false; 106 boolean verbose = false; 107 int linebreakpos = 0; 108 109 compressor.compress(out, linebreakpos, munge, verbose, 110 preserveAllSemiColons, disableOptimizations); 111 out.close(); 112 String result = out.toString(); 113 if( logger.isDebugEnabled() ) { 114 timer.stop(); 115 int compressionPercentage = 100 - (result.length() * 100 / debugCodeLength); 116 timer.logDebugTimeInMilliseconds( "Finished minification for '" + inputFilename + "'. Debug code length: " + debugCodeLength + ", Minified length: " + result.length() + ", Compression: " + compressionPercentage + "%. Time"); 117 } 118 return result; 119 } 120 catch (UnsupportedEncodingException e) { 121 logger.warn( "Unable to minify '" + inputFilename + "'.", e ); 122 return null; 123 } 124 } 125 catch( IOException e) { 126 logger.warn( "Unable to minify '" + inputFilename + "' due to an IOException.", e ); 127 return null; 128 } 129 catch (EvaluatorException e) { 130 logger.warn( "Unable to minify '" + inputFilename + "' due to a problem with the Javascript evaluator.", e ); 131 return null; 132 } 133 } 134 135 }