Carga de Backbone y subrayado usando RequireJS

172

Estoy tratando de cargar Backbone y Underscore (así como jQuery) con RequireJS. Con las últimas versiones de Backbone y Underscore, parece un poco complicado. Por un lado, Underscore se registra automáticamente como un módulo, pero Backbone supone que Underscore está disponible a nivel mundial. También debo señalar que Backbone no parece registrarse como un módulo, lo que lo hace un poco inconsistente con las otras bibliotecas. Este es el mejor main.js que se me ocurrió 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();
    })
});

Debo mencionar que, mientras funciona, el optimizador se ahoga. Recibo lo siguiente:

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

¿Hay una mejor manera de manejar esto? ¡Gracias!

Aaronius
fuente
¿Lo hiciste usando algún tutorial?
kaha
1
Revisé varios tutoriales como backbonetutorials.com/organizing-backbone-using-modules, pero ahora parecen estar desactualizados con las últimas versiones de subrayado y backbone.
Aaronius
También encontré que requirejs es difícil de usar con otras bibliotecas y viceversa. Es por eso que creé una biblioteca que es mucho más fácil de usar y se prueba con angular. Hay una aplicación de demostración en la parte inferior: gngeorgiev.github.io/Modulerr.js También puede combinar todos los scripts en uno sin depender de Modulerr.js
Georgi-it
por cierto, la definición del módulo asíncrono síncrono es un poco oxímoron :)
Strajk
¡Decir ah! Buen punto. Editado
Aaronius

Respuestas:

294

RequireJS 2.X ahora aborda orgánicamente los módulos que no son AMD, como Backbone y Underscore, mucho mejor, utilizando la nueva shimconfiguración.

La shimconfiguración es simple de usar: (1) uno establece las dependencias ( deps), si las hay, (que pueden ser de la pathsconfiguración o pueden ser rutas válidas). (2) (opcionalmente) especifique el nombre de la variable global del archivo que está cambiando, que debe exportarse a las funciones de su módulo que lo requieran. (Si no especifica las exportaciones, necesitará simplemente usar el global, ya que nada pasará a sus funciones require / define).

Aquí hay un ejemplo de uso simple shimpara cargar Backbone. También agrega una exportación para subrayar, aunque no tiene ninguna dependencia.

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 supone que jquery, backbone y subrayado están en archivos llamados "jquery.js", "backbone.js" y "underscore.js" en el mismo directorio que este código "principal" (que se convierte en baseURL para requerir ) Si este no es el caso, deberá utilizar una configuración de rutas .

Personalmente, creo que con la shimfuncionalidad incorporada, las ventajas de no usar una versión bifurcada de Backbone & Underscore superan los beneficios de usar la bifurcación AMD recomendada en la otra respuesta popular, pero de cualquier manera funciona.

Ben Roberts
fuente
¿Debería usarse este código con Sample RequireJS 2.0.1 + jQuery 1.7.2 project requirejs.org/docs/download.html#samplejquery ?
Henry
Si te entiendo correctamente, Henry, estás preguntando si shim es necesario para $ plugins. No lo es, SI usa el archivo require-jquery.js combinado de ese proyecto de muestra. Esto se debe a que con el archivo combinado, jquery se carga sincrónicamente con require, por lo que se garantiza que jquery se cargará para el momento en que intente usar cualquier complemento $ en cualquier módulo. En este caso, cuando desee usar complementos de $, puede incluirlos en su lista de dependencias como si fueran AMD, incluso si no lo son. Esta es definitivamente una excepción a la regla, y generalmente necesitará una cuña para cualquier módulo que no sea AMD.
Ben Roberts
Tenga en cuenta que shim cofiguration es compatible con ese proyecto de muestra y podría usarse para agregar otras bibliotecas que no sean AMD.
Ben Roberts
11
Solo pensé en mencionar que este es realmente el camino a seguir, desearía poder dar +50 votos a favor para que sea la respuesta # 1.
koblas
El método en esta respuesta parecía prometedor, pero no funcionó para mí. En su lugar, utilicé gist.github.com/2517531 , que funcionó bien.
Rob W
171

Actualización : A partir de la versión 1.3.0, subrayado eliminó la compatibilidad con AMD (RequireJS) .

Puede usar amdjs / Backbone 0.9.1 y amdjs / Underscore 1.3.1 fork con soporte AMD de James Burke (el responsable de RequireJS).

Más información sobre el soporte de AMD para Underscore y 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();
    });
});

Los módulos están debidamente registrados y no es necesario el complemento de pedido:

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

El subrayado es realmente opcional, porque Backbone ahora obtiene sus dependencias por sí solo:

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

Con un poco de azúcar AMD también podrías escribirlo así:

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

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

Con respecto al error del optimizador: verifique dos veces su configuración de compilación. Supongo que su configuración de ruta está desactivada. Si tiene una configuración de directorio similar a la de RequireJS Docs , puede 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"
        }
    ]
})
revs Riebel
fuente
44
Eso es exactamente lo que estaba buscando. ¡Gracias! Gran respuesta detallada también. Ahora está funcionando tal como lo has descrito.
Aaronius
2
+1 respuestas + ejemplos precisos, funcionales y actualizados. excelente trabajo Riebel, me has ayudado, y estoy seguro de que otros, mucho.
Ken
22
Súper bonificación por mantener esto actualizado mucho después de la publicación original.
Aaronius
Gran respuesta @Riebel! Me ha sido muy útil. Por cierto, también recomendaría echar un vistazo a volo . Es una biblioteca creada por jrburke (el creador de requirejs) para recuperar dependencias de github. Por ejemplo, la recuperación de la versión AMD de subrayado se realiza simplemente escribiendo: volo add subrayado
txominpelu
4

Buenas noticias, Underscore 1.6.0 ahora soporta requirejs define !!!

las versiones a continuación requieren cuñas, o requieren subrayar.js y luego esperar ciegamente que la variable global "_" no se haya roto (lo que para ser justos es una apuesta justa)

simplemente cárguelo en

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

Escribiré directamente, puede leer la explicación en requirejs.org, puede usar el código a continuación como un fragmento para su uso diario; (ps, uso yeoman) (ya que muchas cosas se actualizaron, estoy publicando esto a partir de febrero de 2014).

Asegúrese de incluir el script en su index.html

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

Luego, en 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 haber sido útil.

ACERO
fuente
1
Más útil de lo que sabes. Esto es exactamente lo que he intentado construir en un proyecto mío, bower_components y todo. Gracias @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
fuente