Note

Usage

使用 command line 執行 Java jar file:

java -jar compiler.jar --指令

Main

  • --compilation_level :設定 compile 的等級,預設為 SIMPLE - SIMPLE: 修改 locale variable - ADVANCED - 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 true
  • --export_local_property_definitions:能夠設定 /** @export */ 於 locale scope

    • EX: --export_local_property_definitions true
  • --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

  • ES6會被 compile 為 ES5

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 Symbols

避免 API 被修改的方法

Solution 1:

  • 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

  • 使用指令 —-generate_exports true--export_local_property_definitions true ; 並將 Google Closure Library 中的 base.js 設為 --js 的第一個檔案
  • 需要保留的屬性/變數添加註記 @export
/** @export */
var customer = {
	name: "Peter",
	gender: "male",
	/** @export */
	hello: function () {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 寫法必須修改