Como fazer um plugin jQuery carregável com requirejs

88

Estou trabalhando com requirejs + jquery e queria saber se havia uma maneira inteligente de fazer um plugin jQuery funcionar bem com o require.

Por exemplo, estou usando o jQuery-cookie. Se bem entendi, posso criar um arquivo chamado jquery-cookie.js e dentro fazer

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

Eu me perguntei se eu poderia fazer coisas como o jQuery faz, que é assim:

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

ou se esta é a única maneira de tornar os plug-ins jQuery compatíveis com requirejs ou qualquer amd

Nicola Peluchetti
fonte

Respostas:

67

Você só precisa fazer QUALQUER

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

no final de jquery-cookie.js, OR

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

em qualquer lugar antes de incluir jquery-cookie (como para onde quer que data-main aponte, por exemplo).

O último bloco de código que você postou é bom para coisas como jQuery, que são redistribuídas e podem ou não estar em um ambiente AMD. Idealmente, todo plugin jQuery já teria essa configuração.

Eu prefiro manter as bibliotecas incluídas o menos adulteradas possível, então a configuração global do shim uma vez por página parece a solução mais limpa para mim . Dessa forma, as atualizações são mais seguras e os CDNs se tornam uma possibilidade.

Hans
fonte
1
Se eu não definir e ajustar as coisas não funcionam, recebo uma mensagem de erro $ .cookie não é uma função
Nicola Peluchetti
Pela minha experiência, não retornar nada da função de definição não é suficiente, o requirejs não reconhecerá que o módulo foi carregado. Isso pode ser ativado por shim: {plugins: {depends: ['jquery'],
extensions
Você deve notar que o script do plugin jQuery precisa realmente ser executado. Não sou especialista, mas encontrei uma solução simples em que você tem um único require(['plugin1', 'plugin2']);etc. Nenhum retorno de chamada é passado, então nada será executado, exceto os próprios scripts de plug-in. Isso significa que eles serão adicionados a si mesmos para jQuery.fnque em todos os outros lugares você possa apenas listar 'jquery' como uma dependência e eles serão incluídos. Como eu disse, sou muito novo nisso e pode haver uma abordagem melhor (como apenas usar uma scripttag), mas funciona.
Joshua Bambrick
3
Josh: Você está apostando que tudo vai carregar na ordem certa. Alguns usuários do seu site provavelmente estão vendo coisas danificadas. O problema não é tanto que o plug-in carrega, é quando o plug-in carrega e o que mais está sendo executado no momento. O principal motivo para usar o require é garantir uma ordem sensata de operações com base em dependências, em vez de suposições.
Hans
104

Existem algumas ressalvas ao usar a configuração de shim no RequireJS, apontadas em http://requirejs.org/docs/api.html#config-shim . A saber, "Não misture carregamento de CDN com configuração de correção em uma compilação" quando estiver usando o otimizador.

Eu estava procurando uma maneira de usar o mesmo código de plugin jQuery em sites com e sem RequireJS. Eu encontrei este snippet para plug-ins jQuery em https://github.com/umdjs/umd/blob/master/jqueryPlugin.js . Você envolve seu plugin neste código e ele funcionará corretamente de qualquer maneira.

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

}));

O crédito vai para jrburke; como muito javascript, são funções dentro de funções agindo em outras funções. Mas acho que descobri o que está fazendo.

O argumento da função factoryna primeira linha é ele próprio uma função que é chamada para definir o plugin no $argumento. Quando nenhum carregador compatível com AMD está presente, ele é chamado diretamente para definir o plug-in no jQueryobjeto global . É exatamente como o idioma de definição de plug-in comum:

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

Se houver um carregador de módulo, factoryserá registrado como retorno de chamada para o carregador invocar após carregar o jQuery. A cópia carregada do jQuery é o argumento. É equivalente a

define(['jquery'], function($) {
  $.fn.yourjQueryPlugin = function() {
     // Plugin code here
  };
})
Carl Raymond
fonte
3
Gosto dessa resposta porque, embora a pergunta seja sobre um plugin jQuery, ele funciona para qualquer tipo de módulo ou biblioteca, não apenas jQuery. Levei um minuto para entender o seu código, mas depois que o fiz, fez todo o sentido.
Adam Tuttle
1
É definitivamente um javascript impenetrável. Eu adicionei algumas explicações sobre como funciona.
Carl Raymond
Alguma dica de como fazer isso e fazer um plugin que funcione com jQuery ou Zepto? Você poderia facilmente substituir o código não-AMD por factory(jQuery || Zepto);, mas não sei como você faria a parte AMD. Eu acho que você teria que definir o "caminho" do jQuery para zepto ?? paths: { jquery: 'vendor/zepto/zepto.min' }
Ryan Wheale
uau, há muito tempo eu queria entender esse trecho de código. Muito obrigado, não é shimessencialmente isso? Eu acho que não .. porque você disse que está codificando manualmente como o acima.
Eugene
Protip para idiotas como eu: onde diz $.fn.jqueryPluginno snippet, mude jqueryPluginpara o nome do plugin !!
Matt Lacey
2

Assim como um FYI para todos os plug-ins jquery já usam amd / require, você não precisa declarar nada no shim. Na verdade, isso pode causar problemas para você em alguns casos.

Se você olhar no JS do cookie jquery, verá define calls e require (["jquery"]).

e em jquery.js você verá uma chamada para definir ("jquery", [], function () ...

TPEACHES
fonte