Requirejs perché e quando usare shim config


97

Ho letto il documento requirejs da qui API

requirejs.config({
    shim: {
        'backbone': {
            //These script dependencies should be loaded before loading
            //backbone.js
            deps: ['underscore', 'jquery'],
            //Once loaded, use the global 'Backbone' as the
            //module value.
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        },
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                //Using a function allows you to call noConflict for
                //libraries that support it, and do other cleanup.
                //However, plugins for those libraries may still want
                //a global. "this" for the function will be the global
                //object. The dependencies will be passed in as
                //function arguments. If this function returns a value,
                //then that value is used as the module export value
                //instead of the object found via the 'exports' string.
                return this.Foo.noConflict();
            }
        }
    }
});

ma non ne ricevo una parte. perché dovrei usare shim e come dovrei configurarlo, posso ottenere qualche chiarimento in più

per favore qualcuno può spiegare con un esempio perché e quando dovremmo usare shim. Grazie.

Risposte:


110

Un utilizzo principale di shim è con le librerie che non supportano AMD, ma è necessario gestirne le dipendenze. Ad esempio, nell'esempio Backbone e Underscore sopra: sai che Backbone richiede Underscore, quindi supponi di aver scritto il tuo codice in questo modo:

require(['underscore', 'backbone']
, function( Underscore, Backbone ) {

    // do something with Backbone

}

RequireJS avvierà richieste asincrone sia per Underscore che per Backbone, ma non sai quale tornerà per primo, quindi è possibile che Backbone provi a fare qualcosa con Underscore prima che venga caricato.

NOTA: questo esempio di sottolineatura / backbone è stato scritto prima che entrambe le librerie supportassero AMD. Ma il principio vale per tutte le librerie odierne che non supportano AMD.

L'hook "init" ti permette di fare altre cose avanzate, ad esempio se una libreria normalmente esporta due cose diverse nello spazio dei nomi globale ma vuoi ridefinirle sotto un unico spazio dei nomi. O forse vuoi fare delle patch scimmie su un metodo nella libreria che stai caricando.

Più background:


Come il tuo codice di esempio, Underscoree Backbonequi usano come al solito, cosa shimfare in questo caso? Posso usare require( function() { _.extend({}); })? Capisce _?
Stiger

"RequireJS darà il via alle richieste asincrone sia per Underscore che per Backbone" -> È possibile impedirlo, nel caso in cui la libreria sia già caricata?
Codii

1
@Codii giusto, se la libreria è già caricata non darà il via a un'altra richiesta del server, ma il punto di RequireJS è che il tuo codice non ha bisogno di preoccuparsi di se / come ciò accade. Forse iniziare una nuova domanda per il tuo caso d'uso particolare?
Explunit

63

Come da documentazione API RequireJS, shim te lo consente

Configurare le dipendenze, le esportazioni e l'inizializzazione personalizzata per gli script "browser globali" più vecchi e tradizionali che non utilizzano define () per dichiarare le dipendenze e impostare un valore di modulo.

- Configurazione delle dipendenze

Supponiamo che tu abbia 2 moduli javascript (moduleA e moduleB) e uno di essi (moduleA) dipende dall'altro (moduleB). Entrambi sono necessari per il tuo modulo, quindi specifichi le dipendenze in require () o define ()

require(['moduleA','moduleB'],function(A,B ) {
    ...
}

Ma dal momento che richiedono esso stesso seguire AMD, non hai idea di quale verrebbe recuperato in anticipo. È qui che Shim viene in soccorso.

require.config({
    shim:{
       moduleA:{
         deps:['moduleB']
        } 
    }

})

Ciò assicurerebbe che il moduloB venga sempre recuperato prima che venga caricato il moduloA.

- Configurazione delle esportazioni

Shim export dice a RequireJS quale membro sull'oggetto globale (la finestra, supponendo che tu sia in un browser, ovviamente) è il valore effettivo del modulo. Diciamo che moduleA si aggiunge a window'modA' (proprio come jQuery e underscore fanno rispettivamente $ e _), quindi rendiamo il valore delle nostre esportazioni 'modA'.

require.config({
    shim:{
       moduleA:{
         exports:'modA'
        } 
    }

Fornirà a RequireJS un riferimento locale a questo modulo. Anche il modA globale esisterà ancora nella pagina.

-Inizializzazione personalizzata per vecchi script "browser global"

Questa è probabilmente la caratteristica più importante di shim config che ci permette di aggiungere script "browser global", "non-AMD" (che non seguono neppure il modello modulare) come dipendenze nel nostro modulo.

Diciamo che moduleB è un semplice vecchio javascript con solo due funzioni funcA () e funcB ().

function funcA(){
    console.log("this is function A")
}
function funcB(){
    console.log("this is function B")
}

Sebbene entrambe queste funzioni siano disponibili nell'ambito della finestra, RequireJS ci consiglia di usarle attraverso il loro identificatore / handle globale per evitare confusioni. Quindi configurando lo spessore come

shim: {
    moduleB: {
        deps: ["jquery"],
        exports: "funcB",
        init: function () {
            return {
                funcA: funcA,
                funcB: funcB
            };
        }
    }
}

Il valore di ritorno dalla funzione init viene utilizzato come valore di esportazione del modulo invece dell'oggetto trovato tramite la stringa "export". Questo ci permetterà di usare funcB nel nostro modulo come

require(["moduleA","moduleB"], function(A, B){
    B.funcB()
})

Spero che questo abbia aiutato.


3
Facile da capire! Una domanda: nell'ultimo esempio, la proprietà "export" è semplicemente ignorata?
Niko Bellic

No, non viene ignorato. Se la proprietà "export" fosse stata ignorata nell'ultimo esempio, l'oggetto passato come parametro ('B' in questo caso) non sarebbe stato definito poiché il moduloB NON è conforme ad AMD e non avrebbe restituito un oggetto da utilizzare per RequireJS ( quindi "B.funcB" non funzionerebbe).
nalinc

Hmm. Ho pensato che il valore dell'esportazione sarebbe stato sovrascritto dall'oggetto restituito nella funzione init. Quindi il parametro B sarebbe l'oggetto {funcA: funcA, funcB: funcB}, non semplicemente funcB da solo. Non è vero?
Niko Bellic

4
Niko Bellic ha ragione, l'esportazione è ignorata (l'ho appena testato). L'oggetto B è l'oggetto restituito dalla funzione specificata nella parte "init". Se rimuovessi la parte 'init', l'oggetto B diventerebbe la funzione funcB, quindi dovresti semplicemente fare B () invece di B.funcB (). E ovviamente in quel caso funcA diventerebbe inaccessibile.
user4205580

-2

È necessario aggiungere percorsi in requirejs.config per dichiarare, ad esempio:

requirejs.config({
    paths: {
          'underscore' : '.../example/XX.js' // your JavaScript file
          'jquery' : '.../example/jquery.js' // your JavaScript file
    }
    shim: {
        'backbone': {
            deps: ['underscore', 'jquery'],
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        },
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                return this.Foo.noConflict();
            }
        }
    }
});

1
Questa risposta è un dump del codice che non spiega "perché e quando usare shim config". Se modifichi la tua risposta per fornire una spiegazione, assicurati di aggiungere qualcosa di nuovo, che non è già coperto dalle risposte precedenti
Louis

copia incolla senza feedback positivo
william.eyidi

dovrebbe essere una virgola prima dello spessore:
Scott
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.