Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simulate async callback makes main require asynchronous, with no way to suppress it #42

Closed
les2 opened this issue Oct 12, 2012 · 6 comments

Comments

@les2
Copy link

les2 commented Oct 12, 2012

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!

@jrburke
Copy link
Member

jrburke commented Oct 14, 2012

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.

@les2
Copy link
Author

les2 commented Oct 15, 2012

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?

@jrburke
Copy link
Member

jrburke commented Oct 16, 2012

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.

@les2
Copy link
Author

les2 commented Oct 16, 2012

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.

@anodynos
Copy link

anodynos commented Dec 2, 2012

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

@jrburke
Copy link
Member

jrburke commented Dec 3, 2012

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants