Exige por que e quando usar a configuração de shim

97

Eu li o documento requirejs aqui 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();
            }
        }
    }
});

mas eu não estou recebendo parte do shim . por que devo usar shim e como devo configurar, posso obter mais esclarecimentos?

por favor, qualquer um pode explicar com um exemplo por que e quando devemos usar o calço. obrigado.

Anil Gupta
fonte

Respostas:

110

O principal uso do shim é com bibliotecas que não oferecem suporte a AMD, mas você precisa gerenciar suas dependências. Por exemplo, no exemplo de Backbone e Underscore acima: você sabe que o Backbone requer Underscore, então suponha que você escreveu seu código assim:

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

    // do something with Backbone

}

RequireJS iniciará solicitações assíncronas para Underscore e Backbone, mas você não sabe qual delas voltará primeiro, então é possível que o Backbone tente fazer algo com o Underscore antes de ser carregado.

NOTA: este exemplo de sublinhado / backbone foi escrito antes que ambas as bibliotecas suportassem AMD. Mas o princípio é válido para qualquer biblioteca hoje que não suporte AMD.

O gancho "init" permite que você faça outras coisas avançadas, por exemplo, se uma biblioteca normalmente exportaria duas coisas diferentes para o namespace global, mas você deseja redefini-las em um único namespace. Ou talvez você queira fazer algum patching em um método na biblioteca que está carregando.

Mais antecedentes:

explodir
fonte
Como seu código de exemplo, o Underscoree Backboneaqui usam como o normal, o que shimfazer neste caso? Posso usar require( function() { _.extend({}); })? Ele entende _?
Stiger de
"RequireJS iniciará solicitações assíncronas para Underscore e Backbone" -> É possível evitar isso, caso a biblioteca já esteja carregada?
Codii
1
@Codii certo, se a biblioteca já estiver carregada, ela não iniciará outra solicitação do servidor, mas o ponto do RequireJS é que seu código não precisa se preocupar se / como isso acontece. Talvez você comece uma nova pergunta para seu caso de uso específico?
explunit
63

De acordo com a documentação da API RequireJS, o shim permite que você

Configure as dependências, exportações e inicialização personalizada para scripts "globais de navegador" mais antigos e tradicionais que não usam define () para declarar as dependências e definir um valor de módulo.

- Configurando dependências

Digamos que você tenha 2 módulos javascript (móduloA e móduloB) e um deles (móduloA) depende do outro (móduloB). Ambos são necessários para seu próprio módulo, então você especifica as dependências em require () ou define ()

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

Mas como o requer-se segue a AMD, você não tem ideia de qual seria buscado antes. É aqui que o shim vem para resgatar.

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

})

Isso garantiria que o módulo B sempre fosse buscado antes que o módulo A fosse carregado.

- Configurando exportações

A exportação de shim informa ao RequireJS qual membro no objeto global (a janela, supondo que você esteja em um navegador, é claro) é o valor real do módulo. Vamos dizer que o móduloA se adiciona ao windowcomo 'modA' (assim como jQuery e sublinhado fazem como $ e _ respectivamente), então tornamos nosso valor de exportação 'modA'.

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

Isso dará ao RequireJS uma referência local para este módulo. O modA global ainda existirá na página também.

- Inicialização personalizada para scripts "globais de navegador" mais antigos

Este é provavelmente o recurso mais importante da configuração do shim, que nos permite adicionar scripts 'globais do navegador' e 'não-AMD' (que também não seguem o padrão modular) como dependências em nosso próprio módulo.

Vamos dizer que o moduleB é um javascript antigo com apenas duas funções funcA () e funcB ().

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

Embora ambas as funções estejam disponíveis no escopo da janela, o RequireJS nos recomenda usá-las por meio de seu identificador / identificador global para evitar confusões. Portanto, configurar o calço como

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

O valor de retorno da função init é usado como o valor de exportação do módulo em vez do objeto encontrado por meio da string 'exportações'. Isso nos permitirá usar funcB em nosso próprio módulo como

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

Espero que tenha ajudado.

nalinc
fonte
3
Fácil de entender! Uma pergunta: no último exemplo, a propriedade "exportações" é simplesmente ignorada?
Niko Bellic,
Não, não está sendo ignorado. Se a propriedade "exportações" tivesse sido ignorada no último exemplo, então o objeto que você passou como parâmetro ('B' neste caso) seria indefinido, pois o módulo B NÃO é compatível com AMD e não teria retornado um objeto para RequireJS usar ( portanto, 'B.funcB' não funcionaria).
nalinc
Hmm. Achei que o valor da exportação seria substituído pelo objeto que é retornado na função init. Portanto, o parâmetro B seria o objeto {funcA: funcA, funcB: funcB}, não simplesmente funcB por si só. Não é verdade?
Niko Bellic
4
Niko Bellic está certo, a exportação É ignorada (acabei de testar isso). O objeto B é o objeto retornado pela função especificada na parte 'init'. Se você removeu a parte 'init', o objeto B se tornaria a função funcB, então você simplesmente faria B () em vez de B.funcB (). E, obviamente, funcA se tornaria inacessível nesse caso.
user4205580
-2

Você deve adicionar caminhos em requirejs.config para declarar, por exemplo:

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
fonte
1
Essa resposta é um dump de código que não explica "por que e quando usar a configuração de shim". Se você editar sua resposta para fornecer uma explicação, certifique-se de adicionar algo novo, que ainda não tenha sido abordado nas respostas anteriores
Louis
copiar colar sem nenhum feedback positivo
william.eyidi
deve ser uma vírgula antes do shim:
Scott