2012-11-14 16 views
37

Il RequireJS docs afferma che per supportare versioni precedenti di IE, è necessario configurare enforceDefine: true.Bootstrap Twitter Shim per RequireJS

Quindi, se si desidera supportare Internet Explorer, errori di caricamento di cattura, e hanno il codice modulare sia attraverso diretta define() chiama o spessore di configurazione, impostare sempre enforceDefine per essere vero. Vedi la prossima sezione per un esempio.

NOTA: Se si imposta enforceDefine: true, e si utilizza data-main = "" per caricare il modulo JS principale, allora quel modulo JS principale deve chiamare define() invece di require() per caricare il codice esigenze. Il modulo JS principale può ancora chiamare require/requirejs per impostare i valori di configurazione, ma per caricare i moduli dovrebbe usare define().

Dal momento che Twitter Bootstrap non è un modulo AMD, ho bisogno di spingerlo per farlo funzionare. Ecco come lo configuro;

<script type="text/javascript"> 
    var require = { 
     paths: { 
      "bootstrap": "../bootstrap", 
      "jquery": "../jquery-1.8.2" 
     }, 
     shim: { 
      "bootstrap": ["jquery"] 
     }, 
     enforceDefine: true 
    }; 
</script> 

Più tardi, quando il mio modulo vuole bootstrap come una dipendenza, ho ancora finire con un messaggio di errore;

Error: No define call for bootstrap 

http://requirejs.org/docs/errors.html#nodefine

Se ho capito bene la documentazione, enforceDefine dovrebbe ignorare spessori ma non lo è.

Cosa sto facendo di sbagliato qui?

risposta

37

In base ai documenti che viene generato un errore se "Script faceva parte di una configurazione di shim che specificava una proprietà di stringa globale che può essere verificata per il caricamento e che il controllo non è riuscito."

Per risolvere questo problema è necessario aggiungere valore di esportazione nella configurazione shim in modo che RequireJS possa verificare se lo script è stato caricato correttamente. Nel caso di Bootstrap che è un po 'complicato in quanto Bootstrap non "esporta" una variabile globale propert solo un gruppo di plugin jquery, ma puoi usare uno qualsiasi di questi plugin come valore di esportazione, ad es. $.fn.popover:

{ 
    paths: { 
     "bootstrap": "../bootstrap", 
     "jquery": "../jquery-1.8.2" 
    }, 
    shim: { 
     "bootstrap": { 
      deps: ["jquery"], 
      exports: "$.fn.popover" 
     } 
    }, 
    enforceDefine: true 
} 
+2

Per quelli di noi nuovi a JS, come useresti il ​​popover nel tuo codice? Con require posso dire "var $ = require ('jquery') dovrei scrivere" var popover = require ("$. Fn.popover")? – KingAndrew

+1

No. Il comando richiede il percorso del modulo nel file system come argomento. In questo caso puoi solo richiedere ("bootstrap") e poi usarlo solo $ ("# esempio"). Popover(). Potresti richiedere singoli plug-in di bootstrap se utilizzi le versioni nononcatenate, ma ciò richiederebbe una maggiore configurazione. In generale i plugin jQuery che si collegano a $ .fn non sono molto compatibili con la filosofia del modulo CJS/AMD. – Karolis

+1

E se fosse necessario accedere a più plug-in? C'è un modo per avere più esportazioni con requirejs? o avresti più shim per ogni plugin? o qualcos'altro? –

14

Invece di fare la magia con spessore, ho convertito il bootstrap JS in un modulo:

define([ "jquery" ], function($) { 
    // bootstrap JS code 
}); 

Tutto il resto ho trovato nei forum e su StackOverflow non ha funzionato per me perché io ottenere jQuery dal CDN. Presumo perché ho riscontrato il problema come descritto nel documento requireJS su http://requirejs.org/docs/api.html

Non mescolare il caricamento del CDN con lo shim config in una build. Scenario di esempio: si carica jQuery dal CDN ma si utilizza la configurazione shim per caricare qualcosa come la versione di riserva di Backbone che dipende da jQuery. Quando esegui il build , assicurati di inserire jQuery nel file creato e non caricare dal CDN. In caso contrario, Backbone verrà inserito nel file creato e verrà eseguito prima del caricamento di jQuery caricato da CDN. Questo è perché la configurazione dello shim ritarda solo il caricamento dei file fino a quando non vengono caricate le dipendenze , ma non viene eseguito alcun auto-wrapping di define. Dopo una compilazione, le dipendenze sono già in linea, la configurazione dello shim non può ritardare l'esecuzione del codice d non-define() fino a più tardi. define() 'i moduli funzionano con il codice caricato CDN dopo una compilazione perché avvolgono correttamente la loro origine in definire la funzione di fabbrica che sarà non eseguita fino a quando non vengono caricate le dipendenze. Quindi la lezione: shim config è una misura stop-gap per codice non modulare, codice legacy. define() 'd i moduli sono migliori.

Conversione del bootstrap in un modulo AMD ordinario e rimozione dello shim config risolto per me. Unico inconveniente: non è possibile recuperare il bootstrap dal CDN di bootstrap.

+0

Quindi probabilmente è meglio non usare il bootstrap CDN poiché non ti permette di eseguire il Closure Compiler per eliminare le funzioni inutilizzate, ecc. –

+0

Nota, la versione corrente di Bootstrap 3 fa riferimento a jQuery not $, quindi ora hai effettivamente per passare in: 'define ('bootstrap', ['jquery'], function (jQuery) {' –

11

Io uso questa configurazione all'interno del mio progetto:

startup.js

require.config({ 
    paths: { 
     /* other paths are omitted */ 
     'bootstrap': '../libs/bootstrap' 
    }, 
    shim: { 
     'bootstrap/bootstrap-slider': { deps: ['jquery'], exports: '$.fn.slider' }, 
     'bootstrap/bootstrap-affix': { deps: ['jquery'], exports: '$.fn.affix' }, 
     'bootstrap/bootstrap-alert': { deps: ['jquery'], exports: '$.fn.alert' }, 
     'bootstrap/bootstrap-button': { deps: ['jquery'], exports: '$.fn.button' }, 
     'bootstrap/bootstrap-carousel': { deps: ['jquery'], exports: '$.fn.carousel' }, 
     'bootstrap/bootstrap-collapse': { deps: ['jquery'], exports: '$.fn.collapse' }, 
     'bootstrap/bootstrap-dropdown': { deps: ['jquery'], exports: '$.fn.dropdown' }, 
     'bootstrap/bootstrap-modal': { deps: ['jquery'], exports: '$.fn.modal' }, 
     'bootstrap/bootstrap-popover': { deps: ['jquery'], exports: '$.fn.popover' }, 
     'bootstrap/bootstrap-scrollspy': { deps: ['jquery'], exports: '$.fn.scrollspy'  }, 
     'bootstrap/bootstrap-tab': { deps: ['jquery'], exports: '$.fn.tab' }, 
     'bootstrap/bootstrap-tooltip': { deps: ['jquery'], exports: '$.fn.tooltip' }, 
     'bootstrap/bootstrap-transition': { deps: ['jquery'], exports: '$.support.transition' }, 
     'bootstrap/bootstrap-typeahead': { deps: ['jquery'], exports: '$.fn.typeahead' }, 
    } 
}); 

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

poi nel mio codice Io uso questo:

define(['jquery', 'underscore', 'backbone', 'text!templates/photos-list.html'], function($, _, Backbone, html) { 
    var PhotosListView = Backbone.View.extend({ 
     viewImageFullscreen: function(e) { 
      e.preventDefault(); 

      require(['bootstrap/bootstrap-modal', 'text!templates/photo-modal.html'], function(modal, htmlModal) { 
       var modalTemplate = _.template(htmlModal, options); 
       $('body').append(modalTemplate); 

       // setup 
       $(selector + '_modal').modal({ 
        backdrop: true, 
        keyboard: true, 
        show: false 
       }).css({ 
        'width': function() { return ($(document).width() * 0.55) + 'px'; }, 
        'margin-left': function() { return -($(this).width() * 0.5); } 
       }); 

       // trigger `modal` 
       $(selector + '_modal').modal('show'); 
      }); // require() call 
     // ... 
+2

Mi piace questo approccio, ecco gli shim aggiornati per bootstrap 3 - https://gist.github.com/benfoxall/ 8844292 – benjaminbenben

+0

@benjaminbenben recentemente ho trovato questa risorsa interessante: http://matznermatzner.de/en/bernd/2013/11/loading-non-amd-modules-requirejs-part-1-jquery-ui – lexeme

+0

e questo : http://matznermatzner.de/en/bernd/2013/12/loading-non-amd-modules-requirejs-part-2-zurb-foundation – lexeme

4

@lexeme & @benjaminbenben come su avvolgere questo concetto in un plug-in RequireJS che crea lo shim, richiede jQuery e restituisce anche jQuery in modo che tu non voglia Non è necessario includerlo manualmente?

Per utilizzare un componente di bootstrap si dovrebbe semplicemente usare:

define(['bootstrap!tooltip'], function($){ 
    $('[data-toggle="tooltip"]').tooltip(); 
}); 

e si dovrebbe utilizzare questo require-bootstrap-plugin per farlo funzionare.

+0

Questo è piuttosto lucido. Tuttavia, fare attenzione perché se un plugin ha dipendenze, questo non funzionerà.Ad esempio, popover richiede tooltip. –