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

Как использовать профиль сборки RequireJS + r.js в многостраничном проекте

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

Структура моего проекта следующая:

httpdocs_siteroot/
    app/
        php files...
    media/
        css/
            css files...
        js/
            libs/
                jquery.js
                require.js
                mustache.js
            mains/
                main.page1.js
                main.page2.js
                main.page3.js
            plugins/
                jquery.plugin1.js
                jquery.plugin2.js
                jquery.plugin3.js
            utils/
                util1.js
                util2.js
        images/

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

Мои вопросы:

  • Является ли RequireJS даже практичным для проектов, которые не являются одностраничными?

  • Без использования оптимизатора каждый из моих основных файлов начинается с тех же конфигурационных параметров:

    requirejs.config({
      paths: {
        'jquery': 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min'
      },
      baseUrl: '/media/js/',
      // etc...
    });
    require(['deps'], function() { /* main code */ });
    

    Есть ли способ избежать этого? Например, если каждый основной файл содержит один и тот же профиль сборки, не имея на самом деле его сборки?

  • Должен ли r.js войти в httpdocs_siteroot родительский каталог?

  • Есть ли что-то нелепое в моей структуре dir приложения или моем использовании RequireJS?

4b9b3361

Ответ 1

Прежде всего, это не вопрос с уникальным решением. Я объясню, как я использую RequireJS, который работает для меня, и может работать для вас:)

Во-вторых, английский не является моим родным языком. Исправления и советы по поводу языка будут очень оценены. Не стесняйтесь, ребята:)

1) Требуется ли js даже практично для проектов, которые не являются одностраничными?

Это зависит. Если у вашего проекта нет общего кода между страницами, например, справка RequireJS будет скромной. Основная идея RequireJS - это модуляция приложения в куски многоразового кода. Если ваше приложение использует только код, специфичный для страницы, то использование RequireJS может быть не очень хорошей идеей.

2) Без использования оптимизатора каждый из моих основных файлов начинается с тех же параметров конфигурации. Есть ли способ избежать этого? Как и каждый основной файл включает в себя один и тот же профиль сборки без необходимости его сборки?

Единственный способ, который я вижу, - это сделать конфигурацию в основном файле или создать модуль, который будет настраивать RequireJS, а затем использовать этот модуль в качестве первой зависимости от main.js. Но это может быть сложно. Я не использую много файлов main.js в своих приложениях; Я использую только тот, который действует как загрузчик (см. Ниже).

3) Должен ли r.js перейти в родительский каталог httpdocs_siteroot?

Не обязательно. Вы можете поместить его в каталог /media, так как все ваши клиентские материалы есть.

4) Есть ли что-то нелепое в моей структуре приложения app или в моем использовании requirejs?

Я бы этого не сказал. С другой стороны, структура, возможно, немного фрагментирована. Например, вы можете поместить все "сторонние вещи" в каталог /vendor. Но это просто сахар; ваша структура будет работать хорошо и кажется правильной. Я думаю, что основной проблемой является вызов requirejs.config() в нескольких основных файлах.

У меня были те же проблемы, с которыми вы сталкиваетесь сейчас, и у меня получилось следующее решение:

1) Не завершайте файлы, не совместимые с AMD, с помощью определения. Хотя он работает, вы можете добиться тех же результатов, используя свойство "shim" в requirejs.config(см. Ниже).

2) В многостраничном приложении решение для меня - это не требовать от модуля, ориентированного на страницы, оптимизированного файла main.js. Вместо этого мне требуется весь общий код (сторонний и мой собственный) из основного файла, оставив на странице страницы код, специфичный для каждой страницы. Основной файл заканчивается только загрузчиком, который запускает код, специфичный для страницы, после загрузки всех файлов shared/lib.

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

Структура каталогов:

/src - я помещаю все содержимое клиента в каталог src, поэтому я могу запустить оптимизатор внутри этого каталога (это ваш медиа-каталог).

/src/vendor - Здесь я размещаю все сторонние файлы и плагины, включая require.js.

/src/lib - Здесь я помещаю весь свой собственный код, который используется всем приложением или некоторыми страницами. Другими словами, модули, не относящиеся к странице.

/src/page-module-xx - И затем я создаю один каталог для каждой страницы, которая у меня есть. Это не строгое правило.

/src/main.js. Это единственный основной файл для всего приложения. Он будет:

  • настроить RequireJS, включая прокладки
  • загрузка разделяемых библиотек/модулей
  • Загрузите основной модуль для страницы

Это пример вызова requirejs.config:

requirejs.config({
        baseUrl: ".",
        paths: {
            // libraries path
            "json": "vendor/json2",
            "jquery": "vendor/jquery",
            "somejqueryplugion": "vendor/jquery.somejqueryplufin",
            "hogan": "vendor/hogan",

            // require plugins
            "templ": "vendor/require.hogan",
            "text": "vendor/require.text"
        },
        // The shim section allows you to specify 
        // dependencies between non AMD compliant files.
        // For example, "somejqueryplugin" must be loaded after "jquery".
        // The 'exports' attribute tells RequireJS what global variable
        // it must assign as the module value for each shim.
        // For example: By using the configutation below for jquery, 
        // when you request the "jquery" module, RequireJS will 
        // give the value of global "$" (this value will be cached, so it is
        // ok to modify/delete the global '$' after all plugins are loaded.
        shim: {
            "jquery": { exports: "$" },
            "util": { exports: "_" },
            "json": { exports: "JSON" },
            "somejqueryplugin": { exports: "$", deps: ["jquery"] }
        }
    });

И затем, после настройки, мы можем сделать первый запрос require() для всех этих библиотек, и после этого выполните запрос для нашего модуля "главная страница".

//libs
require([
    "templ",     //require plugins
    "text",
    "json",      //3rd libraries
    "jquery",
    "hogan", 
    "lib/util"  // app lib modules
 ],
    function () {
        var $ = require("jquery"),
            // the start module is defined on the same script tag of data-main.
            // example: <script data-main="main.js" data-start="pagemodule/main" src="vendor/require.js"/>
            startModuleName = $("script[data-main][data-start]").attr("data-start");

        if (startModuleName) {
            require([startModuleName], function (startModule) {
                $(function(){
                    var fn = $.isFunction(startModule) ? startModule : startModule.init;
                    if (fn) { fn(); }
                });
            });
        }
    });

Как вы можете видеть в теле require() выше, мы ожидаем другого атрибута тега require.js script. Атрибут data-start будет содержать имя модуля для текущей страницы.

Таким образом, на странице HTML мы должны добавить этот дополнительный атрибут:

<script data-main="main" data-start="pagemodule/main" src="vendor/require.js"></script>

Таким образом, мы закончим оптимизированный main.js, который содержит все файлы в каталогах "/vendor" и "/lib" (разделяемые ресурсы), но не скрипты/модули для страницы, как они не жестко закодированы в main.js как зависимости. Модули, специфичные для страницы, будут загружаться отдельно на каждой странице приложения.

Модуль "главная страница" должен вернуть function(), который будет выполняться с помощью "основного приложения" выше.

define(function(require, exports, module) {
    var util = require("lib/util");

    return function() {
        console.log("initializing page xyz module");
    };
});

EDIT

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

Например, скажем, у нас есть следующий модуль страницы:

/page1/main.js

/page1/dep1.js

/page1/dep2.js

Если мы не оптимизируем этот модуль, браузер сделает 3 запроса, по одному для каждого script. Мы можем избежать этого, поручив r.js создать пакет и включить эти 3 файла.

В атрибуте "modules" профиля сборки:

...
"modules": [
   { 
      name: "main"  // this is our main file
   },
   {
        // create a module for page1/main and include in it
        // all its dependencies (dep1, dep2...)
        name: "page1/main",
        // excluding any dependency that is already included on main module
        // i.e. all our shared stuff, like jquery and plugins should not
        // be included in this module again.
        exclude: ["main"]
   }
]

Сделав это, мы создаем другой основной файл на каждой странице со всеми его зависимостями. Но поскольку у нас уже есть основной файл, который будет загружать все наши общие материалы, нам не нужно включать их снова в page1/main module. Конфигурация немного подробна, так как вы должны сделать это для каждого модуля страницы, где у вас есть более одного файла script.

Я загрузил код шаблона в GitHub: https://github.com/mdezem/MultiPageAppBoilerplate. Это рабочий шаблон, просто установите node и модуль r.js для node и выполните build.cmd(внутри каталога /build, иначе он будет терпеть неудачу, потому что он использует относительные пути)

Надеюсь, я поняла. Дайте мне знать, если что-то звучит странно;)

Привет!

Ответ 2

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


// file: js/main

require(['./global.config'], function(){
    require(['./view/home'], function() {
        // do something
    });
});

Это то, что я использовал в своем проекте.