Javascript.RU

Интеграция с Google Closure Library

Update: Более новый материал по этой теме находится по адресу https://learn.javascript.ru/gcc-closure-library.

Google Closure Compiler содержит ряд специальных возможностей для интеграции с Google Closure Library.

Здесь важны две вещи.

  1. Для их использования возможно использовать минимум от Google Closure Library. Это значит - всего несколько лишних строчек кода от всей библиотеки.
  2. Можно расширить компилятор аналогичным образом для интеграции с другими инструментами и фреймворками.

Интеграция подключается флагом --process_closure_primitives, который по умолчанию установлен в true. То есть, она включена по умолчанию.

Этот флаг запускает специальный проход компилятора, описанный классом ProcessClosurePrimitives и подключает дополнительную проверку типов ClosureReverseAbstractInterpreter.

Мы рассмотрим все действия, которые при этом происходят, а также некоторые опции, которые безопасным образом используют символы Google Closure Library без объявления флага.

Следующие действия описаны в классе ProcessClosurePrimitives.

В Google Closure Library есть переменная:

/**
 * @define {boolean} ...
 */
var COMPILED = false;

Проход ProcessClosurePrimitives переопределяет ее в true и использует это при оптимизациях, удаляя ветки кода, не предназначены для запуска на production.

Такие функции существуют, например, в ядре Google Closure Library. К ним в первую очередь относятся вызовы, предназначенные для сборки и проверки зависимостей. Они содержат код, обрамленный проверкой COMPILED, например:

goog.require = function(rule) {
   // ...
  if (!COMPILED) {
     // основное тело функции
  }
}

Аналогично может поступить и любой скрипт, даже без использования Google Closure Library:

Пример: my.js
/** @define {boolean} */
var COMPILED = false

Framework = { }

Framework.sayCompiled = function() {
	if (!COMPILED) {
		alert("Not compressed")
	} else {
		alert("Compressed")
	}
}

После компиляции в продвинутом режиме:

Framework = {};
Framework.sayCompiled = Framework.a = function() {
  alert("Compressed")
};

Компилятор переопределил COMPILED в true и произвел соответствующие оптимизации.

В Google Closure Compiler есть внутренняя опция locale

Эта опция переопределяет переменную goog.LOCALE на установленную при компиляции.

Для использования опции locale, на момент написания статьи, ее нужно задать в Java коде компилятора, т.к. соответствующего флага нет.

Как и COMPILED, константу goog.LOCALE можно и использовать в своем коде без библиотеки Google Closure Library.

Директивы goog.provide, goog.require, goog.addDependency обрабатываются особым образом.

Все зависимости проверяются, а сами директивы проверки - удаляются из сжатого файла.

Экспорты, заданные при помощи goog.exportSymbol, записываются во вспомогательный список, чтобы избежать перезаписи.
Если подробнее, то код goog.exportSymbol('a',myVar) защитит символ a от перезаписи: никакая другая переменная не будет переименована в a.

Google Closure Library умеет преобразовывать классы CSS на более короткие по заданному списку.
Например, следующая функция задает такой список.

goog.setCssNameMapping({
   "goog-menu": "a",
   "goog-menu-disabled": "a-b",
   "CSS_LOGO": "b",
   "hidden": "c"
});

Тогда следующий вызов преобразуется в "a a-b":

goog.getCssName('goog-menu') + ' ' + goog.getCssName('goog-menu', 'disabled')

Google Closure Compiler производит соответствующие преобразования в сжатом файле и удаляет вызов setCssNameMapping из кода.

На мой взгляд, это делается больше из соображений обфускации, нежели оптимизации.

При объявлении внутренней опции externExportsPath, содержащей путь к файлу, в этот файл будут записаны все экспорты, описанные через goog.exportSymbol/goog.exportProperty.

В дальнейшем этот файл может быть использован как список экстернов для компиляции.

Эта опция может быть полезна для создания внешних библиотек, распространяемых со списком экстернов.

Соответствующий проход компилятора описан в классе ExternExportsPass.

В Google Closure Library есть ряд функций для проверки типов. Например: goog.isArray, goog.isString, goog.isNumber, goog.isDef и т.п.

Компилятор использует их для проверки типов.

Например:

function removeNode(id) {
	var node
	if (goog.isNumber(id)) {
		node = document.getElementById(id) // (!)
	}
	node.parentNode.removeChild(node)
}
document.onclick = function() { removeNode(123) }

При компиляции с опцией --check_types такой код приведет к предупреждению:

file.js:4: WARNING - actual parameter 1 of Document.prototype.getElementById does not match formal parameter
found   : number
required: string
                node = document.getElementById(id)

Компилятор увидел вызов goog.isNumber и вывел из этого тип переменной number внутри блока if.

Функция getElementById описана во внутреннем списке стандартных экстернов и принимает строку, а ей передали число id. Поэтому компилятор генерирует предупреждение.

В реальных скриптах обычно используются строковые префиксы, поэтому будет код такого вида:

...
if (goog.isNumber(id)) {
	id = 'node-'+id   // (ok)
	node = document.getElementById(id)
}
...

При этом компилятор, увидев присвоение id='node'+id, обновит тип id в string и никакого предупреждения сгенерировано не будет. Если, конечно, вы используете id там, где допустим именно тип string.

Эта логика описана в классе ClosureReverseAbstractInterpreter.

Названия функций, определяющих типы, жестко прописаны в Java-коде, поменять их на свои без модификации исходников нельзя.

Для этого в Google Closure Compiler есть внутренняя опция generateExports.

Эта недокументированная опция добавляет проход компилятора, описанный классом GenerateExports.

Он читает аннотации @export и создает из них экспортирующие вызовы goog.exportSymbol/exportProperty. Название экспортирующих функций находится в классе соглашений кодирования, каким по умолчанию является GoogleCodingConvention.

Например:

/** @export */
function Widget() {
}
/** @export */
Widget.prototype.hide = function() {
  this.elem.style.display = 'none'
}

После компиляции с продвинутом режиме:

function a() {
}
goog.d("Widget", a);
a.prototype.a = function() {
  this.b.style.display = "none"
};
goog.c(a.prototype, "hide", a.prototype.a);

Свойства благополучно экспортированы. Удобно.

Google Closure Compiler содержит дополнительные фичи, облегчающие интеграцию с Google Closure Library. Некоторые из них весьма полезны.

При этом никто не заставляет вас использовать библиотеку Google целиком - интеграция завязана лишь на конкретные описанные возможности библиотеки.

При обработке символов компилятор не смотрит, подключена ли библиотека, он находит обрабатывает их просто по именам. Поэтому вы можете использовать свою реализацию соответствующих функций, или самостоятельно объявить символ, как в примере с COMPILED.

Для использования некоторых внутренних опций, их необходимо определить внутри компилятора. Различные опции описаны в статьях раздела Google Closure Compiler в деталях.


Автор: attandyVosy (не зарегистрирован), дата: 5 февраля, 2011 - 03:41
#permalink

спасибо за интересную информацию


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
1 + 10 =
Введите результат. Например, для 1+3, введите 4.
 
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние комментарии
Последние темы на форуме
Forum