Requirejs pourquoi et quand utiliser shim config

97

J'ai lu le document requirejs à partir d'ici 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();
            }
        }
    }
});

mais je ne reçois pas shim partie. pourquoi dois-je utiliser shim et comment dois-je configurer, puis-je obtenir plus de précisions

s'il vous plaît, quelqu'un peut-il expliquer avec un exemple pourquoi et quand devrions-nous utiliser shim. Merci.

Anil Gupta
la source

Réponses:

110

Une utilisation principale de shim est avec les bibliothèques qui ne prennent pas en charge AMD, mais vous devez gérer leurs dépendances. Par exemple, dans l'exemple de Backbone et Underscore ci-dessus: vous savez que Backbone nécessite Underscore, alors supposons que vous ayez écrit votre code comme ceci:

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

    // do something with Backbone

}

RequireJS lancera des requêtes asynchrones pour Underscore et Backbone, mais vous ne savez pas lequel reviendra en premier , il est donc possible que Backbone essaie de faire quelque chose avec Underscore avant qu'il ne soit chargé.

REMARQUE: cet exemple de soulignement / d'épine dorsale a été écrit avant que ces deux bibliothèques ne prennent en charge AMD. Mais le principe est vrai pour toutes les bibliothèques d'aujourd'hui qui ne prennent pas en charge AMD.

Le hook "init" vous permet de faire d'autres choses avancées, par exemple si une bibliothèque exporte normalement deux choses différentes dans l'espace de noms global mais que vous voulez les redéfinir sous un seul espace de noms. Ou peut-être voulez-vous faire quelques correctifs de singe sur une méthode de la bibliothèque que vous chargez.

Plus de fond:

explunit
la source
Comme votre exemple de code, le Underscoreet Backboneici utilisez comme d'habitude, que shimfaire dans ce cas? Puis-je utiliser require( function() { _.extend({}); })? Comprend-il _?
Stiger
"RequireJS lancera les requêtes asynchrones pour les deux Underscore et Backbone" -> Est-il possible d'empêcher cela, dans le cas où la bibliothèque est déjà chargée?
Codii
1
@Codii à droite, si la bibliothèque est déjà chargée, elle ne lancera pas une autre requête de serveur, mais le point de RequireJS est que votre code n'a pas besoin de se soucier de si / comment cela se produit. Peut-être commencer une nouvelle question pour votre cas d'utilisation particulier?
explunit
63

Conformément à la documentation de l'API RequireJS, shim vous permet

Configurez les dépendances, les exportations et l'initialisation personnalisée pour les scripts "globaux de navigateur" plus anciens et traditionnels qui n'utilisent pas define () pour déclarer les dépendances et définir une valeur de module.

- Configuration des dépendances

Disons que vous avez 2 modules javascript (moduleA et moduleB) et l'un d'eux (moduleA) dépend de l'autre (moduleB). Les deux sont nécessaires pour votre propre module, vous spécifiez donc les dépendances dans require () ou define ()

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

Mais comme il doit suivre AMD, vous ne savez pas lequel serait récupéré tôt. C'est là que Shim vient à la rescousse.

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

})

Cela garantirait que moduleB est toujours récupéré avant le chargement de moduleA.

- Configuration des exportations

L'exportation Shim indique à RequireJS quel membre de l'objet global (la fenêtre, en supposant que vous êtes dans un navigateur, bien sûr) est la valeur réelle du module. Disons que moduleA s'ajoute au windowas 'modA' (tout comme jQuery et le soulignement le font respectivement pour $ et _), alors nous rendons nos exportations valeur 'modA'.

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

Cela donnera à RequireJS une référence locale à ce module. Le modA global existera également sur la page.

-Initialisation personnalisée pour les anciens scripts "globaux du navigateur"

C'est probablement la caractéristique la plus importante de shim config qui nous permet d'ajouter des scripts «globaux de navigateur», «non-AMD» (qui ne suivent pas non plus le modèle modulaire) comme dépendances dans notre propre module.

Disons que moduleB est un javascript simple avec seulement deux fonctions funcA () et funcB ().

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

Bien que ces deux fonctions soient disponibles dans la portée de la fenêtre, RequireJS nous recommande de les utiliser via leur identifiant / handle global pour éviter les confusions. Donc, configurer la cale comme

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

La valeur de retour de la fonction init est utilisée comme valeur d'exportation du module au lieu de l'objet trouvé via la chaîne 'exports'. Cela nous permettra d'utiliser funcB dans notre propre module comme

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

J'espère que cela a aidé.

nalinc
la source
3
Facile à comprendre! Une question: dans le dernier exemple, la propriété "exports" est-elle simplement ignorée?
Niko Bellic
Non, ce n'est pas ignoré. Si la propriété "exports" avait été ignorée dans le dernier exemple, alors l'objet que vous transmettez en tant que paramètre ('B' dans ce cas) serait indéfini car moduleB n'est PAS compatible AMD et n'aurait pas renvoyé un objet à utiliser par RequireJS ( par conséquent 'B.funcB' ne fonctionnerait pas).
nalinc
Hmm. Je pensais que la valeur de l'exportation serait remplacée par l'objet retourné dans la fonction init. Ainsi, le paramètre B serait l'objet {funcA: funcA, funcB: funcB}, pas simplement funcB en lui-même. N'est-ce pas vrai?
Niko Bellic
4
Niko Bellic a raison, l'exportation est ignorée (je viens de tester ça). L'objet B est l'objet retourné par la fonction spécifiée dans la partie 'init'. Si vous supprimiez la partie 'init', l'objet B deviendrait la fonction funcB, vous feriez donc simplement B () au lieu de B.funcB (). Et évidemment funcA deviendrait inaccessible dans ce cas.
user4205580
-2

Vous devez ajouter des chemins dans requirejs.config pour déclarer, par exemple:

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();
            }
        }
    }
});
Rachman Anwar
la source
1
Cette réponse est un vidage de code qui ne fait rien pour expliquer "pourquoi et quand utiliser shim config". Si vous modifiez votre réponse pour fournir une explication, assurez-vous d'ajouter quelque chose de nouveau, qui n'est pas déjà couvert par les réponses précédentes
Louis
copier coller sans commentaires positifs
william.eyidi
devrait être une virgule avant le shim:
Scott