require()

Modul8's require() works hand in hand with a private define() call that gets pre-pended to the compiled source. On compilation each module is wrapped in a define call (ensuring encapsulation of private variables between modules) that give each of these modules the necessary context for the require() calls it may make. All context is stored via closures and will be hidden from you.

Ways to require

There are four different ways to use require:

File extensions

File extensions are never necessary, but you can (and sometimes should) include them for specificity (except for on the data domain).

The reason you perhaps should is that modul8 allows mixing and matching JavaScript, CoffeeScript, and other altJs languages, but is only as forgiving with such mixing as you deserve.

Server Behaviour

To see why, consider a simplified resolver algorithm from the server

name = require input, domain = domain of requiree
while(domain)
  return true if exists(domain + name)
  return true if exists(domain + name + '.js')
  return true if exists(domain + name + '.coffee')
  return true if exists(domain + name + altJsExt) //optional
  domain = nextDomain // if applicable (see require priority below)
return false

If you use CoffeeScript or other registered compilers for altJs languages, and if there is even a chance of a file of the same name with a .js extension popping up in the same folder, then you should only use require() with an explicitly specified file extension.

In short: DO NOT omit extensions and keep .js and .coffee versions in the same folder or you will quickly become very frustrated as to why your coffee changes arent doing anything.

Client Behaviour

modul8 will truncate the extension from the name passed to the internal define() wrapper. This has two advantages:

However, the server side collision problem applies. modul8 will only be able to define() one of

If you do use extensions (even partially), then modul8 will throw an error if multiple versions of domain::filename was attempted to be included. This error will be usefully be thrown after the .analysis() dependency tree was logged, allowing you to pinpoint the careless require().

Require Folders

Require strings not resolving as a file, or ending in a slash will try to resolve the name as a folder and look for a file named index following the above logic. The following will all resolve a folder, but the last has the possiblility of a collision with a file of the same name as the folder:

require('controllers/index');
require('controllers/'); //looks for controllers/index+extension
require('controllers'); //looks for controllers+extension then controllers/index+extension

Require Priority

Requires are attempted resolved with the following priority:

if require string is relative
  resolve absolutized require string on current domain
else if require string includes domain prefix
  resolve require string on specified domain
else //arbiter search
  resolve require string on the M8 domain

if none of the above true
  resolve on all domains, starting with current domain

//error

In other words, collisions should not occur unless you have duplicate files in different domains, and you are very relaxed about your domain specifiers or arbiter prefixes.

Hooking into define

modul8 defines way to help you attach objects/fn to certain domains both live on the client and from the server via data(). The API docs have full information on this.