使用RequireJS加载Backbone和Underscore

173

我正在尝试使用RequireJS加载Backbone、Underscore(以及jQuery)。使用最新版本的Backbone和Underscore似乎有些棘手。首先,Underscore会自动注册自己为模块,但是Backbone假定Underscore可以在全局范围内使用。另外,我需要注意的是,Backbone似乎没有将自己注册为模块,这使得它与其他库不太一致。以下是我编写的可行的main.js代码:

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

我应该提到,虽然它可用,但优化器在处理它时会出现错误。我收到以下信息:

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

有更好的处理方法吗?谢谢!


你是不是使用任何教程来完成它的? - kaha
1
我查看了各种教程,例如http://backbonetutorials.com/organizing-backbone-using-modules/,但它们似乎已经过时,无法适应最新版本的underscore和backbone。 - Aaronius
我也发现requirejs与其他库的使用相互之间很困难。这就是为什么我创建了一个库,它更容易使用,并且已经通过与angular的测试。底部有一个演示应用程序:http://gngeorgiev.github.io/Modulerr.js/ 您还可以将所有脚本合并为一个,而无需依赖于Modulerr.js。 - Georgi-it
顺便说一句,同步异步模块定义有点矛盾。 - Pavel 'Strajk' Dolecek
哈!说得好。已编辑。 - Aaronius
6个回答

294

RequireJS 2.X 现在更好地支持像 Backbone 和 Underscore 这样的非 AMD 模块,使用新的 shim 配置。

shim 配置很容易使用:(1) 声明依赖项 (deps),如果有的话,可以来自于 paths 配置,也可以是有效的路径。 (2) (可选)指定您要 shim 的文件中应该导出到需要它的模块函数的全局变量名。 (如果您未指定导出内容,则需要使用全局变量,因为不会传递任何内容到您的 require/define 函数。)

这里是一个简单的使用 shim 加载 Backbone 的示例。即使 underscore 没有任何依赖项,它也添加了一个导出。

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

});

注意: 这段简化的代码假设jquery、backbone和underscore的文件名分别为"jquery.js"、"backbone.js"和"underscore.js",它们都在同一个目录中作为"main"代码的基础URL(baseURL)载入。如果不是这种情况,你需要使用路径配置

个人认为使用内置的shim功能,而不是使用其他流行答案中推荐的AMD分支版本的Backbone和Underscore,优势更大,但无论哪种方式都可以工作。


这段代码是否适用于 Sample RequireJS 2.0.1 + jQuery 1.7.2 project http://requirejs.org/docs/download.html#samplejquery? - Henry
如果我理解你的意思正确,Henry,你是在问是否需要为$插件使用shim。如果你使用来自该示例项目的组合require-jquery.js文件,则不需要。这是因为使用组合文件时,jquery会与require同步加载,因此可以保证在任何模块中尝试使用任何$插件时都已经加载了jquery。在这种情况下,当你想要使用$插件时,你可以将它们包含在你的依赖列表中,就像它们是AMD一样,即使它们不是。这绝对是一个例外,通常你需要为任何非AMD模块使用shim。 - B Robster
11
我觉得这真的是正确的方法,但愿我能够给予50个赞并使它成为第一名答案。 - koblas
这个答案中的方法看起来很有前途,但对我没用。我使用了 https://gist.github.com/2517531,它运行良好。 - Rob W
Rob W- 很抱歉那个方法对你没用。可能是路径与你的目录结构不匹配或其他原因。代码是正确的 - 实际上它与 require.js 文档中的 shim 代码没有实质性的区别,该文档展示了如何加载 Backbone: http://requirejs.org/docs/api.html#config-shim -- 所以肯定有其他因素在起作用。你链接的 gist 只是一个 AMD 化的 Backbone 副本。既然你选择这条路线,你应该使用上面接受答案中链接的分支。祝你好运! - B Robster
显示剩余3条评论

170

更新:从版本1.3.0开始,Underscore移除了AMD(RequireJS)支持。

您可以使用amdjs/Backbone 0.9.1amdjs/Underscore 1.3.1分支的带有AMD支持的版本,这些分支由James Burke(RequireJS的维护者)维护。

有关Underscore和Backbone的AMD支持的更多信息,请访问此处

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

这些模块已经正确注册,无需使用顺序插件:

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

Underscore其实是可选的,因为Backbone现在会自己获取它的依赖关系:

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

使用一些AMD语法糖,你也可以像这样编写它:

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

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

关于优化器错误:请重新检查您的构建配置。我认为您的路径配置有误。如果您的目录设置类似于 RequireJS 文档中的设置,您可以使用以下代码:

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

4
这正是我在寻找的。谢谢!你的回答非常详细,现在它正如你所描述的那样运行。 - Aaronius
2
+1 准确、可行和更新的答案和示例。Riebel 做得非常好,你帮了我,也帮了其他人很多。 - Ken
23
不断更新这篇文章之后的超级奖励。 - Aaronius
太棒了,@Riebel的回答非常有用。顺便说一下,我也建议看一下volo。这是一个由jrburke(requirejs的创建者)创建的库,用于从github检索依赖项。例如,只需输入以下内容即可检索underscore的amd版本:volo add underscore。 - txominpelu

5

4
我会直接写下来,您可以在requirejs.org上阅读解释,您可以使用以下代码片段作为日常使用;(附注:我使用yeoman)(由于许多事情已更新,因此我将其发布为2014年2月的版本。)
请确保在index.html中包含了脚本。
<!-- build:js({app,.tmp}) scripts/main.js -->
<script data-main="scripts/main" src="bower_components/requirejs/require.js"></script>
<!-- endbuild -->

接着,在 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;
});

希望我能有所帮助!


1
比你想象的更有用。这正是我一直试图在我的项目中构建的内容,包括 bower_components 等。感谢 @STEEL。 - Dwight Spencer

4

好消息,Underscore 1.6.0 现在支持 requirejs define 了!!!

低于这个版本的需要 shims 支持,或者要求引入 underscore.js,然后盲目地希望 "_" 全局变量没有被破坏(公平来说,这是一个公平的赌注)

只需通过以下方式加载即可

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接