chris Frisina
chris Frisina

Reputation: 19688

Order of events for a Rails 4 Backbone Require loading

I have three main files:

A) application.js  // This resides in rails land at    app/assets/javascripts/application.js
B) SOF.js          // This resides in rails land at    app/assets/javascripts/SOF.js
C) router.js       // This resides in backbone land at app/assets/javascripts/backbone/routers/router.js

I am wondering why the declared dependencies in the router.js are occuring without being called in the router itself. Said another way, the order of events are :

  1. A gives a console.log from before the normal require.js define()
  2. then B's
  3. then C's
  4. then all C's dependencies that are JUST defined in the function init themselves!!!!
  5. then A begins to initialize, where it calls B.initialize()
  6. then B begins to initialize where it calls C.initialize()
  7. (a)then C begins to initialize, (b)recognize the route, and follow the appropriate router method, finishing its router method calls (even though there aren't any).
  8. Then C finishes initing, and passes control back to B
  9. Then B finishes initing, and passes control back to A
  10. Then A finishes initing, and no more logs....

My understanding is that the App.js(A) should init the SOF.js(B), which inits the router in router.js(C), and THEN the router should recognize the route, and follow the appropriate route, and create any models/collections/views there.

Why is it that by just including the files in the define() portion of require.js method declaration that it causes them to load, EVEN before the files themselves init? If I remove the declaration, they won't load, but then of course, I can't reference them to manually initi them in the appropriate route....

Files for your eyes (with above order of events on left):
Application.js:

1-  console.log('Application.js: Started');
    require([      'SOF'    ],
      function(SOF){
5-    console.log("Application.js: initializing SOF...");
      SOF.initialize(App.songs); //App.songs is an object that contains the data from the Rails DB
10-   console.log("Application.js: SOF_Application Fully initialized");
    });

SOF.js:

2- console.log('SOF.js: Started');
   define([
     'jquery',
     'underscore',
     'backbone',
     'backbone/routers/router',
     'd3',
     'jquery-ui'
   ], function($, _, Backbone, Router, d3, $){
     var initialize = function(options){
6-     console.log('SOF.js: In Initialize, initializing Router:');
6-     console.log('SOF.js: options : ', options);
       Router.initialize(options);
9-     console.log('SOF.js: Finished initializing');
     }
     return {
       initialize: initialize
     };
   });

router.js:

3- console.log('Backbone Router started');
   define([
     'jquery',
     'underscore',
     'backbone',
4-   'backbone/relevantModels....',       // Will init just by being here
4-   'backbone/relevantCollections....',  // If I remove it from here, and of course its matching name in the following function formal parameter, it will not init/render
4-   'backbone/relevantViews....'
   ], function($, _, Backbone, RelevantModels, RelevantCollections, RelevantViews){
     var BBRouter = Backbone.Router.extend({
       routes: {
         'new'       : 'newSong',
         '.*'        : 'newSong'
       },
       newSong: function(){
7b       console.log('BB routes => new : newSong');
         // THESE ARE ALL COMMENTED OUT (VERIFIED no caching problems) but still init/render because they are declared above
         // And if I remove the declaration above, I can't call new RelevantView() since it won't know what RelevantView is
         // top side
         // RelevantView.render();
         // middle
         // RelevantView.render();
         // bottom
         // RelevantView.render();
7b       console.log('BB routes: newSong Finished');
       }
     });
     var initialize = function(options){
7a     console.log("BB Router => Initializing...");
       var bb_router = new BBRouter;
       window.router = bb_router;  // attach it to the window for debugging
8-     console.log('BB Router => Initialized');
       Backbone.history.start({root: '/songs/#new'});
     };
     return {
       initialize: initialize
     };
   });

Also note, on the Rails main Application.html.erb, this is the order of declaration in the <head>:

<%= stylesheet_link_tag    "application", :media => "all" %>
<%= requirejs_include_tag "application" %>
<%= javascript_include_tag "assets" %>

Gemfile:

gem 'rails-backbone', git: 'https://github.com/codebrew/backbone-rails.git', tag: 'v1.1.2'
gem 'requirejs-rails', git: 'git://github.com/jwhitley/requirejs-rails.git'

and Gemfile.lock

GIT
  remote: https://github.com/codebrew/backbone-rails.git
  revision: 4c1dfba7b4f2a989bd0dbc95d5afd3fc762a0b6d
  tag: v1.1.2
  specs:
    rails-backbone (1.1.2)
      coffee-script
      ejs
      jquery-rails
      railties
GIT
  remote: git://github.com/jwhitley/requirejs-rails.git
  revision: f2330104aeca4d193fd5680a22ae7eee85d814b5
  specs:
    requirejs-rails (0.9.1)
      railties (>= 3.1.1, < 4.1)

Upvotes: 4

Views: 134

Answers (1)

Denis Washington
Denis Washington

Reputation: 5622

Your understanding of the module initialization order is correct, but look at the end of the view module files (e.g., StageView below):

define([
  ...
], function(...) {
  var StageView = Backbone.View.extend({
    ...
  });

  // A singleton
  return new StageView();
});

In addition to merely defining a view class, it also directly creates an instance of it. This explains why the view's initialize() is called when the module is imported (Backbone calls initialize() from the constructor). It's also the initialize() method which calls render() (see, for instance, stageView.js, line 45).

I hope this solves the mystery. :-)

Upvotes: 1

Related Questions