Ładowanie Backbone i Underscore za pomocą RequireJS

172

Próbuję załadować Backbone i Underscore (a także jQuery) z RequireJS. W przypadku najnowszych wersji Backbone i Underscore wydaje się to trudne. Po pierwsze, Underscore automatycznie rejestruje się jako moduł, ale Backbone zakłada, że ​​Underscore jest dostępny globalnie. Powinienem również zauważyć, że Backbone nie wydaje się rejestrować siebie jako moduł, co powoduje, że jest niespójny z innymi bibliotekami. To najlepszy plik main.js, jaki mogłem wymyślić, który działa:

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

Powinienem wspomnieć, że gdy działa, optymalizator się dusi. Otrzymuję:

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

Czy jest lepszy sposób na rozwiązanie tego problemu? Dzięki!

Aaronius
źródło
Czy zrobiłeś to za pomocą jakiegoś samouczka?
kaha
1
Przejrzałem różne samouczki, takie jak backbonetutorials.com/organizing-backbone-using-modules, ale wydają się być nieaktualne z najnowszymi wersjami podkreślenia i szkieletu.
Aaronius
Zauważyłem również, że requirejs jest trudny w użyciu z innymi bibliotekami i odwrotnie. Dlatego stworzyłem bibliotekę, która jest dużo łatwiejsza w użyciu i jest testowana pod kątem. Jest to aplikacja demo na dole: gngeorgiev.github.io/Modulerr.js Można również połączyć wszystkie skrypty w jeden, bez uzależnienia do Modulerr.js
Georgi-on
btw Synchronous Asynchronous Module Definition is kinda oxymoron :)
Strajk
Ha! Słuszna uwaga. Edytowano.
Aaronius

Odpowiedzi:

294

RequireJS 2.X teraz w sposób organiczny adresuje moduły inne niż AMD, takie jak Backbone i Underscore, znacznie lepiej, korzystając z nowej shimkonfiguracji.

shimUkład jest prosty w obsłudze: (1) jeden stanowi zależności ( deps), jeśli występuje, (które mogą być od pathskonfiguracji i może być ważne Ścieżki się). (2) (opcjonalnie) określ nazwę zmiennej globalnej z pliku, który modyfikujesz, która powinna zostać wyeksportowana do funkcji modułu, które tego wymagają. (Jeśli nie określisz eksportu, musisz po prostu użyć globalnego, ponieważ nic nie zostanie przekazane do twoich funkcji require / define.)

Oto prosty przykład użycia shimdo załadowania Backbone. Dodaje również eksport dla podkreślenia, mimo że nie ma żadnych zależności.

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

});

Uwaga: ten uproszczony kod zakłada, że ​​jquery, backbone i underscore znajdują się w plikach o nazwach „jquery.js”, „backbone.js” i „underscore.js” w tym samym katalogu, co ten „główny” kod (który staje się podstawowym adresem URL dla require ). Jeśli tak nie jest, musisz użyć konfiguracji ścieżek .

Osobiście uważam, że dzięki wbudowanej shimfunkcjonalności zalety nieużywania rozwidlonej wersji Backbone & Underscore przewyższają korzyści wynikające z używania widelca AMD zalecanego w innej popularnej odpowiedzi, ale tak czy inaczej działa.

Ben Roberts
źródło
Czy ten kod powinien być używany z Sample RequireJS 2.0.1 + jQuery 1.7.2 project requirejs.org/docs/download.html#samplejquery ?
Henry
Jeśli dobrze cię rozumiem, Henry, pytasz, czy podkładka jest potrzebna do wtyczek $. Nie jest, JEŚLI używasz połączonego pliku require-jquery.js z tego przykładowego projektu. Dzieje się tak, ponieważ w przypadku połączonego pliku jquery jest ładowane synchronicznie z wymaganiem, więc jquery ma pewność, że zostanie załadowane przed użyciem jakichkolwiek wtyczek $ w dowolnym module. W takim przypadku, gdy chcesz użyć wtyczek $ plugins, możesz po prostu dołączyć je do swojej listy zależności, tak jakby były AMD, nawet jeśli nie są. Jest to zdecydowanie wyjątek od reguły i generalnie będziesz potrzebować podkładki do wszystkich modułów innych niż AMD.
Ben Roberts,
Zwróć uwagę, że konfiguracja podkładek jest zgodna z tym przykładowym projektem i może być używana do dodawania innych bibliotek innych niż AMD.
Ben Roberts,
11
Pomyślałem, że wspomnę, że to naprawdę najlepsza droga, żałuję, że nie mogę dać +50 głosów za, aby uzyskać odpowiedź numer 1.
koblas
Metoda w tej odpowiedzi wyglądała obiecująco, ale nie działała dla mnie. Zamiast tego użyłem gist.github.com/2517531 , co działało dobrze.
Rob W
171

Aktualizacja : Od wersji 1.3.0 Usunięto podkreślenie Obsługa AMD (RequireJS) .

Możesz użyć amdjs / Backbone 0.9.1 i amdjs / Underscore 1.3.1 z obsługą AMD od Jamesa Burke (opiekuna RequireJS).

Więcej informacji na temat wsparcia AMD dla Underscore i 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();
    });
});

Moduły są poprawnie zarejestrowane i nie ma potrzeby dodawania wtyczki do zamówienia:

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

Podkreślenie jest w rzeczywistości opcjonalne, ponieważ Backbone ma teraz własne zależności:

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

Z odrobiną cukru AMD możesz również napisać to w ten sposób:

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

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

Odnośnie błędu optymalizatora: dwukrotnie sprawdź konfigurację kompilacji. Zakładam, że twoja konfiguracja ścieżki jest wyłączona. Jeśli masz konfigurację katalogu podobną do RequireJS Docs , możesz użyć:

// 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
źródło
4
Dokładnie tego szukałem. Dziękuję Ci! Świetna szczegółowa odpowiedź. Teraz działa tak, jak opisałeś.
Aaronius
2
+1 dokładna, działająca i aktualna odpowiedź + przykłady. świetna robota Riebel, pomogłeś mi i jestem pewien, że inni, dużo.
Ken,
22
Super bonus za aktualizowanie tego długo po oryginalnym poście.
Aaronius,
Świetna odpowiedź @Riebel! To było dla mnie bardzo przydatne. Przy okazji polecam też rzucić okiem na volo . Jest to biblioteka stworzona przez jrburke (twórcę requirejs) w celu pobierania zależności z github. Na przykład pobieranie amd wersję podkreślenia odbywa wpisanie: volo dodać podkreślenia
txominpelu
4

Dobra wiadomość, Underscore 1.6.0 obsługuje teraz definicję requirejs !!!

wersje poniżej tego wymagają podkładek lub podkreślenia.

po prostu załaduj go przez

  requirejs.config({
    paths: {
        "underscore": "PATH/underscore-1.6.0.min",
    }
  });
aqm
źródło
4

Napiszę bezpośrednio, możesz przeczytać wyjaśnienie na requirejs.org, możesz użyć poniższego kodu jako fragmentu kodu do codziennego użytku; (ps używam yeoman) (ponieważ zaktualizowano wiele rzeczy, publikuję to od lutego 2014 r.)

Upewnij się, że umieściłeś skrypt w pliku index.html

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

Następnie w 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;
});

Mam nadzieję, że się przydałem.!

STAL
źródło
1
Bardziej użyteczne, niż myślisz. To jest dokładnie to, co próbowałem zbudować na moim projekcie, bower_components i wszystkim. Dzięki @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
źródło