Подтвердить что ты не робот

Require.js вредит моему мозгу. Некоторые фундаментальные вопросы о том, как он загружает скрипты/модули

Предположим, что это мои config.js или main.js:

require.config({
    // paths are analogous to old-school <script> tags, in order to reference js scripts
    paths: {
        jquery: "libs/jquery-1.7.2.min",
        underscore: "libs/underscore-min",
        backbone: "libs/backbone-min",
        jquerymobile: "libs/jquery.mobile-1.1.0.min",
        jquerymobilerouter: "libs/jquery.mobile.router.min"
    },
    // configure dependencies and export value aliases for old-school js scripts
    shim: {
        jquery: ["require"],
        underscore: {
            deps: ["jquery"],
            exports: "_"
        },
        backbone: {
            deps: ["underscore", "jquery"],
            exports: "Backbone"
        },
        jquerymobilerouter: ["jquery", "backbone", "underscore"],
        jquerymobile: ["jquery", "jquerymobilerouter", "backbone", "underscore"]
    }
});
require(["jquery", "backbone", "underscore", "app/app.min", "jquerymobilerouter", "jquerymobile"], function ($, Backbone, _, App) {
    console.log($);
    console.log(Backbone);
    console.log(_);
    $("body").fadeIn(function () {
        App.init();
    });
});
  • Если я правильно понимаю, параметр paths config позволяет вам ссылаться на скрипты, a-la тег <script> в HTML. Предполагая, что это так, мне все еще нужны сценарии псевдонимов, такие как jQuery, с $ или подчеркиванием с _ в моем действительном требовании ниже? Кажется странным, что я должен был бы, учитывая, что если вы ссылаетесь на jQuery со стандартным тегом <script>, $ можно использовать во всех ваших script автоматически. Разве это не должно быть одинаково с помощью paths?

  • Я новичок в опции shim config, который, как я понимаю, заменил устаревший плагин order!. Что на самом деле делает свойство exports? Кажется, он не создает псевдоним для script; например, если я установил exports для подчеркивания на "whatever", а затем попробую console.log(whatever), это undefined. Итак, что точка?

  • Как можно правильно использовать скрипты jQuery "глобально?" То есть, каким образом можно использовать псевдоним $ в моем модуле App.js или любой другой модуль в моей папке "приложение"? Должен ли я требовать jQuery в каждом отдельном модуле и псевдоним $ каждый раз? Или так я сделал это здесь надлежащим образом?

Я бы очень признателен за любую другую критику этого особого script; документация для Require.js, на мой взгляд, оставляет желать лучшего; вещи, о которых я действительно хотел бы узнать больше, похоже, затуманиваются и оставляют меня почесывать голову.

4b9b3361

Ответ 1

  • Пути говорят require.js, где искать, когда вам требуется эта зависимость.

    Например, у меня есть такие настройки, как это:

    "paths": { 
        "jquery": "require_jquery"
    },
    "shim": {
        "jquery-cookie"  : ["jquery"],
        "bootstrap-tab"  : ["jquery"],
        "bootstrap-modal": ["jquery"],
        "bootstrap-alert": ["jquery"]
    },
    

    это означает, что каждый раз в модуле я делаю

    define( ['jquery']
    

    requirejs загружает файл require_jquery из основного пути, а не пытается загрузить jquery.js. В вашем случае он загрузит исходный файл jQuery, который затем будет доступен по всему миру. Мне лично не нравится этот подход, и по этой причине в файле require_jquery.js я делаю:

    define( ["jquery_1.7.2"], function() {
        // Raw jQuery does not return anything, so return it explicitly here.
        return jQuery.noConflict( true );
    } );
    

    что означает, что jQuery будет определяться только внутри моих модулей. (Это потому, что я пишу плагины Wordpress, и поэтому я могу включить свою собственную версию jQuery, не касаясь внешней версии).

  • Экспорт (чтение из документов просто должно быть именем используемого вами модуля, чтобы его можно было обнаружить, если загрузка прошла правильно. Здесь. Поэтому, если вы хотите установить экспорт для подчеркивания, он должен быть _

  • jQuery должен быть глобальным, как я объяснил, если вы просто импортируете его, файл выполняется и jQuery является глобальным

EDIT - ответить на комментарии.

  • да, я имею в виду это, вы должны экспортировать $или jQuery для jQuery и _ для магистрали. Из того, что я получил из документов, это необходимо только в некоторых случаях с краями и не понадобится для библиотек, которые объявляют себя в глобальном пространстве имен как jQuery.

    Я думаю, что requirejs нуждается в них, когда ему приходится отказываться от загрузки jQuery из CDN. я думаю, что requirejs сначала пытается загрузить jQuery из CDN, а затем делает проверку, чтобы убедиться, что она была загружена правильно, проверяя, что существует "экспортированная" переменная, и если она не загружает ее, формирует локальную файловую систему (если вы конечно, сконфигурировал откаты). Это то, что было необходимо, когда requirejs не может видеть возвращение 404.

  • jQuery доступен в глобальном масштабе, поскольку он объявлен глобальным. Если вы просто загрузите и выполните jQuery script, вы получите два глобальных символа, $ и jQuery (или вы можете делать то, что я сделал, и избегать этого). Внутри функции define() вы можете псевдоним jQuery быть тем, что хотите.

    define( [ 'jquery' ], function( jq ) {
        // jq is jquery inside this function. if you declared it 
        // globally it will be also available as $ and jQuery
    } );
    

Ответ 2

Просто, чтобы устранить любую путаницу вокруг exports, он предположил, что любая библиотека shim придает свойство глобальному контексту (window или root) или изменяет уже существующее глобальное свойство (например, плагин jQuery). Когда requireJS получает команду для загрузки зависимой зависимости, он анализирует глобальный контекст для свойства, соответствующего значению exports этой конфигурации shim, и если он находит его, возвращает его как значение этого модуля. Если он не находит его, он загружает связанный script, ждет его выполнения, затем находит глобальный символ и возвращает его.

Важно помнить, что если конфигурация shim не содержит значение exports, любой метод init в этом конфиге НЕ будет выполнен. Загрузчик зависимостей должен найти значение для модуля (это то, что указано exports), прежде чем этот модуль может быть инициализирован, поэтому свойство требуется, если для этого модуля имеется прокладка init.

: Мне также нужно указать, что если рассматриваемый модуль вызывает define в любом месте, любая конфигурация shim, которую вы имеете для этого модуля, будет проигнорирована. Это на самом деле вызвало у меня некоторые головные боли, потому что я хотел использовать конфигурацию shim для вызова метода jQuery jQuery.noConflict(true) для un-globify jQuery и держать его в области только для модулей, которые его требуют, но не смог заставить его работать. (См. Обновление внизу для информации о том, как легко сделать это, используя конфигурацию карты вместо конфигурации shim.)

update 2: недавний вопрос о группе google requireJS заставил меня понять, что мое объяснение может немного ввести в заблуждение, поэтому я хотел бы уточнить. Требование JS будет повторно использовать зашифрованную зависимость, если она была загружена через requireJS хотя бы один раз. То есть, если вы просто используете тег <script> на странице хостинга (например, подчеркивание), например:

<script src='lib/underscore.js'></script>
<script src='lib/require.js' data-main='main.js'></script>

... и у вас есть что-то подобное в вашей конфигурации requireJS:

paths: {
    'underscore': 'lib/underscore'
},
shim: {
    'underscore': {
        exports: '_'
    }
}

Тогда в первый раз, когда вы выполняете define(['underscore'], function (_) {}); или var _ = require('underscore');, RequireJS будет повторно загружать библиотеку подчёркивания, а не повторно использовать ранее определенный window._, потому что, насколько известно requireJS, вы никогда не загружали подчеркивание раньше. Конечно, он может проверить, не определено ли _ в корневой области, но у него нет способа проверить, что _ уже есть тот, что указан в конфигурации paths. Например, как prototype, так и jquery по умолчанию назначаются window.$, и если requireJS предполагает, что "window. $" Является jQuery, когда он на самом деле прототип, вы окажетесь в плохом состоянии.

Все это означает, что если вы смешиваете и сопоставляете стили загрузки script, например, ваша страница будет завершена примерно так:

 <script src='lib/underscore.js'></script>
 <script src='lib/require.js' data-main='main.js'></script>
 <script src='lib/underscore.js'></script>

Где второй экземпляр подчеркивания - тот, который загружен requireJS.

В принципе, библиотека должна быть загружена через requireJS для того, чтобы requireJS знал об этом. Тем не менее, в следующий раз, когда вам потребуется подчеркнуть, requireJS пойдет "эй, я уже загрузил это, так что просто отмените все значения exports и не беспокойтесь о загрузке другого script".

Это означает, что у вас есть два реальных варианта. Один из них - это то, что я считаю анти-шаблоном: просто не используйте requireJS для выражения зависимостей для глобальных скриптов. То есть, пока библиотека присоединяет глобальный корневой контекст, вы сможете получить к нему доступ, если эта зависимость явно не требуется. Вы можете понять, почему это анти-шаблон - вы в основном просто исключили большинство преимуществ использования загрузчика AMD (явный список зависимостей и переносимость).

Другой, лучший вариант - использовать requireJS для загрузки всего, до той степени, что единственным фактическим тегом script, который вы должны создать самостоятельно, является тот, который изначально загружает requireJS. Вы можете использовать прокладки, но в 95% случаев это действительно не так сложно добавить обертку AMD в script. Может потребоваться немного больше работы, чтобы преобразовать все ваши не-AMD-библиотеки в совместимые с AMD, но как только вы сделали один или два, это становится намного проще - я могу использовать любой общий плагин jQuery и преобразовать его в модуль AMD менее чем за минуту. Обычно это просто вопрос добавления

define(['jquery'], function (jQuery) {

вверху и

    return jQuery;
});

внизу. Причина, по которой у меня есть "jquery", сопоставление с jquery, а не $, заключается в том, что я заметил, что большинство плагинов в эти дни завернуты в закрытие следующим образом:

(function ($) {
    // plugin code here
})(jQuery);

И это хорошая идея обратить внимание на предполагаемый объем. Вы можете, конечно, сопоставить 'jquery' с $ напрямую, полагая, что плагин не ожидает найти jquery вместо $. Это просто базовая оболочка AMD - более сложные, как правило, пытаются определить, какой тип загрузчика используется (commonJS vs AMD vs regular ol globals) и использовать другой способ загрузки в зависимости от результата. Вы можете легко найти примеры этого с помощью нескольких секунд в Google.

Обновление. Обходной путь, который я использовал для поддержки использования jQuery.noConflict(true) с RequireJS, работал, но для него очень небольшая модификация источника jQuery, и с тех пор я понял, что гораздо лучший способ выполнить одно и то же без изменения jQuery. К счастью, у Джеймса Берка, автора RequireJS, который добавил его в документацию RequireJS: http://requirejs.org/docs/jquery.html#noconflictmap