require.js + backbone.js: How to structure modules

2019-03-30 14:00发布

问题:

I have an application with three pages (which are single-page interfaces). The pages have similar but not identical functionality.

So I want to have javascript-modules that provide the common functionality. Then each page may customize/overwrite parts of the common functionality.

I'm using backbone.js, so what I do is:

  1. load the files containing the common Models, Views, Collections etc.
  2. load app-specific files that customize/overwrite parts of step 1
  3. call an init() function that instanciates all necessary Models/Views/Collections

At the moment I store my modules in a module-container similar to this: https://stackoverflow.com/a/9426071 Each module has an optional init() function that is executed by my main init() function.

Example:

  1. I have a file called results.js. It defines the common Model/Collection/View of search-results. In its init() function everything is instanciated, but this function is not yet called:

    var resultView = new ResultView()
    
  2. Then I include myApp.js, and parts of the View are overwritten.

  3. The main init() function calls results.js init() which instanciates the new View. Everything works nice, smooth and DRY.

Now I want to switch to require.js instead of my own module-container, and wonder how to organize my code.

I could either instanciate all models/views etc. in myApp.js instead of the init() function of each module. This would mean to have a lot of repetitive code.

Or I could stick to each module having its init() function, and call those init() functions in myApp.js. I don't like this because I would have to explicitly write down my modules three times for each of my three pages:

require(['module1', 'module2', 'module3', ...],
  function(module1, module2, module3, ...) {
    var init = function() {
      module1.init();
      module2.init();
      module3.init();
      ...
    }
    return {init: init};
  }
);

For 10 modules plus a number of libraries this is not nice and DRY. Is there any way to access (loop over) all modules that require.js holds?

Or am I missing something, should I structure my code in a different way?

Any hints/thoughts are welcome,

Michael

回答1:

As discussed in the comments above, you can avoid having to explicitly reference the parameters of the function by looping over them using the arguments object inside the function body. So:

require(['module1', 'module2', 'module3', ..., 'moduleN'],
  function(module1, module2, module3, ..., moduleN) {
    var init = function() {
        module1.init();
        module2.init();
        module3.init();
        ...
        moduleN.init();
    };
    return {init: init};
});

Becomes:

require(['module1', 'module2', 'module3', ..., 'moduleN'],
  function() {
    var args = arguments;
    var init = function() {
        var module;
        for (module in args) {
            if (args.hasOwnProperty(module) && typeof module.init === 'function') {
                module.init.call(this);
            }
        }
    };
    return {init: init};
});

I added in a hasOwnProperty() check inside the for in loop because, for a number of reasons, it's good practice. Also, you'll see the explicit check for init being a function before attempting to call it.

The reason for var args = arguments is so you can reference it from the inner function - otherwise you would be referencing the arguments passed to init(), which is not what you want.

As and aside, on an architectural level, I think the project structure you've described works incredibly well - I use it on a lot of very big projects and it's never let me down. Require.js is awesome! :)