Загрузка Backbone и Underscore с использованием RequireJS

172

Я пытаюсь загрузить Backbone и Underscore (а также jQuery) с RequireJS. С последними версиями 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

Есть ли лучший способ справиться с этим? Спасибо!

Aaronius
источник
Вы делали это с помощью любого учебника?
Каха
1
Я просмотрел различные учебные пособия, такие как backbonetutorials.com/organizing-backbone-using-modules, но, похоже, они устарели с последними версиями underscore и backbone.
Аароний
Я также нашел requirejs трудно использовать с другими библиотеками и наоборот. Вот почему я создал библиотеку, которая намного проще в использовании и проверена на угловых. Внизу находится демонстрационное приложение: gngeorgiev.github.io/Modulerr.js Вы также можете объединить все сценарии в один без зависимости от Modulerr.js
Georgi-it
Кстати, Синхронный Асинхронный Модуль Определение является своего рода оксюморон :)
Strajk
Ха! Хорошая точка зрения. Ред.
Аароний,

Ответы:

294

RequireJS 2.X теперь органически обращается к модулям не-AMD, таким как Backbone & Underscore, намного лучше, используя новую shimконфигурацию.

shimКонфигурация проста в использовании: (1) один утверждает зависимости ( deps), если таковые имеются, (которые могут быть от pathsконфигурации, или могут быть действительными тракты сами). (2) (опционально) укажите имя глобальной переменной из файла, который вы используете, которое должно быть экспортировано в функции вашего модуля, которым это требуется. (Если вы не укажете экспорт, вам нужно будет просто использовать глобальный, так как ничто не будет передано в ваши функции require / define.)

Вот простой пример использования shimдля загрузки Backbone. Он также добавляет экспорт для подчеркивания, даже если у него нет никаких зависимостей.

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" в том же каталоге, что и этот "основной" код (который становится baseURL для require ). Если это не так, вам нужно использовать конфигурацию путей .

Лично я считаю, что благодаря встроенной shimфункциональности преимущества отсутствия разветвленной версии Backbone & Underscore перевешивают преимущества использования AMD-форка, рекомендованного в другом популярном ответе, но в любом случае это работает.

Бен Робертс
источник
Должен ли этот код использоваться с Sample RequireJS 2.0.1 + jQuery 1.7.2 project requirejs.org/docs/download.html#samplejquery ?
Генри
Если я правильно вас понимаю, Генри, вы спрашиваете, нужен ли shim для $ plugins. Это не так, если вы используете объединенный файл require-jquery.js из этого примера проекта. Это связано с тем, что с объединенным файлом jquery загружается синхронно с require, поэтому jquery гарантированно будет загружен, когда вы попытаетесь использовать любые $ plugins в любом модуле. В этом случае, когда вы хотите использовать $ plugins, вы можете просто включить их в свой список зависимостей, как если бы они были AMD, даже если это не так. Это, безусловно, исключение из правила, и, как правило, вам понадобится шим для любых не-AMD модулей.
Бен Робертс
Обратите внимание, что настройка shim совместима с этим примером проекта и может использоваться для добавления других не-AMD библиотек.
Бен Робертс
11
Просто подумал, что упомяну, что это действительно путь, хотел бы я дать +50 голосов, чтобы получить ответ № 1.
Коблас
Метод в этом ответе выглядел многообещающе, но не работал для меня. Вместо этого я использовал gist.github.com/2517531 , который работал нормально.
Роб W
171

Обновление : Начиная с версии 1.3.0 Underscore удалена поддержка AMD (RequireJS) .

Вы можете использовать amdjs / Backbone 0.9.1 и вилку amdjs / Underscore 1.3.1 с поддержкой AMD от James Burke (сопровождающего RequireJS).

Больше информации о поддержке AMD для Underscore и 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();
    });
});

Модули правильно зарегистрированы, и плагин заказа не требуется:

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

Подчеркивание на самом деле необязательно, потому что 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 Docs, вы можете использовать:

// 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
Это именно то, что я искал. Спасибо! Отличный подробный ответ. Теперь он работает так же, как вы описали.
Аароний
2
+1 точный, рабочий и обновленный ответ + примеры. отличная работа, Рибель, ты мне помогаешь, и я уверен, что другие очень сильно.
Кен
22
Супер-бонус за постоянное обновление этого поста после оригинального поста.
Аароний
Отличный ответ @Riebel! Это было действительно полезно для меня. Кстати, я бы также посоветовал взглянуть на volo . Это библиотека, созданная jrburke (создателем requirejs) для извлечения зависимостей из github. Например, для получения версии подчеркивания amd достаточно набрать: volo add underscore
txominpelu
4

Хорошая новость: Underscore 1.6.0 теперь поддерживает requirejs define !!!

версии ниже этого требуют шиммы, или требуют underscore.js, затем вслепую надеясь, что глобальная переменная "_" не была разбита (что справедливо, будет честной ставкой)

просто загрузите его

  requirejs.config({
    paths: {
        "underscore": "PATH/underscore-1.6.0.min",
    }
  });
АКМ
источник
4

Я напишу прямо, вы можете прочитать объяснение на requirejs.org, вы можете использовать приведенный ниже код в качестве фрагмента для вашего повседневного использования; (ps я использую yeoman) (так как многие вещи обновлены, я публикую это по состоянию на февраль 2014 года.)

Убедитесь, что вы включили скрипт в ваш 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
Дуайт Спенсер
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();
});
Сумеш Т.Г.
источник