RequireJS ve jQuery'yi birlikte nasıl kullanırım?


82

RequireJS'yi kullanmak istiyorum ve jQuery kullanıyorum. En son jQuery sürümünü kullanmadığım için requireJS ve jQuery'nin birleşik sürümünü kullanmak istemiyorum. RequireJS ile çalışmanın en iyi yolu nedir?


2
En son jQuery'yi kullanmanızı engelleyen nedir?
Gizli

JQuery 1.3.8 kullanıyorum. Bu sürüm 1.4.X'ten biraz farklı çalışır. En yeni jQuery'yi kullanmak için sipariş veriyorum, bazı kodları güncellemem gerekiyor ve şu anda bunun için zamanım yok. Dahası, paketleri birleştirmenin doğru bir şey olduğunu düşünmüyorum.
Naor

Aşağıdaki cevap güzel ... neden doğru olarak işaretlemediniz?
Mahkum SIFIR

@ Mahkum ZERO: Dürüst olmak gerekirse, test etmeyi başaramadım. son zamanlarda microsoft'un ajax script yükleyicisini kullandım. Bu yanıtı işaretlememi hatırlattığın için teşekkürler. Harika diyorsan - sana inanıyorum.
Naor

Ayrıca needjs'i diğer kütüphanelerde kullanmanın zor olduğunu ve bunun tersini buldum. Bu yüzden kullanımı çok daha kolay ve açısal olarak test edilen bir kütüphane oluşturdum. Altta bir demo uygulaması var: gngeorgiev.github.io/Modulerr.js Tüm komut dosyalarını, Modulerr.js'ye bağımlı olmadan da birleştirebilirsiniz
Georgi-it

Yanıtlar:


130

Benim de tam sorum bu! Ayrıca daha eski bir jQuery kullanmalıyım, ama aynı zamanda daha "geleneksel" javascript kitaplıkları. Bunu yapmak için en iyi teknik nedir? (Sakıncası yoksa sorunuzu daha geniş hale getirmek için düzenleyebilirim.) İşte öğrendiklerim.

RequireJS yazarı James Burke, birleştirilmiş RequireJS + jQuery dosyasının avantajlarını açıkladı . İki şey alırsın.

  1. Bir modül jquerymevcuttur ve bu jQuery nesnesidir. Bu güvenlidir:

    // My module depends on jQuery but what if $ was overwritten?
    define(["jquery"], function($) {
      // $ is guaranteed to be jQuery now */
    })
    
  2. jQuery zaten herhangi önce yüklenen require()veya define()malzeme. Tüm modüller jQuery'nin hazır olduğu garantilidir. require/order.jsEklentiye bile ihtiyacınız yok çünkü jQuery temelde ilk olarak yüklenmek üzere sabit kodlandı.

Bana göre # 2 pek yardımcı olmuyor. Çoğu gerçek uygulamalar var birçok .js dosya olmalıdır doğru sırayla-acı ama gerçek yüklüyoruz. Sammy veya Underscore.js'ye ihtiyacınız olduğu anda, birleştirilmiş RequireJS + jQuery dosyası yardımcı olmaz.

Benim çözümüm, "order" eklentisini kullanarak geleneksel komut dosyalarımı yükleyen basit RequireJS paketleyicileri yazmaktır.

Misal

Uygulamamın bu bileşenlere sahip olduğunu varsayalım (bağımlılığa göre).

  • Benim uygulamam, harika uygulama
    • greatapp özel bağlıdır jquery (ı kullanmalıdır eski sürüm)
    • greatapp bağlıdır my_sammy (SammyJS artı kullanmalıdır tüm eklentileri). Bunlar sırayla olmalı
      1. my_sammy bağlıdır Jquery (SammyJS bir jQuery eklentisi olan)
      2. my_sammy, sammy.js'ye bağlıdır
      3. my_sammy, sammy.json.js'ye bağlıdır
      4. my_sammy, sammy.storage.js'ye bağlıdır
      5. my_sammy, sammy.mustache.js'ye bağlıdır

Bence yukarıdaki ile biten her şey .js"geleneksel" bir yazı. Olmayan her şey .jsbir RequireJS eklentisidir. Anahtar şudur: üst düzey öğeler (harika uygulama, my_sammy) modüllerdir ve daha derin düzeylerde, geleneksel .jsdosyalara geri döner .

Önyükleme

Her şey, RequireJS'e nasıl başlayacağını söyleyen bir destekçiyle başlar.

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

Sadece js/boot.jsyapılandırmayı ve uygulamayı nasıl başlatacağımı koydum.

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

Ana uygulama

İçinde greatapp.jsnormal görünümlü bir modülüm var.

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

Geleneksel dosyaların etrafında JS modül sarmalayıcıları gerektir

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
Bu cevap üzerinde iyi iş çıkardınız ... umarım soru soran bunu işaretler!
Mahkum SIFIR

gerçek jquery dosyasına bağlı olarak bir require_jquery modülü oluşturuyorsunuz, ancak jquery global kalmıyor mu? özel yoldan yüklediğiniz gerçek jquery dosyası 1.4.2 bir require.js modülü değil mi? yoksa bu dosyayı da sarmaladınız mı?
Sander

3
JQuery'nin (1.7) en son sürümüyle zaten modülleri desteklediğini ve bu nedenle yapmanız gereken tek şeyin normal olarak bunu gerektirdiğini ve işe yarayacağını belirtmek isterim.
MikeMurko

1
AMD'yi destekleyen JS 2 (w / shim) + jQuery 1.7+ gereksinimlerini yansıtmak için birisi bu yanıtı güncelleyebilir mi?
Henry

1
AMD olmayan javascript dosyalarıyla bağımlılık desteği sağlamanın en iyi yolunun artık RequireJS 2.0+ içinde bulunan shim yapılandırması olduğunu belirtmek isterim. Hala Require 1.x kullanıyorsanız, pulun öncüsünü kullanabilirsiniz. , wrapjs
Johann

32

Bu soru şu anda en az iki yaşında, ancak bunun hala RequireJS 2.0 ile ilgili bir sorun olduğunu fark ettim (required-jquery.js jQuery 1.8.0 kullanıyor, ancak en son sürüm 1.8.2).

Bu soruyu görürseniz, require-jquery.js'nin artık sadece require.js ve jquery.js'nin birlikte karıştırıldığını unutmayın. Yalnızca require-jquery.js'yi düzenleyebilir ve jQuery parçalarını daha yeni bir sürümle değiştirebilirsiniz .

Güncelleme (30 Mayıs 2013) : RequireJS'de artık yollar ve şim var, jQuery ve jQuery eklentilerini içe aktarmanın yeni bir yolu var ve eski yöntem artık gerekli değil ve önerilmiyor . İşte mevcut yöntemin kısaltılmış bir versiyonu:

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

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

Daha fazla bilgi için http://requirejs.org/docs/jquery.html adresine bakın .


Teşekkürler, bu hala geçerli :)
Naor

Hala jQuery 1.3.8 kullanıyor musunuz? :)
Chris

Bunu işaret ettiğiniz için teşekkür ederim. 1.8'in eski bir sürümünün en son çözülen sorunları olduğunu okudum.
Blaine Mucklow

Aslında. CurCSS ile jQueryUI sorunları değildi, değil mi?
Chris

1
@AHMED: İkisi de çalışıyor. Aradaki fark, tanımlamanın açıkça bir modülü belirtmesidir. Yollar hakkında daha açık olduğu için neredeyse sadece define kullanmayı tercih ediyorum: stackoverflow.com/questions/16087635/…
Chris

9

En iyi yaklaşımın jQuery'yi RequireJS yapımın dışında tutmak olduğunu buldum.

HTML'nize jquery.min.js eklemeniz yeterlidir. Ardından, bunun gibi bir jquery.js dosyası oluşturun ...

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

Komut dosyası etiketleri kullanılarak geleneksel olarak yüklenmesi gereken bazı JS dosyalarım olduğu ve bunlar jQuery'ye bağlı oldukları için bu iyi bir çözümdür.
jingtao

3

JasonSmith'in cevabını muazzam derecede yararlı buldu, muhtemelen RequireJS'nin belgelerinden daha fazla.

Ancak, (küçük) tanımlama-tanımlayıcı modüller için ayrı AJAX isteklerinden kaçınmak için optimizasyon yapmanın bir yolu vardır ("require_jquery" "require_sammy"). R.js'nin bunu optimizasyon aşamasında yapacağından şüpheleniyorum, ancak Path, BaseURI sistemi ile savaşmamak için bunu önceden yapabilirsiniz.

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

son olarak 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
    }
})

Bu yapı (gevşek bir şekilde değiştirilir (yinelenir?) RequireJS's Order eklentisi, ancak) AJAX'a ihtiyacınız olan dosya sayısını azaltmanıza, bağımlı ve bağımlı ağaç tanımına daha fazla kontrol eklemenize izin verir.

Ayrıca jQuery'yi ayrı olarak yüklemenin büyük bir avantajı da vardır (ki bu genellikle 100k'de gelir) - sunucuda önbelleğe almayı kontrol edebilir veya jQuery'yi tarayıcının localStorage'ına önbelleğe alabilirsiniz. AMD-Cache projesine buradan https://github.com/jensarps/AMD-cache bir göz atın ve ardından tanımlamayı (ifadeleri "önbellek!" İçerecek şekilde değiştirin: ve kullanıcının tarayıcısında (sonsuza kadar :)) sıkışacaktır.

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 + hakkında not Artık kendisini pencere nesnesine bağlamaz, bu nedenle yukarıdakiler değiştirilmemiş jQuery 1.7.x + dosyasıyla çalışmayacaktır. Burada jquery **. Js'nizi "}) (pencere);" kapanışından önce bunu içerecek şekilde özelleştirmelisiniz:

;window.jQuery=window.$=jQuery

Konsolda "jQuery tanımsız" hatalarınız varsa, bu kullandığınız jQuery sürümünün kendisini pencereye eklemediğinin bir işaretidir.

Kod lisansı: Kamu malı.

Açıklamalar: Yukarıdaki JavaScript, çok daha ayrıntılı üretim kodunun başka bir deyişle (elle budama) olması nedeniyle "sözde kod" kokuyor. Yukarıda sunulduğu şekliyle kodun çalışması garanti edilmez ve sunulduğu gibi çalıştığı test EDİLMEMİŞTİR. Denetim, test et. JS spesifikasyonuna göre gerekli olmadıklarından ve kodlar olmadan daha iyi göründüğünden noktalı virgül bilerek ihmal edilir.


RequireJS ile kavga ettikten sonra (düzensiz yüklenen, tanımlamaya uymayan, iç içe geçmeyi gerektiren, diğer sihirli yanlış davranışlar) Curl.JS'ye geçti ve geceleri iyi uyumaya başladı. O kadar abartılı değil, ama kahretsin, kararlı ve çalışması kolay!
ddotsenko

1

Jhs'in cevabına ek olarak , README.md dosyasındaki required -jquery github sayfasındaki daha yeni talimatlara bakın . Hem birleşik bir jquery / require.js dosyası kullanmanın en basit yaklaşımını hem de ayrı bir jquery.js'nin nasıl kullanılacağını kapsar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.