Skip to content

Instantly share code, notes, and snippets.

@Integralist
Created January 23, 2012 14:35
Show Gist options
  • Save Integralist/1663422 to your computer and use it in GitHub Desktop.
Save Integralist/1663422 to your computer and use it in GitHub Desktop.
Beware of setting 'require' as a dependancy

Imagine this is your module…

define(['Utils/css'], function(css){

	console.log(css);
	
});

If your Utils/css dependancy was like the following…

define(['require'], function(require){

	return {
		style: require('Utils/CSS/getAppliedStyle'),
		classes: require('Utils/CSS/getArrayOfClassNames'),
		add: require('Utils/CSS/addClass'),
		remove: require('Utils/CSS/removeClass'),
		has: require('Utils/CSS/hasClass')
	}

});

…then you would have this error displayed: Uncaught Error: Module name 'Utils/CSS/getAppliedStyle' has not been loaded yet for context: _ because you created a race condition issue.

One work around would be to do…

define(['Utils/CSS/getAppliedStyle', 'Utils/CSS/getArrayOfClassNames', 'Utils/CSS/addClass', 'Utils/CSS/removeClass', 'Utils/CSS/hasClass'], function(getAppliedStyle, getArrayOfClassNames, addClass, removeClass, hasClass){

	return {
		style: getAppliedStyle,
		classes: getArrayOfClassNames,
		add: addClass,
		remove: removeClass,
		has: hasClass
	}

});

But that's FUGLY, so instead, go back to what we had before but just don't specify require as a dependancy…

define(function(require){

	return {
		style: require('Utils/CSS/getAppliedStyle'),
		classes: require('Utils/CSS/getArrayOfClassNames'),
		add: require('Utils/CSS/addClass'),
		remove: require('Utils/CSS/removeClass'),
		has: require('Utils/CSS/hasClass')
	}

});

I have an idea of why this works but maybe @jrburke can clarify.

@Integralist
Copy link
Author

@millermedeiros so to clarify: no dependencies and passing require as argument means modules are loaded synchronously. But the downside is that there is no check to first see whether the require'd module(s) have already been loaded. Where as the AMD async require() calls will check internally to make sure we're not double loading.

@millermedeiros
Copy link

the flow is basically:

no dependencies and +1 parameter define(function(require){ ... })

  1. call toString() on the callback function and read all the require('module_id') calls.
  2. load all the dependencies asynchronously.
  3. execute callback.

no dependencies and no parameters define(function(){ ... });

  1. execute callback

dependency array define(['require'], function(require){ ... })

  1. load all the dependencies on the array asynchronously.
  2. execute callback.

so as you can see both loads the files asynchronously but the later doesn't check the require('module_id') since it considers that all the dependencies are already on the array and/or all the internal require calls are asynchronous or are requiring modules that was previously loaded.

if you want the require('module_id') to work as if it was a CJS module you need to use the 1st pattern or use the full CJS wrapper (2-3 arguments):

define(function(require, exports, module){
  exports.foo = require('./foo');
});

@millermedeiros
Copy link

I just created a new page on the RequireJS wiki explaining the difference between the module formats and what RequireJS does internally: https://github.com/jrburke/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define

@Integralist
Copy link
Author

@millermedeiros thanks for the 'flow' style explanation that worked a lot better for me :-)
One other query though, why do you recommend using relative paths?
e.g. define(['./css'], function(css){ over define(['Utils/css'], function(css){
Is there a benefit that I'm not aware of, or is that just your personal preference?
I thought it would be 'clearer' the way I have it if I was to move this module from one project to another.

@millermedeiros
Copy link

since both will end up pointing at the same place I usually use relative paths to reference things that are inside the same folder, if you change the folder structure or decide to rename folders you don't need to go back and update everything. It's also more concise.

@Integralist
Copy link
Author

@millermedeiros actually yes the folder renaming thing could be a pain if not using relative paths. That's good enough for me, I'll change them :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment