Comment rendre un plugin jQuery chargeable avec requirejs

88

Je travaille avec requirejs + jquery et je me demandais s'il y avait un moyen intelligent de faire fonctionner correctement un plugin jQuery avec require.

Par exemple, j'utilise jQuery-cookie. Si j'ai bien compris, je peux créer un fichier appelé jquery-cookie.js et à l'intérieur faire

define(["jquery"], // Require jquery
       function($){
// Put here the plugin code. 
// No need to return anything as we are augmenting the jQuery object
});
requirejs.config( {
    "shim": {
        "jquery-cookie"  : ["jquery"]
    }
} );

Je me suis demandé si je pouvais faire des choses comme jQuery, ce qui est comme ceci:

if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
    define( "jquery", [], function () { return jQuery; } );
}

ou si c'est le seul moyen de rendre les plugins jQuery compatibles avec requirejs ou tout amd

Nicola Peluchetti
la source

Réponses:

67

Vous avez seulement besoin de faire SOIT

define(["jquery"], // Require jquery
       function($){
// Put here the plugin code. 
// No need to return anything as we are augmenting the jQuery object
});

à la fin de jquery-cookie.js, OU

requirejs.config( {
    "shim": {
        "jquery-cookie"  : ["jquery"]
    }
} );

n'importe où avant d'inclure jquery-cookie (comme partout où pointe data-main, par exemple).

Le dernier bloc de code que vous avez publié est bon pour des choses comme jQuery qui sont redistribuées et peuvent ou non être dans un environnement AMD. Idéalement, chaque plugin jQuery l'aurait déjà configuré.

Je préfère garder les bibliothèques incluses aussi intactes que possible, donc la configuration globale du shim une fois par page me semble être la solution la plus propre . De cette façon, les mises à niveau sont plus sûres et les CDN deviennent une possibilité.

Hans
la source
1
Si je ne fais pas à la fois la définition et le shim, les choses ne fonctionnent pas, j'obtiens un message d'erreur $ .cookie is not a function
Nicola Peluchetti
D'après mon expérience, ne rien renvoyer de la fonction de définition n'est pas suffisant, requirejs ne reconnaîtra pas que le module est chargé. Cela peut être réveillé par shim: {plugins: {depend: ['jquery'], exports: 'plugins'}
honzajde
Vous devez noter que le script du plugin jQuery doit réellement s'exécuter. Je ne suis pas un expert, mais j'ai trouvé une solution simple où vous en avez un, require(['plugin1', 'plugin2']);etc. Aucun rappel n'est passé, donc rien ne fonctionnera sauf les scripts du plugin eux-mêmes. Cela signifie qu'ils s'ajouteront jQuery.fnalors partout ailleurs, vous pouvez simplement lister 'jquery' comme dépendance et ils seront inclus. Comme je l'ai dit, je suis assez nouveau dans ce domaine et il peut y avoir une meilleure approche (comme utiliser simplement une scriptbalise), mais cela fonctionne.
Joshua Bambrick
3
Josh: Vous pariez que tout va se charger dans le bon ordre. Certains utilisateurs de votre site voient probablement des éléments défectueux. Le problème n'est pas tant que le plugin se charge, c'est quand le plugin se charge et quoi d'autre s'exécute à ce moment-là. La principale raison d'utiliser require est d'assurer un ordre raisonnable des opérations basé sur des dépendances plutôt que sur des suppositions.
Hans
104

Il y a quelques mises en garde avec l'utilisation de la configuration shim dans RequireJS, soulignées sur http://requirejs.org/docs/api.html#config-shim . À savoir, "Ne mélangez pas le chargement CDN avec la configuration de shim dans une construction" lorsque vous utilisez l'optimiseur.

Je cherchais un moyen d'utiliser le même code de plugin jQuery sur les sites avec et sans RequireJS. J'ai trouvé cet extrait de code pour les plugins jQuery sur https://github.com/umdjs/umd/blob/master/jqueryPlugin.js . Vous enveloppez votre plugin dans ce code, et cela fonctionnera correctement dans les deux cas.

(function (factory) {
if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module depending on jQuery.
    define(['jquery'], factory);
} else {
    // No AMD. Register plugin with global jQuery object.
    factory(jQuery);
}
}(function ($) {

    $.fn.yourjQueryPlugin = function () {
        // Put your plugin code here
    };  

}));

Le crédit revient à jrburke; comme beaucoup de javascript, ce sont des fonctions à l'intérieur de fonctions agissant sur d'autres fonctions. Mais je pense avoir déballé ce qu'il fait.

L'argument de fonction factorydans la première ligne est lui-même une fonction qui est appelée pour définir le plugin sur l' $argument. Lorsqu'aucun chargeur compatible AMD n'est présent, il est appelé directement pour définir le plugin sur l' jQueryobjet global . C'est exactement comme l'idiome de définition de plugin commun:

function($)
{
  $.fn.yourjQueryPlugin = function() {
    // Plugin code here
  };
}(jQuery);

S'il existe un chargeur de module, alors factoryest enregistré comme rappel que le chargeur doit appeler après le chargement de jQuery. La copie chargée de jQuery est l'argument. C'est équivalent à

define(['jquery'], function($) {
  $.fn.yourjQueryPlugin = function() {
     // Plugin code here
  };
})
Carl Raymond
la source
3
J'aime cette réponse car même si la question portait sur un plugin jQuery, cela fonctionne pour tout type de module ou de bibliothèque, pas seulement jQuery. Il m'a fallu une minute pour comprendre votre code, mais une fois que je l'ai fait, c'était parfaitement logique.
Adam Tuttle
1
C'est définitivement du javascript impénétrable. J'ai ajouté quelques explications sur son fonctionnement.
Carl Raymond
Des conseils sur la façon de faire cela et de créer un plugin qui fonctionne avec jQuery ou Zepto? Vous pouvez facilement remplacer le code non AMD par factory(jQuery || Zepto);, mais je ne sais pas comment vous feriez la partie AMD. Je pense que vous devriez définir le "chemin" jQuery sur zepto ?? paths: { jquery: 'vendor/zepto/zepto.min' }
Ryan Wheale
wow, je voulais depuis longtemps comprendre cet extrait de code. Merci beaucoup, n'est-ce pas shimessentiellement cela? Je suppose que non ... parce que vous avez dit que vous le codez manuellement comme ci-dessus.
eugene
Protip pour les idiots comme moi: là où il est dit $.fn.jqueryPlugindans l'extrait, changez jqueryPluginle nom du plugin !!
Matt Lacey
2

Tout comme pour info, tous les plugins jquery utilisent déjà amd / require, vous n'avez donc rien à déclarer dans le shim. En fait, cela pourrait vous causer des problèmes dans certains cas.

Si vous regardez dans le cookie jquery JS, vous verrez définir les appels et require (["jquery"]).

et dans jquery.js, vous verrez un appel à define ("jquery", [], function () ...

TPEACHES
la source