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>
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.