使用 Closure Compiler Service API 壓縮檔案

Closure 編譯器服務已遭淘汰,日後將予以移除。請考慮在本機執行編譯器。

總覽

與 API 通訊說明瞭與 Closure Compiler 服務通訊的基本概念,但這個 API 只透過服務從一行 JavaScript 中去除註解。本教學課程說明如何在合理的情境中,使用 Closure Comppiler 服務:處理整個 JavaScript 檔案以大幅縮減大小。

本教學課程假設您對 JavaScript 和 HTTP 有基本的瞭解。雖然它使用 Python 指令碼將 JavaScript 提交到 Closure Compiler 服務,但您不必知道 Python 就能按照範例操作。

  1. 壓縮檔案
  2. 改善壓縮
    1. 程式碼有多小?
    2. 封閉式編譯器服務如何讓這個程式更小?
  3. 後續步驟

壓縮檔案

與 API 通訊中的範例會將 JavaScript 字串做為指令列參數傳遞給我們的編譯指令碼。不過,對實際大小的 JavaScript 程式而言,這個方法並不太有效,因為當程式碼長度超過幾行時,JavaScript 字串可能會很快就變得不理想。如果是大型程式,您可以使用 code_url 要求參數指定要處理的 JavaScript 檔案名稱。除了 js_code 以外,您也可以使用 code_url,或替換 js_code

以下列 JavaScript 程式為例:

/**
 * A simple script for adding a list of notes to a page. The list diplays
 * the text of each note under its title.
 */

/**
 * Creates the DOM structure for a note and adds it to the document.
 */
function makeNoteDom(noteTitle, noteContent, noteContainer) {
  // Create DOM structure to represent the note.
  var headerElement = document.createElement('div');
  var headerText = document.createTextNode(noteTitle);
  headerElement.appendChild(headerText);

  var contentElement = document.createElement('div');
  var contentText = document.createTextNode(noteContent);
  contentElement.appendChild(contentText);

  var newNote = document.createElement('div');
  newNote.appendChild(headerElement);
  newNote.appendChild(contentElement);

  // Add the note's DOM structure to the document.
  noteContainer.appendChild(newNote);
}

/**
 * Iterates over a list of note data objects and creates a DOM
 */
function makeNotes(data, noteContainer) {
  for (var i = 0; i < data.length; i++) {
    makeNoteDom(data[i].title, data[i].content, noteContainer);
  }
}

function main() {
  var noteData = [
      {title: 'Note 1', content: 'Content of Note 1'},
      {title: 'Note 2', content: 'Content of Note 2'}];
  var noteListElement = document.getElementById('notes');
  makeNotes(noteData, noteListElement);
}

main();

您可以將這個程式做為檔案,直接作為 Closure Compiler 服務傳送,作為一個大型字串。請按照下列步驟使用服務處理檔案:

  1. 將 JavaScript 儲存成檔案。
  2. 在網路上存取檔案 (例如將檔案上傳至您的網路伺服器)。
  3. 向 Closure Compiler 服務發出 POST 要求,如與 API 通訊中所述,但 js_code 參數會取代 code_url 參數。code_url 的值必須是您在步驟 1 建立的 JavaScript 檔案網址。

例如,您可以在 tutorial2.js 檔案中找到這個範例的 JavaScript。如要使用 Closure Compiler 服務 API 處理這個檔案,請將 Python 程式從與 API 通訊改為使用 code_url,如下所示:

#!/usr/bin/python2.4

import httplib, urllib, sys

# Define the parameters for the POST request and encode them in
# a URL-safe format.

params = urllib.urlencode([
    ('code_url', sys.argv[1]), # <--- This parameter has a new name!
    ('compilation_level', 'WHITESPACE_ONLY'),
    ('output_format', 'text'),
    ('output_info', 'compiled_code'),
  ])

# Always use the following value for the Content-type header.
headers = { "Content-type": "application/x-www-form-urlencoded" }
conn = httplib.HTTPSConnection('closure-compiler.appspot.com')
conn.request('POST', '/compile', params, headers)
response = conn.getresponse()
data = response.read()
print data
conn.close()

注意:如要重現這個範例,Windows 使用者可能需要安裝 Python。請參閱 Python Windows 常見問題,瞭解如何在 Windows 中安裝及使用 Python。

使用下列指令將程式碼傳送至 Closure Compiler 服務:

$ python compile.py https://closure-compiler.appspot.com/closure/compiler/samples/tutorial2.js

Closure Compiler 服務會從 https://closure-compiler.appspot.com/closure/compiler/samples/tutorial2.js 擷取檔案,並在回應中傳回壓縮的 JavaScript。

如要將多個輸出檔案編譯成一個輸出檔案,請加入多個 code_url 參數,如以下範例所示:

params = urllib.urlencode([
    # Multiple code_url parameters:
    ('code_url', 'http://yourserver.com/yourJsPart1.js'),
    ('code_url', 'http://yourserver.com/yourJsPart2.js'),
    ('compilation_level', 'WHITESPACE_ONLY'),
    ('output_format', 'text'),
    ('output_info', 'compiled_code'),
  ])

改善壓縮

到目前為止,範例都使用了 WHITESPACE_ONLYcompilation_level,而這僅會移除註解和空白字元。使用 SIMPLE_OPTIMIZATIONS 壓縮等級時,您可以提高壓縮率。如要使用 SIMPLE_OPTIMIZATIONS 壓縮,請將 compilation_level 參數變更為 SIMPLE_OPTIMIZATIONS

params = urllib.urlencode([
    ('code_url', sys.argv[1]),
    ('compilation_level', 'SIMPLE_OPTIMIZATIONS'),  # <--- This parameter has a new value!
    ('output_format', 'text'),
    ('output_info', 'compiled_code'),
  ])

然後依以下方式執行指令碼:

$ python compile.py https://closure-compiler.appspot.com/closure/compiler/samples/tutorial2.js

輸出內容應如下所示:

var GLOBAL_document=document,$$PROP_appendChild="appendChild";function makeNoteDom(a,b,c){var d=GLOBAL_document.createElement("div");a=GLOBAL_document.createTextNode(a);d[$$PROP_appendChild](a);a=GLOBAL_document.createElement("div");b=GLOBAL_document.createTextNode(b);a[$$PROP_appendChild](b);b=GLOBAL_document.createElement("div");b[$$PROP_appendChild](d);b[$$PROP_appendChild](a);c[$$PROP_appendChild](b)}function makeNotes(a,b){for(var c=0;c<a.length;c++)makeNoteDom(a[c].title,a[c].content,b)}
function main(){var a=[{title:"Note 1",content:"Content of Note 1"},{title:"Note 2",content:"Content of Note 2"}],b=GLOBAL_document.getElementById("notes");makeNotes(a,b)}main();

這個程式碼比來源程式更難以讀取,但比較小。

程式碼有多小?

如果我們將要求參數中的 output_infocompiled_code 變更為 statistics,就可以看到確切的儲存空間:

Original Size: 1372
Compressed Size: 677
Compilation Time: 0

新版 JavaScript 只有原始圖片的一半。

封閉式編譯器服務如何讓這個程式更小?

在此情況下,Closure Compiler 可以藉由重新命名本機變數而縮減大小。例如,原始檔案包含以下這行程式碼:

var headerElement = document.createElement('div');

Closure Compiler 將此陳述式更改為:

var d=document.createElement("div");

Closure Compiler 會將 headerElement 符號改成 d 函式 makeNoteDom 內的任何位置,因此可以保留功能。但 headerElement 的 13 個字元已縮短為顯示三個位置的每一個字元。因此總共可省下 36 個字元。

使用 SIMPLE_OPTIMIZATIONS 進行編譯一律會保留語法有效 JavaScript 的功能,前提是程式碼不會使用字串名稱存取本機變數 (例如,eval() 陳述式)。

後續步驟

現在,您已熟悉 SIMPLE_OPTIMIZATIONS 和使用服務的基本機制,下一步就是瞭解 ADVANCED_OPTIMIZATIONS 編譯層級。這個層級需要額外步驟,才能確保您的 JavaScript 在編譯前後能夠以相同方式運作,但是會讓 JavaScript 縮小。如要瞭解 ADVANCED_OPTIMIZATIONS,請參閱進階編譯與外部