Cómo hacer que un complemento de jQuery se pueda cargar con requirejs

88

Estoy trabajando con requirejs + jquery y me preguntaba si había una forma inteligente de hacer que un complemento de jQuery funcionara bien con require.

Por ejemplo, estoy usando jQuery-cookie. Si entendí correctamente, puedo crear un archivo llamado jquery-cookie.js y dentro

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"]
    }
} );

Me preguntaba si podría hacer cosas como jQuery, que es así:

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

o si esta es la única forma de hacer que los complementos de jQuery sean compatibles con requirejs o cualquier amd

Nicola Peluchetti
fuente

Respuestas:

67

Solo necesitas hacer CUALQUIER

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

al final de jquery-cookie.js, O

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

en cualquier lugar antes de incluir jquery-cookie (como donde apuntan los datos principales, por ejemplo).

El último bloque de código que ha publicado es bueno para cosas como jQuery que se redistribuyen y pueden o no estar en un entorno AMD. Idealmente, todos los complementos de jQuery ya lo tendrían configurado.

Prefiero mantener las bibliotecas incluidas lo más sin adulterar posible, por lo que la configuración de corrección global una vez por página me parece la solución más limpia . De esa manera, las actualizaciones son más seguras y las CDN se convierten en una posibilidad.

Hans
fuente
1
Si no hago tanto la definición como la corrección, las cosas no funcionan, obtengo un mensaje de error de $ .cookie no es una función
Nicola Peluchetti
En mi experiencia, no devolver nada de la función de definición no es suficiente, requirejs no reconocerá que el módulo se cargó. Esto se puede solucionar con shim: {plugins: {depende: ['jquery'], exportaciones: 'plugins'}
honzajde
Debe tener en cuenta que el script del complemento jQuery debe ejecutarse realmente. No soy un experto, pero encontré una solución sencilla mediante la cual tiene un solo, require(['plugin1', 'plugin2']);etc. No se pasa ninguna devolución de llamada, por lo que no se ejecutará nada excepto los scripts del complemento. Esto significa que luego se agregarán a sí mismos, por jQuery.fnlo que en cualquier otro lugar puede enumerar 'jquery' como una dependencia y se incluirán. Como dije, soy bastante nuevo en esto y puede haber un enfoque mejor (como simplemente usar una scriptetiqueta), pero esto funciona.
Joshua Bambrick
3
Josh: Estás apostando a que todo se cargará en el orden correcto. Es probable que algunos usuarios de su sitio vean cosas dañadas. El problema no es tanto que se cargue el complemento, sino cuándo se carga el complemento y qué más se está ejecutando en ese momento. La razón principal para usar require es garantizar un orden sensato de operaciones basado en dependencias en lugar de conjeturas.
Hans
104

Hay algunas advertencias sobre el uso de la configuración de corrección en RequireJS, señaladas en http://requirejs.org/docs/api.html#config-shim . Es decir, "No mezcle la carga de CDN con la configuración de shim en una compilación" cuando esté usando el optimizador.

Estaba buscando una forma de usar el mismo código de complemento de jQuery en sitios con y sin RequireJS. Encontré este fragmento para los complementos de jQuery en https://github.com/umdjs/umd/blob/master/jqueryPlugin.js . Envuelve tu complemento en este código y funcionará correctamente de cualquier manera.

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

}));

El crédito va a jrburke; como mucho javascript, sus funciones están dentro de funciones que actúan sobre otras funciones. Pero creo que he descompuesto lo que está haciendo.

El argumento factoryde la función en la primera línea es en sí mismo una función que se invoca para definir el complemento en el $argumento. Cuando no hay un cargador compatible con AMD, se invoca directamente para definir el complemento en el jQueryobjeto global . Es como el modismo común de definición de complementos:

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

Si hay un cargador de módulo, factoryse registra como devolución de llamada para que el cargador lo invoque después de cargar jQuery. La copia cargada de jQuery es el argumento. Es equivalente a

define(['jquery'], function($) {
  $.fn.yourjQueryPlugin = function() {
     // Plugin code here
  };
})
Carl Raymond
fuente
3
Me gusta esta respuesta porque aunque la pregunta era sobre un complemento de jQuery, esto funciona para cualquier tipo de módulo o biblioteca, no solo para jQuery. Me tomó un minuto entender tu código, pero una vez que lo hice, tuvo perfecto sentido.
Adam Tuttle
1
Definitivamente es javascript impenetrable. Agregué una explicación sobre cómo funciona.
Carl Raymond
¿Algún consejo sobre cómo hacer esto y crear un complemento que funcione con jQuery o Zepto? Podrías reemplazar fácilmente el código que no es de AMD con factory(jQuery || Zepto);, pero no sé cómo harías la parte de AMD. Creo que tendrías que establecer la "ruta" de jQuery en zepto. paths: { jquery: 'vendor/zepto/zepto.min' }
Ryan Wheale
wow, hacía tiempo que quería entender este fragmento de código. Muchas gracias, ¿no es shimbásicamente eso? Supongo que no ... porque dijiste que lo estás codificando manualmente como el anterior.
Eugene
Sugerencia para idiotas como yo: donde dice $.fn.jqueryPluginen el fragmento, ¡cambie jqueryPluginal nombre del complemento!
Matt Lacey
2

Al igual que para su información, algunos de los complementos de jquery ya usan amd / require, por lo que no necesita declarar nada en el shim. De hecho, hacerlo puede causarle problemas en algunos casos.

Si miras en la cookie jquery JS, verás definir llamadas y requerir (["jquery"]).

y en jquery.js verá una llamada para definir ("jquery", [], function () ...

TPEACHES
fuente