Javascript.RU

Система сборки и зависимостей Google Closure Library

В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.

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

Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.

В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.

Символ - это имя javascript-объекта, который тут же можно использовать. Например:

goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }

Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:

my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}

Так что существующие объекты и свойства не перезаписываются.

При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.

Например:

goog.provide('goog.Delay');
goog.provide('goog.async.Delay');

goog.require('goog.Disposable');
goog.require('goog.Timer');

Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.

Для добавления информации о зависимостях используется функция goog.addDependency.

Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).

Например:

goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);

Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.

После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.

C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.

Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.

Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).

Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.

Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.

Эта утилита получает три основные опции:

-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода

Например:

calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script

В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.

Скрипт calcdeps.py делает следующие простые шаги:

  1. Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
  2. Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
  3. В зависимости от типа вывода:
    deps
    Выводит набор директив goog.addDependency.
    В нашем случае это будет длинная простыня:
// This file was autogenerated by calcdeps.py
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
// ...

Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.

Свой deps.js в Closure Library

Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:

// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true

(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег <script>, либо формировать список зависимостей goog.addDependency каким-либо другим путем.

list
выводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js

Других файлов для сборки не нужно.

script
собирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
// Input 0
содержание файла closure-library/closure/goog/base.js

// Input 1
содержание файла main.js

// Input 2 
содержание файла hello.js
compiled
Компилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.

Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:

calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"

Кавычки для передачи флагов компилятора должны быть двойными.

Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.

С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.

Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.

Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.

У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.

Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.

Исходный вариант:

goog.require = function(rule) {

  // if the object already exists we do not need do do anything
  // TODO: ...
  if (!COMPILED) {
    // если объект уже есть - возврат
    if (goog.getObjectByName(rule)) {
      return;
    }
    // получить путь к файлу с символом rule 
    var path = goog.getPathFromDeps_(rule);
    if (path) {
      // _writeScripts пишет <script> только 1 раз для каждого файла
      goog.included_[path] = true;
      goog.writeScripts_();
    } else {
      // файл не нашли
      var errorMessage = 'goog.require could not find: ' + rule;
      if (goog.global.console) {
        goog.global.console['error'](errorMessage);
      }

        throw Error(errorMessage);
    }
  }
};

Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.

А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:

goog.namespacePrefixes = {
  'my': '/js/my'
}

Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.

Вот версия goog.require с соответствующими модификациями:

goog.require = function(rule) {
  if (!COMPILED) {
    if (goog.getObjectByName(rule)) {
      return;
    }
    var path = goog.getPathFromDeps_(rule);
    if (path) {
      goog.included_[path] = true;
    } else {
      path = rule.replace(/\./g,'/')+'.js'
      for(var prefix in goog.namespacePrefixes) {
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
      }
      goog.included_[path] = true;
      setTimeout(function() {
        if (goog.getObjectByName(rule)) {
          return
        }
        var errorMessage = 'goog.require could not find: ' + rule;
        if (goog.global.console) {
          goog.global.console['error'](errorMessage);
        }
        throw Error(errorMessage);
      }, 0)
    }
    goog.writeScripts_();
    
  }
};

В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.

Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.

После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.

Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?

При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.

Для удобства примеры в этой статье собраны в архив gbuild.zip.

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

Содержимое:

goog 
  директория с base.js из Google Closure Library
my
  директория с нашими js-файлами, base_require.js содержит модифицированный require 
calcdeps.py
  стандартный calcdeps.py из Google Closure Library
compiler.jar
  стандартный Google Closure Compiler
compile.bat
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
hello.html
  файл-пример, использующий hello.js

Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:44
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:45
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:46
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:47
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:47
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:48
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:49
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:49
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:50
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:51
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:52
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:52
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:53
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:53
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:54
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:55
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:55
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:56
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:56
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:57
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:57
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:58
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:59
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 15:59
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:00
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:00
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:01
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:02
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:02
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:03
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:04
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:04
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:05
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:06
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:07
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:07
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:07
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:07
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:07
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:07
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:08
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:09
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:09
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:09
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:09
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:09
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:09
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:10
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:11
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:11
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:12
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 28 февраля, 2014 - 16:12
#permalink

Россия заняла 3 место в рейтинге стран-спамеров
Специалисты компании Symantec опубликовали отчет об интенсивности рассылки спама в мире за январь текущего года. Во включенные в данный отчет рейтинг стран, из которых активнее всего осуществляется рассылка спама вошла и Россия - наша страна заняла в нем «почетное» третье место с показателем 6,4% в общей доле мирового спама.
Самой «спамерской» страной в январе по версии специалистов Symantec стала Канада - на ее долю пришлось 7,7% мирового спама, а второе место с показателем 6,8% заняла Испания. При этом общая доля спама в мировом почтовом трафике по итогам первого месяца текущего года составила 62,1% - это на 1,9% меньше прошлогоднего декабрьского показателя.


Автор: Гость (не зарегистрирован), дата: 1 марта, 2014 - 11:08
#permalink

2221112222211112121212133333333333


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:16
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:18
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:18
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:18
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:19
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:19
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:19
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:19
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:19
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:19
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: guest (не зарегистрирован), дата: 2 марта, 2014 - 12:19
#permalink

Система сборки и зависимостей Google Closure Library
1.goog.provide
2.goog.require
3.Структура зависимостей
4.Система сборки и генерации зависимостей
5.Автоматический подхват зависимостей
6.Пример использования модифицированной системы сборки
В этой статье мы рассмотрим систему сборки и зависимостей Google Closure Library.
А также увидим, как применить ее к своему коду, даже если вместо Google Closure Library используется совсем другой фреймворк.
Система зависимостей Google Closure Library имеет два основных декларативных метода: goog.provide и goog.require.
goog.provide
В javascript-файлах при помощи goog.provide указывается, какие символы предоставляет этот файл.
Символ - это имя javascript-объекта, который тут же можно использовать. Например:
goog.provide('my.super.dom')
my.super.dom.createElement = function() { ... }
Как видите, здесь мы декларируем, что файл объявляет символ my.super.dom, и goog.provide тут же создает пустой объект, используя для этого код, наподобие следующего:
my = window.my || {}
my.super = my.super || {}
my.super.dom = my.super.dom || {}
Так что существующие объекты и свойства не перезаписываются.
goog.require
При помощи goog.require указывается, какие символы нужны. Указывать require принято после provide для лучшей читабельности кода.
Например:
1
goog.provide('goog.Delay');
2
goog.provide('goog.async.Delay');
3

4
goog.require('goog.Disposable');
5
goog.require('goog.Timer');
Структура зависимостей
Функция goog.require лишь декларирует требование объекта и проверяет его. Она также может подгрузить нужный файл, но только если найдет его во внутренней структуре зависимостей.
Для добавления информации о зависимостях используется функция goog.addDependency.
Эта функция для каждого файла перечисляет список символов, которые он дает (provide) и которые требует (require).
Например:
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
Этот вызов добавляет в структуру зависимостей информацию, что файл bye.js предоставляет символ my.bye и требует my.main.
После такого вызова можно смело использовать goog.require('my.bye') - библиотека подгрузит файл /tmp/my/bye.js.
C другой стороны, если информация не была добавлена при помощи goog.addDependency - вызов goog.require('my.bye') завершится с ошибкой.
Для символов, объявленных в Google Closure Library, зависимости хранятся в корневой директории библиотеки, в файле deps.js.
Для ваших собственных символов и файлов вы должны либо прописать зависимости goog.addDependency самостоятельно, либо использовать для этого скрипт calcdeps.py (см. далее).
Система сборки и генерации зависимостей
Для автоматической сборки и генерации файла зависимостей из ваших модулей используется скрипт calcdeps.py, поставляемый вместе с библиотекой.
Для его запуска под Windows можно использовать ActivePython, под Linux/MacOS - обычный python.
Эта утилита получает три основные опции:
-i file.js
входной javascript-файл, можно указать несколько
-p path/to/dir
список путей
-o script/deps/list/compiled
тип вывода
Например:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o script
В нашем примере /tmp/my - место, где хранятся файлы main.js, bye.js, hello.js, а /tmp/gc/closure-library - каталог с google closure library, которая взята из SVN.
Скрипт calcdeps.py делает следующие простые шаги:
1.Рекурсивно проходит по всем директориям из списка -p, находит все файлы с расширением .js
2.Для каждого файла - регулярными выражениями выцепляет списки, что ему надо (goog.require) и что он дает (goog.provide).
3.В зависимости от типа вывода:
deps
Выводит набор директив goog.addDependency.
В нашем случае это будет длинная простыня:
1
// This file was autogenerated by calcdeps.py
2
goog.addDependency('/tmp/my/bye.js', ['my.bye'], ['my.main']);
3
goog.addDependency('/tmp/my/hello.js', ['my.hello'], ['my.main']);
4
goog.addDependency('/tmp/my/main.js', ['my.main'], []);
5
goog.addDependency('/tmp/gc/closure-library/alltests.js', [], []);
6
goog.addDependency('/tmp/gc/closure-library/closure/goog/base.js', [], []);
7
goog.addDependency('/tmp/gc/closure-library/closure/goog/deps.js', [], []);
8
goog.addDependency('/tmp/gc/closure-library/closure/goog/array/array.js', ['goog.array'], []);
9
// ...
Первые несколько зависимостей взяты из файлов bye.js, main.js, hello.js, а остальные - построены из файлов Google Closure Library.
Свой deps.js в Closure Library
Если вы используете Google Closure Library, то можете загружать новый файл в качестве deps.js вместо стандартного.
Для этого нужно установить флаг:
// до загрузки base.js
goog.global.CLOSURE_NO_DEPS=true
(base.js перестанет подгружать стандартный deps.js) и загружать deps.js через отдельный тег , либо формировать список зависимостей goog.addDependency каким-либо другим путем.
listвыводит список нужных файлов в порядке зависимостей.
В нашем случае:
/tmp/gc/closure-library/closure/goog/base.js
/tmp/my/main.js
hello.js
Других файлов для сборки не нужно.
scriptсобирает все входные файлы (-i) и требуемые для них в один файл.
В нашем случае это будет javascript-файл следующего вида:
1
// Input 0
2
содержание файла closure-library/closure/goog/base.js
3

4
// Input 1
5
содержание файла main.js
6

7
// Input 2
8
содержание файла hello.js
compiledКомпилирует файл, полученный в результате сборки. При использовании этой опции обязательно указание флага --compiler_jar с путем до jar-файла с компилятором.
Кроме того, как правило, указываются и флаги компиляции. Чтобы вывести откомпилированный файл в o.js, вызовем calcdeps.py вот так:
calcdeps.py -i hello.js -p /tmp/my -p /tmp/gc/closure-library -o compiled \
--compiler_jar compiler.jar --compiler_flags "--js_output_file o.js"
Кавычки для передачи флагов компилятора должны быть двойными.
Обратите внимание - в результате компиляции не будет директив goog.provide/require. Это потому, что компилятор использует специальный проход для проверки зависимостей и удаления этих директив из итогового файла.
С другой стороны, после компиляции с обычным уровнем оптимизации в файле остается много лишнего. Если добавить экспорт какой-нибудь функции и указать флаг "--js_output_file o.js --compilation_level ADVANCED_OPTIMIZATIONS", то почти вся base.js исчезнет. Таким образом, overhead от использования системы сборки google будет сведен к минимуму.
Вообще, никто не заставляет использовать Google Closure Library. Для использования системы зависимости хватит base.js.
Так как calcdeps.py основан на регэкспах, условные директивы provide/require не поддерживаются. Утилита выхватит из файла все provide/require без разбора блока и местоположения в файле.
Автоматический подхват зависимостей
У функции goog.require есть один недостаток. Если встроенные зависимости Google Closure Library она загружает автоматически, то для собственных символов такой возможности не предусмотрено: нужно для каждого символа/файла прописывать goog.addDependency.
Чтобы упростить процесс, мы немного расширим goog.require, добавив автоматический подхват символов.
Исходный вариант:
01
goog.require = function(rule) {
02

03
  // if the object already exists we do not need do do anything
04
  // TODO: ...
05
  if (!COMPILED) {
06
    // если объект уже есть - возврат
07
    if (goog.getObjectByName(rule)) {
08
      return;
09
    }
10
    // получить путь к файлу с символом rule
11
    var path = goog.getPathFromDeps_(rule);
12
    if (path) {
13
      // _writeScripts пишет только 1 раз для каждого файла
14
      goog.included_[path] = true;
15
      goog.writeScripts_();
16
    } else {
17
      // файл не нашли
18
      var errorMessage = 'goog.require could not find: ' + rule;
19
      if (goog.global.console) {
20
        goog.global.console['error'](errorMessage);
21
      }
22

23
        throw Error(errorMessage);
24
    }
25
  }
26
};
Введем правило - символ a.b.c находится в файле a/b/c.js, и модифицируем функцию goog.require, чтобы она при отсутствии зависимости в списке загружала файл по этому правилу.
А чтобы было еще удобнее - добавим префиксы, которые будут указывать путь к каждому пространству имен. Например:
goog.namespacePrefixes = {
  'my': '/js/my'
}
Это будет означать, что goog.require('my.file') загрузит символ из /js/my/file.js.
Вот версия goog.require с соответствующими модификациями:
01
goog.require = function(rule) {
02
  if (!COMPILED) {
03
    if (goog.getObjectByName(rule)) {
04
      return;
05
    }
06
    var path = goog.getPathFromDeps_(rule);
07
    if (path) {
08
      goog.included_[path] = true;
09
    } else {
10
      path = rule.replace(/\./g,'/')+'.js'
11
      for(var prefix in goog.namespacePrefixes) {
12
       path = path.replace(new RegExp("^"+prefix), goog.namespacePrefixes[prefix])
13
      }
14
      goog.included_[path] = true;
15
      setTimeout(function() {
16
        if (goog.getObjectByName(rule)) {
17
          return
18
        }
19
        var errorMessage = 'goog.require could not find: ' + rule;
20
        if (goog.global.console) {
21
          goog.global.console['error'](errorMessage);
22
        }
23
        throw Error(errorMessage);
24
      }, 0)
25
    }
26
    goog.writeScripts_();
27

28
  }
29
};
В функции выше также оставлен контроль ошибок. В отличие от простого require, мы можем узнать, появился ли символ, только после загрузки файла, поэтому проверка обернута в setTimeout(..., 0). Такой вызов сработает сразу после синхронной загрузки script.
Вы можете пропатчить base.js или, что гораздо лучше, загрузить свой файл с новым require и префиксами, который перезапишет определение в base.js.
После этого goog.require начнет подгружать зависимости аналогично системе зависимостей в dojo toolkit и других фреймворках.
Можно расширить эту функциональность, добавить подгрузку вида goog.require('my.*'), более сложную логику нахождения файла по символу и т.п., но нужно ли?
При сборке нескольких модулей Google Closure Compiler проверяет зависимости require/provide, но при этом многомодульные сборки можно делать и без них, как описано в соответствующей статье.
Пример использования модифицированной системы сборки
Для удобства примеры в этой статье собраны в архив gbuild.zip.
Он содержит модифицированный require и иллюстрирует, как использовать систему сборки Google, даже если вы не используете Google Closure Library.
Содержимое:
01
goog
02
  директория с base.js из Google Closure Library
03
my
04
  директория с нашими js-файлами, base_require.js содержит модифицированный require
05
calcdeps.py
06
  стандартный calcdeps.py из Google Closure Library
07
compiler.jar
08
  стандартный Google Closure Compiler
09
compile.bat
10
   файл для компиляции hello.js с ADVANCED оптимизациями и зависимостями
11
hello.html
12
  файл-пример, использующий hello.js


Автор: Гость (не зарегистрирован), дата: 3 марта, 2014 - 08:13
#permalink

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA


Автор: Гостlfgdkь (не зарегистрирован), дата: 8 мая, 2014 - 11:52
#permalink

dsfs ss


Автор: Гость (не зарегистрирован), дата: 2 июля, 2014 - 23:06
#permalink

alert('!')


Автор: 228Pacan282 (не зарегистрирован), дата: 22 августа, 2014 - 21:12
#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
Антиспам
4 + 13 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Реклама
Содержание

Учебник javascript

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

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

Интерфейсы

Все об AJAX

Оптимизация

Разное

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

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