사용자 도구

사이트 도구


javascript:performance:closurecompiler

Google Javascript Closure Compiler

역할

  • 불필요한 코드를 삭제하고, 공백등을 제거하여 용량을 줄여준다.
  • 압축시 에러를 일으킬만한 문법(세미콜론 안 쓴 것등)을 자동 보정해준다.
  • 잘못된 코드에 경고와 에러를 내 주어서 브라우저까지 확인하지 않아도 오류를 알 수 있다. 특히 많이 실수하는 (IE 8 이하에서 안되는) json의 마지막 쉼표 등을 찾아서 오류를 내준다.

문제점

  • float을 키워드로 인식하는 버그가 있다.
    • 이는 ClosureCompiler가 사용하는 Rhino 엔진이 float을 키워드로 지정했기 때문인 것 같다.
    • 웹 브라우저에서는 float을 키워드로 보지 않는다.
    • style.float = xx 갈은 구문이 있다면 style['float'] = xx로 변경해야 한다.
  • outputEncoding 을 명시하지 않으면 한글을 Unicode 기호로 바꾼다(\ucXXX 형태). 이 때문에 한글로 된 문자열이 많으면 파일 크기가 오히려 늘어난다. Ant로 할 경우 outputEncoding 옵션이 지정 안 되는 듯하다. CompilerOptions

설치 사용

  • 실행 자바 클래스 : com.google.javascript.jscomp.CommandLineRunner
  • 기본 사용법
    java -jar compiler.jar --js hello.js --js_output_file hello-compiled.js
  • 도움말
    java -jar compiler.jar --help
    • WHITESPACE_ONLY : 공백과 주석 제거등만 실행
    • SIMPLE_OPTIMIZATIONS : 기본값. 공백제거, 세미콜론 보정등. 가끔 오보정이 일아났다.
    • ADVANCED_OPTIMIZATIONS : 더 강력한 압축. 불필요한 코드 삭제 등.
    • 적용
      java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js hello.js
  • Options
    • --js VAL : 컴파일 대상 파일
    • --js_output_file VAL : 컴파일 결과 파일. 저장하지 않으면 표준출력.
    • --charset VAL : 입출력 캐릭터셋
    • --compilation-level [WHITESPACE_ONLY | SIMPLE_OPTIMIZATIONS | ADVANCED_OPTIMZATIONS] : 컴파일 레벨 지정

Ant 연동

<?xml version="1.0"?>
<project basedir="." default="compile">
 
  <taskdef name="jscomp" classname="com.google.javascript.jscomp.ant.CompileTask"
           classpath="../build/compiler.jar"/>
 
  <target name="compile">
 
    <jscomp compilationLevel="simple" warning="verbose" 
            debug="false" output="output/file.js">
 
      <externs dir="${basedir}/src">
        <file name="extern.js"/>
      </externs>
 
      <sources dir="${basedir}/src">
        <file name="simple1.js"/>
        <file name="simple2.js"/>
      </sources>
 
      <sources dir="${basedir}/other">
        <file name="simple3.js"/>
      </sources>
 
    </jscomp>
 
  </target>
 
</project>

Closure Compiler API

  • JsMinifier.groovy에서 ClosureCompilerAPI 사용법 예제를 볼 수 있다.
  • 혹은 com.google.javascript.jscomp.CommandLineRunner 참조
  • 일괄 Minify 예
    import java.io.*;
    import java.nio.charset.Charset;
    import java.nio.file.*;
    import java.nio.file.attribute.BasicFileAttributes;
    import java.util.ArrayList;
    import java.util.List;
     
    import com.google.javascript.jscomp.*;
    import com.google.javascript.jscomp.Compiler;
     
    public class BatchJsMinify {
        private static final String[] EXCLUDE_PATTERNS = { ".min.js", "-min.js" };
        private static final CompilationLevel DEFAULT_COMPILATION_LEVEL = CompilationLevel.SIMPLE_OPTIMIZATIONS;
     
        private String srcDirName;
        private final File srcDir;
     
        private String destDirName;
        private final File destDir;
     
        private com.google.javascript.jscomp.Compiler compiler = new Compiler();;
        private CompilerOptions options = new CompilerOptions();
        private WarningLevel warningLevel = WarningLevel.QUIET;
     
        public BatchJsMinify(String srcDirName, String destDirName) {
            this.srcDirName = srcDirName;
            this.destDirName = destDirName;
            srcDir = new File(srcDirName);
            destDir = new File(destDirName);
     
            if (!srcDir.exists() || !srcDir.isDirectory()) {
                throw new IllegalArgumentException(srcDirName + " must exist and be a directory.");
            }
     
            destDir.mkdirs();
        }
     
        public void compile() throws IOException {
            options.setCodingConvention(CodingConventions.getDefault());
            options.setOutputCharset("UTF-8");
     
            warningLevel.setOptionsForWarningLevel(options);
            DEFAULT_COMPILATION_LEVEL.setOptionsForCompilationLevel(options);
     
            final List<SourceFile> jsSourceFiles = getSourceFiles();
     
            if (jsSourceFiles == null || jsSourceFiles.size() == 0) {
                System.out.println("Nothing to compile.");
                return;
            }
     
            final List<SourceFile> defaultExterns = CommandLineRunner.getDefaultExterns();
     
            compiler.disableThreads(); // thread가 활성화 돼 있으면 오히려 종료가 늦게 되었다.
            final Result result = compiler.compile(defaultExterns, jsSourceFiles, options);
     
            if (result.success) {
                writeToFile(jsSourceFiles);
            } else {
                printErrors(result);
            }
     
        }
     
        private void printErrors(Result result) {
            for (JSError error : result.errors) {
                System.err.println("Error : " + error.sourceName + ":" + error.lineNumber + " - " + error.description);
            }
        }
     
        private List<SourceFile> getSourceFiles() throws IOException {
            final List<SourceFile> jsSourceFiles = new ArrayList<>();
            Files.walkFileTree(Paths.get(srcDirName), new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                    throws IOException {
                    String filename = file.toString();
     
                    if (filename.endsWith(".js") && !filename.endsWith(".min.js") && !filename.endsWith("-min.js")) {
                    final SourceFile sourceFile = SourceFile.fromFile(file.toFile(), Charset.forName("UTF-8"));
                    jsSourceFiles.add(sourceFile);
                    }
                    return FileVisitResult.CONTINUE;
                    }
                    });
            return jsSourceFiles;
        }
     
        private void writeToFile(List<SourceFile> jsSourceFiles) {
            final String[] minified = compiler.toSourceArray();
     
            for (int i = 0; i < jsSourceFiles.size(); i++) {
                final SourceFile sourceFile = jsSourceFiles.get(i);
                String fileRestPath = sourceFile.getOriginalPath().replace(srcDirName, "");
                final File destFile = new File(destDir, fileRestPath);
                destFile.getParentFile().mkdirs();
     
                System.out.println("Writing minified js file : " + destFile.getAbsolutePath());
     
                try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destFile), "UTF-8"))) {
                    writer.write(minified[i]);
                } catch (IOException e) {
                    throw new IllegalStateException("minified js file save error.", e);
                }
            }
        }
    }
javascript/performance/closurecompiler.txt · 마지막으로 수정됨: 2015/06/18 11:19 저자 kwon37xi