Usage

使用 command line 執行 Java jar file:

java -jar compiler.jar --指令

Main

  • --compilation_level :設定 compile 的等級,預設為 SIMPLE_COMPILATIONS

    • SIMPLE_COMPILATIONS: 修改 locale variable
    • ADVANCED_COMPILATIONS

    EX: --compilation_level SIMPLE_COMPILATIONS

  • --js:要進行 compile 的 JavaScript file 路徑;可以使用 * 一次添加複數檔案,或是 !* 排除複數檔案

    EX: --js 'JS1.js' 'JS2.js'--js 'JS1.js' --js 'JS2.js'

  • --js_output_file:匯出的檔案名稱及路徑

    EX: --js_output_file 'compiledJS.js'

  • --externs:引用的 library。設定此參數會排除 JavaScrip file 中外部檔案的 variables。

    • jQuery 必須使用 Google Closure Library 中提供的檔案

      EX: --externs './path/jquery-3.1.js' --externs './path/semantic-ui.js'

Other

  • --formatting:設定匯出檔案的格式

    • PRETTY_PRINT:匯出的檔案斷行

    EX: --formatting PRETTY_PRINT

  • --generate_exports:設定是否識別 /** @export */ 並將註記的 variable 作為 symbol 處理

    EX: --generate_exports

  • --force_inject_library:強制於匯出的 js 檔中加入指定名稱的 library

    EX: --force_inject_library es6_runtime:匯出的 js 檔中加入相容於 es6 的 polyfill library

  • --isolation_mode:將匯出的程式包裹在 function 中 EX:

    //Command 參數:
    //--compilation_level ADVANCED
    //--generate_exports true
    //--isolation_mode IIFE
    
    //Import
    /** @export */
    class Citizen {
        constructor(name) {
            this.name = name;
    	}
        /** @export */
        sayHello(to) {
            let output = this.name + 'say: "Hello! "'+ to.name +'!';
            console.log(output);
        }
    }
    //Export
    //NOTE: 為方便理解, 部分屬性名稱與實際輸出不同
    function() {
        var global = this;
        function a (name) {
            this.name = name || "";
        }
        a.prototype.a = function (a) {
            let output = this.name + 'say: "Hello! "'+ a.name +'!';
            console.log(output);
        }
        a.prototype.sayHello = a.prototype.a;
        global["Citizen"] = a;
    }.call(this);
    

Feature

ADVANCED_OPTIMIZATIONS

  • 修改 local variable

  • 修改 global variable

  • 移除未被使用的 code

  • 將部分 functions/variables 修改為 inline 呼叫的方式:

    // Before
    function hello () {console.log("hello")};
    hello();
    
    // After
    console.log("hello");
    
  • 若要避免 code 被修改,則需做 export 處理

Note

  • name 作為 key 的話,key 不會被修改。

    //Before
    var customer = {name: "John"}
    window["customer"] = customer;
    
    //After
    var a= {name: "John"}
    window["customer"] = a;
    

Export

避免 API 被修改的方法

Solution 1: Export Symbols

Google Closure Compiler 進行編譯時不會修改 String

  • 於作為 Symbol 的變數後在 global scope 以 String 重新宣告 variables:

    var customer = {
        name: "Peter",
        gender: "male",
        hello: function () {console.log("hello " + this.name);}
    }
    
    window["customer"] = customer;
    customer["name"] = customer.name;
    customer["gender"] = customer.gender;
    customer["hello"] = customer.hello;
    
    customer.hello();
    
  • 將變數中屬性的 key 以 String 表示:

    var customer = {
        "name": "Peter",
        "gender": "male",
        "hello": function () {console.log("hello " + this["name"]);}
    }
    
    window["customer"] = customer;
    
    customer["hello"]();
    

Solution 2: /** @export */

增加指令 --generate_exports 並將 Google Closure Library 中的 base.js 設為 --js 'base.js' 'otherJavascript.js'

  • 不支持 objectliteral expression

    /** @export */
    var customer = {
        name: "Peter",
        gender: "male",
        /** @export */ //error: @export only applies to symbols/properties defined in the global scope.
        hello: function () {console.log("hello " + this.name);}
    }
    

    要作為 Symbols 的 properties 必須各別宣告:

    var customer = {}
    /** @export */
    customer.name = "Peter";
    /** @export */
    customer.gender = "male";
    /** @export */
    customer.hello = function () {console.log("hello " + this.name)};
    
    customer.hello();
    
  • ES6 將被編譯為 ES5:

    /** @export */
    class Customer {
      constructor() {
        this.nickName = "Arren";
        /** @export */ //error: @export only applies to symbols/properties defined in the global scope.
        this.gender = "male"
      }
      /** @export */
      hello () {
        console.log("hello" + this.name);
      }
    }
    

Compile 前後比較

  • Solution 1 - 以 String 重新宣告 variables:Before 276 字 | After 164 字

    • 優點:現有 code 需要修改的範圍較小
    • 缺點:每個元件 API 處皆須增加數行 variables 宣告,後續維護麻煩
  • Solution 1 - 屬性的 key 以 String 表示:Before 180 字 | After 129 字

    • 優點:編譯後的字數最少
    • 缺點:現有 API 的使用皆須改為 componentName["PROPERTY_NAME"] 的方式,修改幅度較大
  • Solution 2 - /** @export */Before 198 字 | After 141 + 285 字

    • 285 字為重複使用的部分
    • 優點:後續維護方便,僅需在註記的部分增加 @export 關鍵字
    • 缺點:若 library 為各部分獨立 compile,則每個檔案都會多出 285 字;且現有 literal 寫法必須修改