Spec-Zone.ru › RequireJS

Плагины

  • Вступление
  • Имена плагинов
  • API
    • load
    • normalize
    • write
    • onLayerEnd
    • writeFile
    • pluginBuilder

Вступление

RequireJS позволяет вам создавать плагины загрузчика, которые могут загружать различные типы ресурсов в качестве зависимостей и даже включать зависимости в оптимизированные сборки.

Примеры существующих плагинов загрузчика — плагины text! и i18n!. Плагин text! обрабатывает загрузку текста, а плагин i18n — загрузку JavaScript-объекта, состоящего из объектов из нескольких разных модулей. Объект содержит локализованные строки.

На странице wiki RequireJS есть более подробный список плагинов.

Имена плагинов

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

Примечание: плагин и его зависимости должны работать в средах, не являющихся браузерами, таких как Node и Nashorn. Если это невозможно, вы должны использовать альтернативный модуль строителя плагинов, который может работать в этих средах, чтобы они могли участвовать в оптимизированных сборках.

Вы можете сослаться на свой плагин, поместив его имя модуля перед ! в зависимости. Например, если вы создали плагин с именем «foo.js», вы будете использовать его следующим образом:

require(['foo!something/for/foo'], function (something) {
    //something is a reference to the resource
    //'something/for/foo' that was loaded by foo.js.
});

Таким образом, имя модуля плагина предшествует разделителю !. Часть после разделителя ! называется именем ресурса. Имя ресурса может выглядеть как обычное имя модуля. Имя модуля плагина может быть любым допустимым именем модуля, поэтому, например, вы можете использовать относительный указатель:

require(['./foo!something/for/foo'], function (something) {
});

Или, если он находился внутри пакета или каталога, скажем, bar/foo.js:

require(['bar/foo!something/for/foo'], function (something) {
});

API

RequireJS сначала загрузит модуль плагина, а затем передаст остальную часть имени зависимости в метод load() плагина. Также существуют некоторые методы для нормализации имен модулей и использования плагина в рамках оптимизатора.

Полный API плагина:

  • load: функция, вызываемая для загрузки ресурса. Это единственный обязательный метод API, который необходимо реализовать для полезности плагина.
  • normalize: функция для нормализации имени ресурса. Это полезно для обеспечения оптимального кеширования и оптимизации, но необходимо только в том случае, если имя ресурса не является именем модуля.
  • write: используется оптимизатором для указания момента, когда плагин должен записать представление ресурса в оптимизированный файл.
  • pluginBuilder: строка имени модуля для модуля, который должен использоваться в оптимизаторе для выполнения работы по оптимизации. Этот модуль используется вместо модуля плагина при запуске оптимизатора.

load: function (name, parentRequire, onload, config)

load — это функция, и она будет вызвана со следующими аргументами:

  • name: Строка. Имя ресурса для загрузки. Это часть после разделителя ! в имени. Таким образом, если модуль запрашивает «foo!something/for/foo», функция load модуля foo получит «something/for/foo» в качестве имени.
  • parentRequire: Функция. Локальная функция «require» для использования при загрузке других модулей. Эта функция будет разрешать относительные имена модулей относительно имени модуля, запросившего этот ресурс плагина. Если плагин загрузчика хочет require() что-то относительно своего собственного идентификатора, он может запросить require в собственном вызове define. У этой функции require есть некоторые утилиты:
    • parentRequire.toUrl(moduleResource): где moduleResource — имя модуля плюс расширение. Например, «view/templates/main.html». Он вернет полный путь к ресурсу, соблюдая все настройки RequireJS.
    • parentRequire.defined(moduleName): Возвращает true, если модуль уже загружен и определен. Раньше назывался require.isDefined до RequireJS 0.25.0.
    • parentRequire.specified(moduleName): Возвращает true, если модуль уже запрошен или находится в процессе загрузки и должен быть доступен в какой-то момент.
  • onload: Функция. Функция, вызываемая со значением для name. Это сообщает загрузчику, что плагин завершил загрузку ресурса. onload.error() можно вызвать, передав в него объект ошибки, если плагин обнаруживает ошибку, которая означает, что ресурс не будет загружен правильно.
  • config: Объект. Объект конфигурации. Это способ для оптимизатора и веб-приложения передать информацию о конфигурации плагину. Плагин i18n! использует это для получения текущего языка, если веб-приложение хочет принудительно установить определенный язык. Оптимизатор установит свойство isBuild в config в true, если этот плагин (или pluginBuilder) вызывается в рамках сборки оптимизатора.

Пример плагина, который ничего интересного не делает, просто выполняет обычный require для загрузки JS-модуля:

define({
    load: function (name, req, onload, config) {
        //req has the same API as require().
        req([name], function (value) {
            onload(value);
        });
    }
});

Некоторым плагинам может потребоваться оценить JavaScript, который был получен в виде текста, и использовать эту оцененную JavaScript в качестве значения для ресурса. В аргументе onload() есть функция onload.fromText(), которую можно использовать для оценки JavaScript. eval() используется RequireJS для оценки этой JavaScript, и RequireJS выполнит необходимую работу для любого анонимного вызова define() в оцененном тексте и использует этот модуль define() в качестве значения ресурса.

Аргументы для onload.fromText() (RequireJS 2.1.0 и более поздние версии):

  • text: Строка. Строка JavaScript для оценки.

Пример функции загрузки плагина, использующей onload.fromText():

define({
    load: function (name, req, onload, config) {
        var url = req.toUrl(name + '.customFileExtension'),
            text;

        //Use a method to load the text (provided elsewhere)
        //by the plugin
        fetchText(url, function (text) {
            //Transform the text as appropriate for
            //the plugin by using a transform()
            //method provided elsewhere in the plugin.
            text = transform(text);

            //Have RequireJS execute the JavaScript within
            //the correct environment/context, and trigger the load
            //call for this resource.
            onload.fromText(text);
        });
    }
});

До RequireJS 2.1.0 onload.fromText принимала имя модуля в качестве первого аргумента: onload.fromText(moduleName, text), и плагин загрузчика должен был вручную вызвать require([moduleName], onload) после вызова onload.fromText().

Учет особенностей сборки: оптимизатор отслеживает зависимости синхронно для упрощения логики оптимизации. Это отличается от работы require.js в браузере, и это означает, что только плагины, которые могут удовлетворить свои зависимости синхронно, должны участвовать в этапах оптимизации, позволяющих встраивать значения плагина загрузчика. В противном случае плагин должен просто немедленно вызвать load(), если config.isBuild равно true:

define({
    load: function (name, req, onload, config) {
        if (config.isBuild) {
            //Indicate that the optimizer should not wait
            //for this resource any more and complete optimization.
            //This resource will be resolved dynamically during
            //run time in the web browser.
            onload();
        } else {
            //Do something else that can be async.
        }
    }
});

Некоторые плагины могут выполнять асинхронную операцию в браузере, но выбирают завершение загрузки ресурса синхронно при запуске в Node/Nashorn. Это то, что делает плагин text. Если вы просто хотите запустить AMD-модули и загрузить зависимости плагина с помощью amdefine в Node, им также необходимо завершить работу синхронно, чтобы соответствовать синхронной системе модулей Node.

normalize: function (name, normalize)

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

  • name: Строка. Имя ресурса для нормализации.
  • normalize: Функция. Функция, которая может быть вызвана для нормализации обычного имени модуля.

Пример: предположим, что есть плагин index!, который загрузит имя модуля, заданное индексом. Это искусственный пример, просто чтобы проиллюстрировать концепцию. Модуль может ссылаться на ресурс index! таким образом:

define(['index!2?./a:./b:./c'], function (indexResource) {
    //indexResource will be the module that corresponds to './c'.
});

В этом случае нормализованные имена './a', './b' и './c' будут определены относительно модуля, запросившего этот ресурс. Поскольку RequireJS не знает, как просмотреть «index!2?./a:./b:./c» для нормализации имен './a', './b' и './c', ему нужно спросить плагин. В этом заключается цель вызова normalize.

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

Плагин index! можно написать так:

(function () {

    //Helper function to parse the 'N?value:value:value'
    //format used in the resource name.
    function parse(name) {
        var parts = name.split('?'),
            index = parseInt(parts[0], 10),
            choices = parts[1].split(':'),
            choice = choices[index];

        return {
            index: index,
            choices: choices,
            choice: choice
        };
    }

    //Main module definition.
    define({
        normalize: function (name, normalize) {
            var parsed = parse(name),
                choices = parsed.choices;

            //Normalize each path choice.
            for (i = 0; i < choices.length; i++) {
                //Call the normalize() method passed in
                //to this function to normalize each
                //module name.
                choices[i] = normalize(choices[i]);
            }

            return parsed.index + '?' + choices.join(':');
        },

        load: function (name, req, onload, config) {
            req([parse(name).choice], function (value) {
                onload(value);
            });
        }
    });

}());

Вам не нужно реализовывать normalize, если имя ресурса — просто обычное имя модуля. Например, плагин text! не реализует normalize, потому что имена зависимостей выглядят как «text!./some/path.html».

Если плагин не реализует normalize, загрузчик попытается нормализовать имя ресурса, используя обычные правила имен модулей.

write: function (pluginName, moduleName, write)

write используется только оптимизатором и реализуется только в том случае, если плагин может выводить что-то, что должно принадлежать оптимизированному слою. Он вызывается со следующими аргументами:

  • pluginName: Строка. Нормализованное имя плагина. Большинство плагинов не будут создаваться с именем (они будут анонимными плагинами), поэтому полезно знать нормализованное имя модуля плагина для использования в оптимизированном файле.
  • moduleName: Строка. Нормализованное имя ресурса.
  • write: Функция. Функция, вызываемая со строкой вывода, которая записывается в оптимизированный файл. Эта функция также содержит функцию свойства write.asModule(moduleName, text). asModule можно использовать для записи модуля, который может содержать вызов анонимного define(), требующий вставки имени, и/или содержит неявные зависимости require(""), которые необходимо извлечь для оптимизированного файла. asModule полезен для плагинов преобразования текста, таких как плагин CoffeeScript.

Плагин text! реализует write для записи строкового значения файла текста, который он загрузил. Фрагмент этого файла:

write: function (pluginName, moduleName, write) {
    //The text plugin keeps a map of strings it fetched
    //during the build process, in a buildMap object.
    if (moduleName in buildMap) {
        //jsEscape is an internal method for the text plugin
        //that is used to make the string safe
        //for embedding in a JS string.
        var text = jsEscape(buildMap[moduleName]);
        write("define('" + pluginName + "!" + moduleName  +
              "', function () { return '" + text + "';});\n");
    }
}

onLayerEnd: function (write, data)

onLayerEnd используется только оптимизатором и поддерживается только в версии 2.1.0 или более поздней. Вызывается после записи модулей для слоя в слой. Полезно использовать, если вам нужен какой-то код, который должен идти в конце слоя, или если плагин нуждается в сбросе некоторого внутреннего состояния.

Пример: плагин, который должен записывать некоторые вспомогательные функции в начале слоя в качестве части первого вызова write, и плагину необходимо знать, когда сбрасывать внутреннее состояние, чтобы знать, когда записывать утилиты для следующего слоя. Если плагин реализует onLayerEnd, он может получить уведомление о том, когда следует сбросить внутреннее состояние.

onLayerEnd вызывается со следующими аргументами:

  • write: Функция. Функция, которая вызывается со строкой вывода, чтобы записать её в оптимизированный слой. Модули не должны записываться в этом вызове. Они не будут правильно нормализованы для сосуществования с другими вызовами define() уже в файле. Она полезна только для записи кода, не являющегося define().
  • data: Объект. Информация о слое. Имеет только две свойства:
    • name: имя модуля слоя. Может быть неопределённым.
    • path: путь к файлу слоя. Может быть неопределённым, особенно если вывод осуществляется только в строку, которая используется другим скриптом.

writeFile: function (pluginName, name, parentRequire, write)

writeFile используется только оптимизатором, и его нужно реализовывать только если плагин должен записать альтернативную версию зависимости, обрабатываемой плагином. Сканирование всех модулей проекта для поиска всех зависимостей плагинов немного дорого, поэтому метод writeFile будет вызван только если optimizeAllPluginResources: true находится в профиле сборки для оптимизатора RequireJS. writeFile вызывается со следующими аргументами:

  • pluginName: Строка. Нормализованное имя плагина. Большинство плагинов не имеют имени (они являются анонимными плагинами), поэтому полезно знать нормализованное имя модуля плагина для использования в оптимизированном файле.
  • name: Строка. Нормализованное имя ресурса.
  • parentRequire: Функция. Локальная функция "require". Основное использование этого в writeFile — вызов parentRequire.toUrl() для генерации путей к файлам внутри каталога сборки.
  • write: Функция. Функция, которая вызывается с двумя аргументами:
    • fileName: Строка. Имя файла для записи. Можно использовать parentRequire.toUrl() с относительным путём для генерации имени файла, который будет находиться в каталоге вывода сборки.
    • text: Строка. Содержимое файла. Должно быть закодировано в UTF-8.
    Эта функция также содержит функцию-свойство write.asModule(moduleName, fileName, text). asModule может использоваться для записи модуля, который может иметь анонимный вызов define(), требующий вставки имени, и/или содержит неявные зависимости require(""), которые необходимо извлечь для оптимизированного файла.

См. плагин text! для примера writeFile.

pluginBuilder

pluginBuilder может быть строкой, указывающей на другой модуль, который следует использовать вместо текущего плагина, когда плагин используется в составе сборки оптимизатора.

Плагин может иметь очень специфическую логику, зависящую от определенной среды, например, браузера. Однако при выполнении внутри оптимизатора среда сильно отличается, и у плагина может быть реализация API плагина write, которую он не хочет предоставлять в составе обычного плагина, загружаемого в браузере. В таких случаях указание pluginBuilder полезно.

Некоторые замечания по использованию pluginBuilder:

  • Не используйте именованные модули для плагина или pluginBuilder. Содержимое текста pluginBuilder используется вместо содержимого файла плагина, но это будет работать только если файлы не вызывают define() с именем.
  • Плагины и pluginBuilders, выполняющиеся в процессе сборки, имеют очень ограниченную среду. Оптимизатор работает в нескольких различных средах JS. Будьте внимательны к предположениям об окружении, если вы хотите, чтобы плагин работал в составе оптимизатора.

© jQuery Foundation and other contributors
Licensed under the MIT License.
http://requirejs.org/docs/plugins.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API