Как я могу использовать requireJS и jQuery вместе?

Я хотел бы использовать requireJS, и я использую jQuery. Я не хочу использовать комбинированную версию requireJS и jQuery, так как я не использую последнюю версию jQuery. Каков наилучший способ работы с requireJS?

Ответ 1

Это тоже мой точный вопрос! Я также должен использовать более старые jQuery, но также более "традиционные" javascript-библиотеки. Какая лучшая техника для этого? (Я могу изменить ваш вопрос, чтобы сделать его более широким, если вы не возражаете.) Вот что я узнал.

Требование JS автор Джеймс Берк объяснил преимущества комбинированного файла RequireJS + jQuery. Вы получаете две вещи.

  • Доступен модуль jquery, и это объект jQuery. Это безопасно:

    // My module depends on jQuery but what if $ was overwritten?
    define(["jquery"], function($) {
      // $ is guaranteed to be jQuery now */
    })
    
  • jQuery уже загружен перед любыми тэгами require() или define(). Все модули гарантируют, что jQuery готов. Вам даже не нужен плагин require/order.js, поскольку jQuery в основном был жестко запрограммирован для загрузки.

Мне, # 2 не очень полезно. Большинство реальных приложений имеют много файлов .js, которые должны загружаться в правильном порядке, но правда. Как только вам понадобится Sammy или Underscore.js, объединенный файл RequireJS + jQuery не поможет.

Мое решение заключается в написании простых оболочек RequireJS, которые загружают мои традиционные скрипты с помощью плагина "order".

Пример

Предположим, что мое приложение имеет эти компоненты (по зависимости).

  • Мое приложение greatapp
    • greatapp зависит от пользовательского jquery (старая версия, которую я должен использовать)
    • greatapp зависит от my_sammy (SammyJS плюс все его плагины, которые я должен использовать). Эти должны быть в порядке
      • my_sammy зависит от jquery (SammyJS - это плагин jQuery)
      • my_sammy зависит от sammy.js
      • my_sammy зависит от sammy.json.js
      • my_sammy зависит от sammy.storage.js
      • my_sammy зависит от sammy.mustache.js

На мой взгляд, все выше, что заканчивается на .js, является "традиционным" script. Все без .js является плагином RequireJS. Ключ: материал высокого уровня (greatapp, my_sammy) - это модули, а на более глубоких уровнях он возвращается к традиционным файлам .js.

Загрузка

Все начинается с того, что booter сообщает RequireJS, как начать.

<html>
  <head>
    <script data-main="js/boot.js" src="js/require.js"></script>
  </head>
</html>

В js/boot.js я ставлю только конфигурацию и как запустить приложение.

require( // The "paths" maps module names to actual places to fetch the file.
         // I made modules with simple names (jquery, sammy) that will do the hard work.
         { paths: { jquery: "require_jquery"
                  , sammy : "require_sammy"
                  }
         }

         // Next is the root module to run, which depends on everything else.
       , [ "greatapp" ]

         // Finally, start my app in whatever way it uses.
       , function(greatapp) { greatapp.start(); }
       );

Основное приложение

В greatapp.js У меня есть нормальный модуль.

define(["jquery", "sammy"], function($, Sammy) {
  // At this point, jQuery and SammyJS are loaded successfully.
  // By depending on "jquery", the "require_jquery.js" file will run; same for sammy.
  // Those require_* files also pass jQuery and Sammy to here, so no more globals!

  var start = function() {
    $(document).ready(function() {
      $("body").html("Hello world!");
    })
  }

  return {"start":start};
}

Обязательные модули модуля вокруг традиционных файлов

require_jquery.js:

define(["/custom/path/to/my/jquery.js?1.4.2"], function() {
  // Raw jQuery does not return anything, so return it explicitly here.
  return jQuery;
})

require_sammy.js:

// These must be in order, so use the "order!" plugin.
define([ "order!jquery"
       , "order!/path/to/custom/sammy/sammy-0.6.2-min.js"
       , "order!/path/to/custom/sammy/plugins/sammy.json-0.6.2-min.js"
       , "order!/path/to/custom/sammy/plugins/sammy.storage-0.6.2-min.js"
       , "order!/path/to/custom/sammy/plugins/sammy.mustache-0.6.2-min.js"
       ]

       , function($) {
           // Raw sammy does not return anything, so return it explicitly here.
           return $.sammy;
         }
      );

Ответ 2

Этот вопрос, по крайней мере, два года, но я заметил, что это проблема с RequireJS 2.0 (require-jquery.js использует jQuery 1.8.0, но последняя версия - 1.8.2).

Если вы столкнулись с этим вопросом, обратите внимание, что require-jquery.js теперь просто требует .js и jquery.js, выровненных вместе. Вы можете просто отредактировать require-jquery.js и заменить части jQuery на более новую версию.

Обновление (30 мая 2013 г.): Теперь, когда RequireJS имеет пути и прокладки, существует новый способ импортировать плагины jQuery и jQuery, и старый метод больше не нужен, а рекомендуется. Ниже приведена сокращенная версия текущего метода:

requirejs.config({
    "paths": {
      "jquery": "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min"
    }
});

define(["jquery"], function($) {
    $(function() {
    });
});

Подробнее см. http://requirejs.org/docs/jquery.html.

Ответ 3

Я нашел лучший подход - сохранить jQuery вне сборки RequireJS.

Просто включите jquery.min.js в свой HTML. Затем создайте файл jquery.js с чем-то вроде этого...

define([], function() {
    return window.$;
});

Ответ 4

Найден JasonSmith anwer чрезвычайно полезен, возможно, больше, чем документация RequireJS.

Однако есть возможность оптимизировать его, чтобы избежать отдельных запросов AJAX для (крошечных) модулей определения-объявления ( "require_jquery" "require_sammy" ). Я бы предположил, что r.js сделает это на стадии оптимизации, но вы можете сделать это раньше времени, чтобы не сражаться с Path, системой BaseURI.

index.html

<html>
  <head>
    <script data-main="js/loader.js" src="js/require.js"></script>
  </head>
</html>

loader.js:

// We are going to define( dependencies by hand, inline.
// There is one problem with that through (inferred from testing):
// Dependencies are starting to load (and execute) at the point of declaring the inline
// define, not at the point of require(
// So you may want to nest the inline-defines inside require( 
// this is, in a way, short replacement for Order plug in, but allows you to use
// hand-rolled defines, which the Order plug in, apparently does not allow.

var jQueryAndShims = ['jquery']

if(window.JSON == null){
    jQueryAndShims.push('json2')
    define(
        'json2'
        , ['js/libs/json2.min.js']
        , function() {
            return window.JSON
        }
    )
}
// will start loading the second we define it.
define(
    'jquery'
    , ['js/libs/jquery_custom.min.js']
    , function() {
        // we just pick up global jQuery here. 
        // If you want more than one version of jQuery in dom, read a more complicated solution discussed in
        // "Registering jQuery As An Async-compatible Module" chapter of
        // http://addyosmani.com/writing-modular-js/
        return window.jQuery 
    }
)

// all inline defines for resources that don't rely on other resources can go here.

// First level require(
// regardless of depends nesting in 'myapp' they will all start downloading 
// at the point of define( and exec whenever they want, 
// async in many browsers. Actually requiring it before the nested require makes
// sure jquery had *executed and added jQuery to window object* before
// all resolved depends (jquery plugins) start firing.
require(jQueryAndShims, function($) {

    // will start loading the second we define it.        
    define(
        'sammy_and_friends'
        , ['jquery','js/libs/jquery_pluginone.min.js','js/libs/jquery_plugintwo.min.js','js/libs/sammy.min.js']
        , function($) {
            // note, all plugins are unaltered, as they are shipped by developers.
            // in other words, they don't have define(.. inside.
            // since they augment global $ (window.jQuery) anyway, and 'jquery' define above picks it up
            // , we just keep on returning it.
            // Sammy is attached to $ as $.sammy, so returning just Sammy makes little sense
            return $
        }
    )

    // second level require - insures that Sammy (and other jQuery plugins) - 'sammy_and_friends' - is
    // loaded before we load Sammy plugins. I normally i would inline all sammy plugins i need 
    // (none, since i use none of them preferring jQuery direct templating API
    // and no other Sammy plug in is really of value. )  right into sammy.js file. 
    // But if you want to keep them separate:
    require(['sammy_and_friends'], function() {

        // will start loading the second we define it.
        define(
            'sammy_extended'
            , ['sammy_and_friends','js/libs/sammy_pluginone.min.js','js/libs/sammy_plugintwo.min.js']
            , function($) {
                // as defined above, 'sammy_and_friends' actually returns (globall) jQuery obj to which
                // Sammy is attached.  So we continue to return $
                return $
            }
        )
        // will start loading the second we define it.
        define(
            'myapp'
            , ['sammy_extended', 'js/myapplication_v20111231.js'] 
            , function($, myapp_instantiator) {
                // note, myapplication may, but does not have to contain RequireJS-compatible define
                // that returns something. However, if it contains something like 
                // "$(document).ready(function() { ... " already it MAY fire before 
                // it depends - 'sammy_extended' is fully loaded.
                // Insdead i recommend that myapplication.js returns a generator 
                // (app-object-generating function pointer)
                // that takes jQuery (with all loaded , applied plugins) 
                // The expectation is that before the below return is executed, 
                // all depends are loaded (in order of depends tree)
                // You would init your app here like so:
                return myapp_instantiator($)
                // then "Run" the instance in require( as shown below
            }
        )

        // Third level require - the one that actually starts our application and relies on
        // dependency pyramid stat starts with jQuery + Shims, followed by jQuery plugins, Sammy, 
        // followed by Sammy plugins all coming in under 'sammy_extended'
        require(['jquery', 'myapp'], function($, myappinstance) {
            $(document).ready(function() {myappinstance.Run()})
        })
    }) // end of Second-level require
}) // end of First-level require

наконец, myapplication.js:

// this define is a double-wrap.
// it returns application object instantiator that takes in jQuery (when it available) and , then, that
// instance can be "ran" by pulling .Run() method on it.
define(function() {
    // this function does only two things:
    // 1. defines our application class 
    // 2. inits the class and returns it.
    return function($) {
        // 1. defining the class
        var MyAppClass = function($) {
            var me = this
            this._sammy_application = $.sammy(function() {
                this.raise_errors = true
                this.debug = true
                this.run_interval_every = 300
                this.template_engine = null
                this.element_selector = 'body'
                // ..
            })
            this._sammy_application.route(...) // define your routes ets...
            this.MyAppMethodA = function(blah){log(blah)}  // extend your app with methods if you want
            // ...
             // this one is the one we will .Run from require( in loader.js
            this.Run = function() {
                me._sammy_application.run('#/')
            }
        }
        // 2. returning class instance
        return new MyAppClass($) // notice that this is INITED app, but not started (by .Run) 
        // .Run will be pulled by calling code when appropriate
    }
})

Эта структура (свободно заменяет (дублирует?) RequireJS Order plugin, но) позволяет вам сократить количество файлов, которые вам нужны для AJAX, добавив больше контроля в определение дерева зависимых и зависимых.

Существует также большой бонус к загрузке jQuery отдельно (обычно на 100k) - вы можете контролировать кеширование на сервере или кешировать jQuery в браузере localStorage. Взгляните на проект AMD-Cache здесь https://github.com/jensarps/AMD-cache, затем измените определение (инструкции, которые включают "cache!": И это будет (навсегда:)) застрял в пользовательском браузере.

define(
    'jquery'
    , ['cache!js/libs/jquery_old.min.js']
    , function() {
        // we just pick up global jQuery here. 
        // If you want more than one version of jQuery in dom, read a more complicated solution discussed in
        // "Registering jQuery As An Async-compatible Module" chapter of
        // http://addyosmani.com/writing-modular-js/
        return window.jQuery 
    }
)

Замечание о jQuery 1.7.x + Оно больше не прикрепляется к объекту окна, поэтому выше НЕ будет работать с неизмененным файлом jQuery 1.7.x +. Там вы должны настроить jquery **. Js, чтобы включить это перед закрытием "}) (window);":

;window.jQuery=window.$=jQuery

Если у вас есть ошибки "jQuery undefined" в консоли, то используемая вами версия значка jQuery не привязывается к окну.

Код лицензии: Public domain.

Раскрытие информации: JavaScript над запахами "псевдокода", поскольку это перефразирование (обрезка вручную) гораздо более детального производственного кода. Код, представленный выше, не гарантированно работает и НЕ тестировался, чтобы работать как представленный. Аудит, протестируйте его. Точки с запятой опущены специально, так как они не требуются для спецификации JS, и код выглядит лучше без них.

Ответ 5

В дополнение к ответу jhs см. более последние инструкции на странице require-jquery github из файла README.md. Он охватывает как простейший подход использования комбинированного файла jquery/require.js, так и как использовать отдельный jquery.js.