2

I'd like to define A, but A should require B and B require C (for the sake of r.js)

Any of the these two are correct?

define([
    'module'
], function(module) {
    require(['C'], function() {
        require(['B'], function() {

            var A;

            return A;
        });
    });
});


require(['C'], function() {
    require(['B'], function() {
        define([
            'module'
        ], function(module) {
            var A;

            return A;
        });
    });
});
eugene
  • 39,839
  • 68
  • 255
  • 489

2 Answers2

5

Neither of your choices are correct.

You first choice attempts to use return to return a value from an asynchronous callback. It is generally not possible, and RequireJS is no different. See this question and its answers for why it is that way.

Your second choice puts a define inside a callback passed to require. This may work in some toy cases but in general this just won't work. (By "toy case" I mean proof-of-concepts where all conditions are under tight control. Such cases do not reflect the realities of real applications.)

Linh Pham's suggestion is really your option here:

define(["module", "B", "C"], function(module){
    var A;

    return A;
});

And if B depends on C and is not a AMD library, put a shim for it. In a comment you objected that you'd have to have "hundreds" of shims if you did this. You have a few options to avoid these shims:

  1. Do not load C with RequireJS. Load it with a script element before RequireJS is loaded on your page.

  2. Design your application to be started with just one module and require that your application be started by loading C before anything else:

    require(['C'], function () {
        require(['main']);
    });
    

    main would be the module that starts your application. The disadvantage of this method is that if you are like me, eventually, you are going to forget to require C before you require main.

Community
  • 1
  • 1
Louis
  • 146,715
  • 28
  • 274
  • 320
  • or simply use `deps: ["C", "main"]` in `require.config` _(note: `deps` at the same level with `shim`, `path` or `baseUrl`... etc..)_, I think this should be short and clearer. – Linh Pham Apr 01 '15 at 10:44
  • @LinhPham `deps: ["C"]` is *asynchronous*. There is no point in time by which it is guaranteed that `C` will be loaded. So if you adapt my last example to use `deps:["C"]` instead of `require(['C'], ...` chances are that `require(['main'])` will execute *before* `C` is loaded. – Louis Apr 01 '15 at 10:46
  • That is very useful info, so in order to use `deps: ["C", "main"]` I will need to config `shim` for `main` module like: `shim:{ "main" : ["C"] }` right? – Linh Pham Apr 01 '15 at 10:48
  • Yes, if `main` happens to be a non-AMD module. I did not state it explicitly in my answer but `main` should be an AMD module since it is created for the application developed by the OP. – Louis Apr 01 '15 at 10:52
  • Your second option is what I adapted. – eugene Apr 02 '15 at 05:20
1

just put deps inside define block, like this:

define(["module", "B", "C"], function(module){
    var A;

    return A;
});

If your module B depend on C then you should config it in your require.config like following

shim: {
    "B": ["C"] // shorthand of "B": {deps: ["C"]}
}
Linh Pham
  • 3,005
  • 23
  • 34
  • That's a good idea. Unfortunately I can't use it. C is like a library module, and I should add hundreds of shim configs if I use this. – eugene Apr 01 '15 at 09:25
  • you mean that `C` will be used globally, and all the modules depend on it? – Linh Pham Apr 01 '15 at 10:07
  • C is not global, but it is required by so many modules so I won't attempt to list them all in shim config. – eugene Apr 02 '15 at 05:19