Simulate async callback makes main require asynchronous, with no way to suppress it
les2 opened this issue · 6 comments
I ended up commenting out these lines beginning at 293:
//Simulate async callback;
//if (forceSync) { // LES: we need this to be synchronous, but there is no way to force it using r.js insertRequire config option; this is a workaround; i'm not sure why almond has this branch in here.
main(undef, deps, callback, relName);
//} else {
// setTimeout(function () {
// main(undef, deps, callback, relName);
// }, 15);
//}
(this code is inside this function):
requirejs = require = req = function (deps, callback, relName, forceSync) {
The insertRequire option of the optimizer script (r.js) does not allow passing the forceSync parameter. For a use case, I needed to execute everything synchronously in the main module until I have bootstrapped because a script included by another party needs some initialization stuff I export there.
The hack above works and didn't seem to break anything, but I was wondering if someone here would know exactly why the above hack is a bad idea?
The version of almond.js I downloaded was 0.1.2 .
Thanks!
Is this for a top-level require() call (not a require call inside a define())? If so, then this should work:
var a = require('a');
However, in general, top level require([], function () {}) calls should stay async to keep similar execution flows as the source-loaded code via require.js.
I believe I was making a "top-level require" call?
app.js:
(function () {
... almond.js here ...
... all my modules here ... define(........) x 1000
// oh, nos - this guy is async (which is okay, generally)
require(["wapo/app/main"]);
}());
The file is produced by running r.js with a profile more or less like this:
{
name: 'almond',
wrap: true,
include: [
'wapo/app/main'
],
insertRequire: ['wapo/app/main'], <------------- want this to be sync :(
paths: {
'almond': 'lib/almond/almond',
'wapo/app/config' : 'wapo/app/config/prod-config'
}
}
What I noticed stepping through the debugger was that I was going through that async path. Unfortunately, I could not find an option in the optimizer to force the synchronous version of the require call so I had to hack it to pieces.
Is there something I'm missing?
The require([]) form is async. Try require('') instead at the top level. To do that with an almond build, use wrap, but as startFile and wrap.endFile. The startFile can just be:
(function () {
and then the end file can be
require('wapo/app/main');
}());
then remove the insertRequire from the build config since the wrap.endFile will do the require. Also be sure to use the latest almond.js.
startFile / endFile are sweet! i converted the build to use the array versions for concat'ing external libraries for the "-with-dependencies.js" version of the build.
It would be cool if start / end could take a file name or the actual string - mixed into one (maybe a {content: 'foo'} if you are using mixed mode).
For example, I build several distributions of the project, with the difference in runtime behavior determined by the configuration used at compile time (so I can get handle the various deployments without nasty if statements all over the place):
var layers = [ {
layer: 'foo', <------ determines file name; a build {name}.min.js and {name}.full.js for each
config: { <----- requirejs optimizer config
},
... <----- other stuff i want to set for the layer
},
...
];
For some versions, I want to use: insertRequire: ['one', 'two', 'three']
For yet other versions, I use only: insertRequire: ['one']
If I use the wrap: { ... } config, I would need to put the require('one') in a separate file (because I am also the wrap to concatenate other libraries (I guess I could have a file pass to do that, but then I would need to optimize the entire file again).
startFile: [ 'some/lib1.js', 'some/lib2.js', 'var bar = lib2.noConflict(true);', '(function(){' ],
endFile: ['require(['one','two','three']); }());', 'maybe/another/file/here/why/i/know/not.js']
I guess I could just use require('one');require('two');require('three');... to get three sync versions.
Now that I think about it, it's probably not worth it. I can work around it.
+1 for insertSyncRequire
as an an option on r.js.
Last night I faced the exact same problem as les2, on uBerscore (an experimental facade over underscore).
uBescore has 'lodash' as a dependency on AMD, but internally all modules use _.
I basically want to have a 'standalone' .js library (along AMD) that can be <script/> loaded after some global '_' is globalized, so I used almond.
Unfortunately the async require([])
breaks it unless I setTimout.
So I intuitively used a 'modified' almond where just line ~354 if (forceSync)
becomes if (true)
, which does the trick!
To day found this issue and tryed the trick with wrap.endFile
, it worked.
But why not have an insertSyncRequire
or something by default ? Unless somebody read this post, s/he is in trouble...
@anodynos using the latest almond.js, if you do a wrap.endFile, you can have that file added to the end of the build, and that endFile can do the sync require supported by almond (not requirejs) at the top level:
window.globalName = require('moduleName');
Going to close this since this is possible now.