Search code examples
jqueryknockout.jsrequirejsamdnested

How to remove nested RequireJS calls?


I got a job to refac a quite complex app by introducing RequireJS. The app uses a engine with a complex class tree. While struggling to achieve my goals and learning about AMD I got a lot of questions but I'll try to stick just to the first one. I got a bad time loading just jQuery+knockout+mapping+Sammy but managed to work it using nested requireJS calls. The code belows works but I'm not satisfied with the nested requires. How to remove the nesting and just use a single requireJS call?


    // my first require: myBoot.js

/* [www](index.html) |------scripts (app lies here) |-------libs (3th party libs) |-------engine (base URL) */ requirejs.config({ "baseUrl": "scripts/engine", "paths": { "app": "../", "lib": "../libs", "knockout": "../libs/knockout-2.2.1.debug" }//, //"shim": { // "lib/jquery.mylibA": ["lib/jquery-2.0.0"], // "lib/jquery.mylibB": ["lib/jquery-2.0.0"] //} }); // load jquery requirejs(["lib/jquery-2.0.0"], function ($) { // load third party libraries requirejs(["knockout", "lib/knockout.mapping-latest", "lib/sammy-latest.min"], function (ko, komap, Sammy) { // Oh god! why? ko.mapping = komap; window.ko = ko; window.Sammy = Sammy; // load my self-made libs requirejs(["lib/jquery.mylibA", "lib/jquery.mylibB" // load my engine e FOOlings , "FOOEngine" // each FOOlings is a node in a FOO tree of classes, the goal here is to load them by demand , "FOOling00" , /* 40 more FOOlings */ , "FOOling41" // load my app ,"app/xmlLoader", "app/MoreLoaderStuff", "app/App"]); }); }); /* // example on FOOlings: function FOOling21(settings) { var self = this; // lots of stuff: initialize, constructor, propertiers, methods... //#region Constructor if (settings) { $.extend(this, settings); } //#endregion // can depend on other FOOlings like FOOling11 and FOOling02 // can request data from web services // can uses ko to do binding data // can depend on other libs // etc return this; } // can turn in? (for the sake of the example, F21 extendes F02 and uses F11 for generic stuff) define(["FOOling11", "FOOling02"], function(f11, f02) { return { function FOOling21() { var self = this; //#region Constructor if (f02) { $.extend(this, f02); } //#endregion //... return this; } } // or is a best pratice to do this way? define(["FOOling11", "FOOling02"], function(f11, f02) { return { var settings = f02; function FOOling21(settings) { // no changes ... return this; } } */ </pre></code>

Solution

  • I posted an answer here that may help answer your question.

    The answer I linked to above will explain this process a little more, but you can rely heavily on the require.js configuration object to build up scripts as shown here:

    var require = {
      paths: {
        'knockout': '...',
        'mapping': '...'
      },
    
      // configuration dependencies
    
      deps: ['knockout', 'mapping'],
    
      // configuration callback
    
      callback: function (ko, mapping) {
        ko.mapping = mapping;
      }
    };
    

    In the sample above, deps are loaded with require and callback is then fired where we are able to attach mapping to the ko object. All future requirements for knockout will include the mapping property we just added:

    define(['knockout'], function (ko) {
      ko.mapping // mapping is accessible in other modules
    });
    

    Using this pattern, you can setup and "compose" scripts as needed as part of the overall require.js configuration/initialization process.