Загрузить модуль requireJS, встроенный в тело HTML?

Я интегрирую RequireJS в CMS, поэтому я разместил это в нижней части шаблона моей страницы:

<html>
<body>
  {Placeholder1}
  <script src="scripts/require.js" data-main="scripts/main"></script>
  {Placeholder2}
</body>
</html>

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

<html>
<body>
    <h1>Home</h1>
    <div class="slider">Slider content</div>

    <script src="scripts/require.js" data-main="scripts/main"></script>

    <script type="text/javascript">
      require([
        'jquery',
        'utils',
        'slider'
      ], function ($, utils, slider) {
        slider.start();
      });
    </script>
</body>
</html>

Но я получаю 404 в файлах jquery, utils и js слайдера. Похоже, он не читает мои конфиги main.js, которые у меня есть:

require.config({
    paths: {
        jquery: 'libs/jquery-1.8.1.min',
        utils: 'libs/utils',
        slider: 'libs/jquery.slider.min'
    },
    shim: {
        slider: ['jquery']
    }
});

require([ 'utils' ], function (utils) {
    utils.init();
});

Я попытался загрузить RequireJS и main в заголовок страницы, но таким образом получил противоречивые результаты. Иногда jquery, утилиты и слайдер загружались вовремя, а иногда нет. Как будто встроенный «require» в нижней части страницы не знает об основном RequireJS на странице или правилах зависимостей, но моя точка останова попадает в main.js, поэтому я знаю, что она вызывается. Это потому, что main.js загружается асинхронно, но мой встроенный блок «требуется» в нижней части страницы загружается при рендеринге страницы? Как мне обойти это?

Раньше я успешно использовал RequireJS, но без CMS. Я всегда использовал «define», и модули всегда вызывались асинхронно, но мне никогда не приходилось вызывать встроенную функцию RequireJS, как это. Любые идеи о правильном способе сделать это?


person Basem    schedule 02.10.2012    source источник


Ответы (2)


Здесь важно то, что параметры конфигурации устанавливаются до того, как будут запрошены какие-либо модули. Как вы правильно определили, существуют условия гонки, которые означают, что параметры конфигурации в вашем main.js не загружаются вовремя. Простейшим способом было бы вставить параметры конфигурации в строку перед загрузкой сценария require.js.

<script>
var require = {
    baseUrl: <?= $someVar ?>,
    paths: {
        // etc
    }
}
</script>
<script src="scripts/require.js" data-main="scripts/main"></script>

Далее вниз по странице:

<script>
    require([
        'jquery',
        'utils',
        'slider'
      ], function ($, utils, slider) {
        slider.start();
      });
</script>

См. также Как RequireJS работает с несколькими страницами и частичными представлениями. ?

person Simon Smith    schedule 04.10.2012
comment
Проблема с этой настройкой заключается в том, что ресурсы могут загружаться дважды, когда скрипты/основной файл содержит несколько модулей (обычно в случае использования оптимизатора r.js). Это особенно проблема, если это файл, не использующий определение require. Предположим, что файл scripts/main содержит модуль LESS JS. Кроме того, предположим, что для встроенного вызова require также требуется этот модуль. Теперь, если доступ к встроенному вызову осуществляется до загрузки основного скрипта (что обычно и бывает), модуль будет получен дважды. Если содержимое не является модулем AMD, это может привести к ошибкам! - person Roel van Duijnhoven; 05.10.2013

Похоже, что происходит то, что main.js загружается асинхронно, в то время как встроенный запрос вызывается сразу. Отсюда и противоречивые результаты. Решение состоит в том, чтобы НЕ использовать атрибут data-main и вызывать файл main.js через тег сценария под тегом сценария require.js.

Вы все еще можете определить baseUrl из загруженного файла main.js, сделав это там:

//DETERMINE BASE URL FROM CURRENT SCRIPT PATH
var scripts = document.getElementsByTagName("script");
var src = scripts[scripts.length-1].src;
var baseUrl = src.substring(src.indexOf(document.location.pathname), src.lastIndexOf('/'));

//CONFIGURE LIBRARIES AND DEPENDENCIES VIA REQUIREJS
require.config({
    baseUrl: baseUrl,
....
person Basem    schedule 02.10.2012
comment
Или вместо этого вы можете поместить свой встроенный код в файл main.js. Или вы можете поместить свой путь во встроенный блок кода. - person dqhendricks; 03.10.2012
comment
Одной из причин использования RequireJS является желание не полагаться на глобальные переменные, поэтому избегайте этого. - person Simon Smith; 03.10.2012
comment
@Simon, спасибо за совет. С системами CMS этого трудно избежать. На мой взгляд, почти все CMS устарели. - person Basem; 04.10.2012
comment
Добавил ответ, так как он получился довольно длинным;) - person Simon Smith; 04.10.2012
comment
Это сводило меня с ума! Спасибо. Глупая часть: у меня уже была точно такая же проблема, как год назад, но я не сразу об этом подумал. - person Christof; 14.08.2015