Як я можу використовувати requireJS та jQuery разом?


82

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


2
Що заважає вам використовувати найновіший jQuery?
Incognito

Я використовую jQuery 1.3.8. Ця версія працює дещо інакше, ніж 1.4.X. Я хочу використовувати найновіший jQuery, я повинен оновити деякий код, і зараз у мене немає часу на це. Більше того, я не вважаю, що поєднання пакетів - це правильно.
Наор

Відповідь нижче хороша ... чому ви не позначили її як правильну?
В'язень ZERO

@Prisoner ZERO: Чесно кажучи, мені не вдалося це перевірити. поступово я використовував завантажувач сценаріїв ajax від Microsoft. Дякуємо, що нагадали мені позначити цю відповідь. Якщо ви сказали, що це здорово - я вам вірю.
Наор,

Я також виявив, що requirejs важко використовувати з іншими бібліотеками, і навпаки. Ось чому я створив бібліотеку, яка набагато простіша у використанні та перевірена за допомогою angular. Внизу є демонстраційний додаток: gngeorgiev.github.io/Modulerr.js Ви також можете об'єднати всі сценарії в один без залежності від Modulerr.js
Georgi-it

Відповіді:


130

Це теж моє точне запитання! Я також повинен використовувати старішу jQuery, але також і більш "традиційні" бібліотеки javascript. Яка найкраща техніка для цього? (Я можу відредагувати ваше запитання, щоб зробити його більш широким, якщо ви не проти.) Ось що я дізнався.

Автор RequireJS, Джеймс Берк, пояснив переваги комбінованого файлу RequireJS + jQuery . Ви отримуєте дві речі.

  1. Доступний модуль jquery,, і це об’єкт jQuery. Це безпечно:

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

Для мене №2 не дуже корисний. Більшість реальних додатків мають багато .js файлів, які потрібно завантажувати у правильному порядку - сумно, але правдиво. Як тільки вам знадобиться Sammy або Underscore.js, комбінований файл RequireJS + jQuery не допомагає.

Моє рішення - написати прості обгортки RequireJS, які завантажують мої традиційні сценарії за допомогою плагіна "order".

Приклад

Припустимо, у моїй програмі є ці компоненти (залежно).

  • Мій додаток, greatapp
    • greatapp залежить від користувацького jquery (стара версія, яку я повинен використовувати)
    • greatapp залежить від my_sammy (SammyJS плюс усі його плагіни, якими я повинен користуватися). Вони повинні бути в порядку
      1. my_sammy залежить від jquery (SammyJS - це плагін jQuery)
      2. my_sammy залежить від sammy.js
      3. my_sammy залежить від sammy.json.js
      4. my_sammy залежить від sammy.storage.js
      5. my_sammy залежить від sammy.mustache.js

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

Завантаження

Все починається з бутера, який розповідає 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};
}

Потрібні обгортки модулів JS навколо традиційних файлів

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;
         }
      );

5
Хороша робота над цією відповіддю ... сподіваємось, запитувач позначить це!
В'язень ZERO

ви створюєте модуль require_jquery залежно від фактичного файлу jquery, але чи не залишається jquery глобальним? фактичний файл jquery 1.4.2, який ви завантажуєте зі спеціального шляху, не є модулем require.js? чи ви теж обгортали цей файл?
Сандер

3
Я хотів би зазначити, що з останньою версією jQuery (1.7) він вже підтримує модулі, і тому все, що вам потрібно зробити, це вимагати його як зазвичай, і він буде працювати.
MikeMurko

1
хтось може оновити цю відповідь, щоб відобразити, як зробити потрібно JS 2 (w / shim) + jQuery 1.7+, що підтримує AMD?
Генрі

1
Я просто хотів би зазначити, що найкращим способом досягнення підтримки залежностей за допомогою файлів JavaScript, що не належать до AMD, є конфігурація shim, яка знаходиться в RequireJS 2.0+. Якщо ви все ще використовуєте Require 1.x, ви можете використовувати попередник shim , wrapjs
Йоганн

32

Цьому питанню вже щонайменше два роки, але я помітив, що це проблема досі з RequireJS 2.0 (require-jquery.js використовує jQuery 1.8.0, але остання версія - 1.8.2).

Якщо ви випадково бачите це запитання, зверніть увагу, що require-jquery.js тепер є лише require.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 для отримання додаткової інформації.


Дякую, це все ще актуально :)
Наор

Ви все ще використовуєте jQuery 1.3.8? :)
Кріс,

Дякуємо, що вказали на це. Я читав, що у старої версії 1.8 були проблеми, які були вирішені в останній.
Blaine Mucklow

Справді. Вони не мали проблем з jQueryUI з curCSS, чи не так?
Кріс

1
@AHMED: Вони обидва працюють. Різниця полягає в тому, що дефініція явно визначає модуль. Я, як правило, вважаю за краще використовувати дефініцію майже виключно, тому що це більш чітко про шляхи: stackoverflow.com/questions/16087635/…
Кріс,

9

Я знайшов найкращий підхід - тримати jQuery поза моєю збіркою RequireJS.

Просто включіть jquery.min.js у свій HTML. Потім створіть файл jquery.js приблизно з цим ...

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

Це хороший спосіб вирішити проблему, оскільки у мене є деякі файли JS, які традиційно завантажуються за допомогою тегів сценаріїв, і вони залежать від jQuery.
jingtao

3

Виявлено, що відповідь ДжейсонСміта надзвичайно корисна, можливо, більше, ніж документація 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's 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's 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's 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's 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's 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's Order, але) дозволяє обрізати кількість файлів, необхідних для AJAX, додаючи більше контролю у визначенні дерева залежностей та залежностей.

Також є великий бонус за окреме завантаження jQuery (яке зазвичай становить 100 тис.) - ви можете керувати кешуванням на сервері або кешувати jQuery в localStorage браузера. Погляньте на проект AMD-Cache тут https://github.com/jensarps/AMD-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.jQuery=window.$=jQuery

Якщо у вас є помилки "jQuery undefined" у консолі, це означає, що версія jQuery, яку ви використовуєте, не прикріплюється до вікна.

Ліцензія коду: Суспільне надбання.

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


Після боротьби з RequireJS (речі, що завантажуються не в порядку, не дотримуючись визначення, вимагають вкладеності. Інші магічні поведінки) перейшов на Curl.JS і почав добре спати вночі. Це не так розкручено, але, блін, воно стабільне і з ним легко працювати!
ddotsenko

1

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.