Carregando Backbone e Sublinhado usando RequireJS

172

Estou tentando carregar o Backbone e o Underscore (assim como o jQuery) com o RequireJS. Com as versões mais recentes do Backbone e Underscore, parece meio complicado. Por um lado, o Underscore se registra automaticamente como um módulo, mas o Backbone assume que o Underscore está disponível globalmente. Devo também observar que o Backbone não parece se registrar como um módulo, o que o torna meio inconsistente com as outras bibliotecas. Este é o melhor main.js que eu poderia criar que funciona:

require(
{
    paths: {
        'backbone': 'libs/backbone/backbone-require',
        'templates': '../templates'
    }
},
[
    // jQuery registers itself as a module.
    'http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js',

    // Underscore registers itself as a module.
    'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.2.1/underscore-min.js'
], function() {

    // These nested require() calls are just due to how Backbone is built.  Underscore basically says if require()
    // is available then it will automatically register an "underscore" module, but it won't register underscore
    // as a global "_".  However, Backbone expects Underscore to be a global variable.  To make this work, we require
    // the Underscore module after it's been defined from within Underscore and set it as a global variable for
    // Backbone's sake.  Hopefully Backbone will soon be able to use the Underscore module directly instead of
    // assuming it's global.
    require(['underscore'], function(_) {
        window._ = _;
    });

    require([
        'order!http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.5.3/backbone-min.js',
        'order!app'
    ], function(a, app) {
        app.initialize();
    })
});

Devo mencionar que, enquanto funciona, o otimizador engasga com isso. Eu recebo o seguinte:

Tracing dependencies for: main
js: "/home/httpd/aahardy/requirejs/r.js", line 7619: exception from uncaught JavaScript throw: Error: Error: Error evaluating module "undefined" at location "/home/httpd/aahardy/phoenix/trunk/ui/js/../../ui-build/js/underscore.js":
JavaException: java.io.FileNotFoundException: /home/httpd/aahardy/phoenix/trunk/ui/js/../../ui-build/js/underscore.js (No such file or directory)
fileName:/home/httpd/aahardy/phoenix/trunk/ui/js/../../ui-build/js/underscore.js
lineNumber: undefined
http://requirejs.org/docs/errors.html#defineerror
In module tree:
    main

Existe uma maneira melhor de lidar com isso? Obrigado!

Aaronius
fonte
Você fez isso usando algum tutorial?
kaha
1
Examinei vários tutoriais como backbonetutorials.com/organizing-backbone-using-modules, mas eles parecem estar desatualizados agora com as versões mais recentes de sublinhado e backbone.
Aaronius 15/11
Também achei o requirejs difícil de usar com outras bibliotecas e vice-versa. Por isso, criei uma biblioteca que é muito mais fácil de usar e é testada com angular. Há uma aplicação de demonstração na parte inferior: gngeorgiev.github.io/Modulerr.js Você também pode combinar todos os scripts em uma sem a dependência para Modulerr.js
Georgi-it
btw Synchronous Módulo Asynchronous Definição é meio oxímoro :)
Strajk
Ha! Bom ponto. Editado.
Aaronius 14/10

Respostas:

294

O RequireJS 2.X agora aborda organicamente os módulos não-AMD, como Backbone & Underscore, muito melhor, usando a nova shimconfiguração.

A shimconfiguração é simples de usar: (1) afirma-se as dependências ( deps), se houver, (que podem ser da pathsconfiguração ou podem ser caminhos válidos). (2) (opcionalmente) especifique o nome da variável global do arquivo que você está exibindo, que deve ser exportado para as funções de seu módulo que exigem isso. (Se você não especificar as exportações, precisará usar apenas o global, pois nada será passado para suas funções de exigência / definição.)

Aqui está um exemplo simples de shimcomo carregar o Backbone. Ele também adiciona uma exportação para sublinhado, mesmo que não tenha nenhuma dependência.

require.config({
  shim: {
    underscore: {
      exports: '_'
    },
    backbone: {
      deps: ["underscore", "jquery"],
      exports: "Backbone"
    }
  }
});

//the "main" function to bootstrap your code
require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone) {   // or, you could use these deps in a separate module using define

});

Nota: este código simplificado assume que jquery, backbone e underscore estão em arquivos denominados "jquery.js", "backbone.js" e "underscore.js" no mesmo diretório que este código "principal" (que se torna a baseURL para requerer ) Se não for esse o caso, você precisará usar uma configuração de caminhos .

Pessoalmente, acho que com a shimfuncionalidade incorporada, as vantagens de não usar uma versão bifurcada do Backbone & Underscore superam os benefícios do uso do garfo AMD recomendado na outra resposta popular, mas de qualquer maneira funciona.

Ben Roberts
fonte
Esse código deve ser usado com Sample RequireJS 2.0.1 + jQuery 1.7.2 project requirejs.org/docs/download.html#samplejquery ?
Henry
Se bem entendi, Henry, você está perguntando se o shim é necessário para os plugins $. Não, se você usar o arquivo require-jquery.js combinado desse projeto de amostra. Isso ocorre porque, com o arquivo combinado, o jquery é carregado de forma síncrona com o require, portanto é garantido que o jquery seja carregado quando você tentar usar qualquer plug-in $ em qualquer módulo. Nesse caso, quando você quiser usar $ plugins, basta incluí-los na sua lista de dependências como se fossem AMD, mesmo que não sejam. Definitivamente, essa é uma exceção à regra e geralmente você precisará de calços para qualquer módulo que não seja da AMD.
Ben Roberts
Observe que a cofiguração do shim é compatível com esse projeto de amostra e pode ser usada para adicionar outras bibliotecas não AMD.
21487 Ben Ben Roberts
11
Apenas pensei em mencionar que este é realmente o caminho a percorrer, gostaria de poder dar +50 upvotes para que seja a resposta número 1.
Koblas
O método nesta resposta parecia promissor, mas não funcionou para mim. Em vez disso, usei o gist.github.com/2517531 , que funcionou bem.
Rob W
171

Atualização : A partir da versão 1.3.0, o Underscore removeu o suporte AMD (RequireJS) .

Você pode usar o amdjs / Backbone 0.9.1 e o garfo amdjs / Underscore 1.3.1 com suporte da AMD de James Burke (o mantenedor do RequireJS).

Mais informações sobre o suporte da AMD para Underscore e Backbone .

// main.js using RequireJS 1.0.7
require.config({
    paths: {
        'jquery': 'libs/jquery/1.7.1/jquery',
        'underscore': 'libs/underscore/1.3.1-amdjs/underscore', // AMD support
        'backbone': 'libs/backbone/0.9.1-amdjs/backbone', // AMD support
        'templates': '../templates'
    }
});

require([
    'domReady', // optional, using RequireJS domReady plugin
    'app'
], function(domReady, app){
    domReady(function () {
        app.initialize();
    });
});

Os módulos estão registrados corretamente e não há necessidade do plug-in de pedido:

// app.js
define([
    'jquery', 
    'underscore',
    'backbone'
], function($, _, Backbone){
    return {
        initialize: function(){
            // you can use $, _ or Backbone here
        }
    };
});

Sublinhado é realmente opcional, porque o Backbone agora obtém suas dependências por conta própria:

// app.js
define(['jquery', 'backbone'], function($, Backbone){
    return {
        initialize: function(){
            // you can use $ and Backbone here with
            // dependencies loaded i.e. Underscore
        }
    };
});

Com um pouco de açúcar AMD, você também pode escrever assim:

define(function(require) {
    var Backbone = require('backbone'),
        $ = require('jquery');

    return {
        initialize: function(){
            // you can use $ and Backbone here with
            // dependencies loaded i.e. Underscore
        }
    };
});

Em relação ao erro do otimizador: verifique novamente sua configuração de compilação. Presumo que a configuração do seu caminho esteja desativada. Se você tiver uma configuração de diretório semelhante ao RequireJS Docs, poderá usar:

// app.build.js
({
    appDir: "../",
    baseUrl: "js",
    dir: "../../ui-build",
    paths: {
        'jquery': 'libs/jquery/1.7.1/jquery',
        'underscore': 'libs/underscore/1.3.1-amdjs/underscore',
        'backbone': 'libs/backbone/0.9.1-amdjs/backbone',
        'templates': '../templates'
    }, 
    modules: [
        {
            name: "main"
        }
    ]
})
Riebel
fonte
4
Era exatamente o que eu estava procurando. Obrigado! Ótima resposta detalhada também. Agora está funcionando exatamente como você descreveu.
Aaronius 17/11/11
2
+1 resposta precisa, funcional e atualizada + exemplos. excelente trabalho Riebel, você me ajudou, e tenho certeza que os outros, muito.
Ken
22
Super-bônus por manter isso atualizado por muito tempo após a postagem original.
Aaronius 21/01
Ótima resposta @Riebel! Tem sido realmente útil para mim. Aliás, eu também recomendaria dar uma olhada no volo . É uma biblioteca criada por jrburke (o criador do requirejs) para recuperar dependências do github. Por exemplo recuperar a versão amd de sublinhado é feito apenas de digitação: volo adicionar sublinhado
txominpelu
4

Boas notícias, o Underscore 1.6.0 agora suporta requirejs define !!!

as versões abaixo disso requerem calços ou exigem underscore.js, esperando cegamente que a variável global "_" não tenha sido esmagada (o que ser justo é uma aposta justa)

basta carregá-lo

  requirejs.config({
    paths: {
        "underscore": "PATH/underscore-1.6.0.min",
    }
  });
aqm
fonte
4

Escreverei diretamente, você pode ler a explicação em requirejs.org, você pode usar o código abaixo como um trecho para o seu uso diário; (ps eu uso yeoman) (como muitas coisas foram atualizadas, estou publicando isso em fevereiro de 2014.)

Certifique-se de incluir o script no seu index.html

<!-- build:js({app,.tmp}) scripts/main.js -->
<script data-main="scripts/main" src="bower_components/requirejs/require.js"></script>
<!-- endbuild -->

Então, no main.js

require.config({
    shim: {
        'backbone': {
            deps: ['../bower_components/underscore/underscore.js', 'jquery'],
            exports: 'Backbone'
        }
    },

    paths: {
        jquery: '../bower_components/jquery/jquery',
        backbone: '../bower_components/backbone/backbone'
    }
});

require(['views/app'], function(AppView){
    new AppView();
});

app.js

/**
 * App View
 */
define(['backbone', 'router'], function(Backbone, MainRouter) {
    var AppView = Backbone.View.extend({
        el: 'body',

        initialize: function() {
            App.Router = new MainRouter();
            Backbone.history.start();
        }
    });

    return AppView;
});

Espero ter sido útil.!

AÇO
fonte
1
Mais útil do que você imagina. Isto é exatamente o que eu tentei construir em um projeto meu, bower_components e tudo. Obrigado @STEEL
Dwight Spencer
0
require.config({
  waitSeconds: 500,
  paths: {
    jquery: "libs/jquery/jquery",
    jqueryCookie: "libs/jquery/jquery.cookie",
    .....
  },

  shim: {
    jqxcore: {
      export: "$",
      deps: ["jquery"]
    },
    jqxbuttons: {
      export: "$",
      deps: ["jquery", "jqxcore"]
    }
    ............
  }
});

require([
 <i> // Load our app module and pass it to our definition function</i>
  "app"
], function(App) {
  // The "app" dependency is passed in as "App"
  // Again, the other dependencies passed in are not "AMD" therefore don't pass a parameter to this function
  App.initialize();
});
Sumesh TG
fonte