Fork me on GitHub

Frequently Asked Questions

Why use Module Loaders?

Cause in modern single-page apps, you're not receiving just a data REST, but also executable code.

You want a dynamic code loading mechanism.

You want to follow standards and the available tools.

Either your app is on browser, mobile or even nodejs. Run single page Apps with truly dynamic code loading.

What exactly is the problem with AMD running on web / node as it is ? Why not use RequireJS / amdefine on node ?

There are various problems with modules in the current era.

Yes, RequireJS can be be used on node. Installed as a local package via npm its a large 600kb dependency, but that is not the problem.

  • RequireJS on node is strict on dependencies declarations on node, just like on web execution: if you ommit declaring a dependency on the dependency array define(['dep']...), it will fail when you require('dep') on the body (on node it actually returns 'undefined').

    Also, if you forget to list 'require' as your first dependency, you'll unleash hell: it'll work in some cases and some paths, not in others. This is all expected, due to the 'strictness' of the AMD standard. Hence, even this is not really the problem, just a caveat.

  • The real problem stems from the need to load your AMD-defined modules via RequireJs special 'adapter' (loader). Taken from its documentation :

var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});
requirejs(['foo', 'bar'], function(foo, bar) {});

This works ok for your AMD defined modules. But if you need to use a node-native .js module, residing on your file system, r.js fails with Error: Evaluating '/path/to/myLib.js' as module "myLib" failed with error: ReferenceError: module is not defined. See examples/rjs

One may ask, why would I need to load native nodejs modules from AMD/UMD modules that are supposed to be runnable on the web side mainly/also ?. One simple answer is cause you wanna share code between client & server, but also be able to inject code on either side at will. Perhaps this issue is a single stopper for using AMD on node.

uRequire modules overcome this problem: they can require any native node module as it is, without any special treatment, adapter or conversion. Third party code can get 'required' and work as it is. You only need to use the fake-plugin notation of require('node!./path/to/nativeNodeJsModule'), to signal that this module should not appear on AMD dependency array & then make sure at runtime that it gets loaded only when you are at nodejs (isNode & isWeb variables are provided for this purppose). See examples/nodeNative-requiredByABC_and_rjs and examples\abc\a-lib.

  • Similarly, your AMD defined modules can't be used by node-native modules as they are with requireJS. Your AMD modules start with define, which is unknown to the node runtime. So your node-native requiring modules need to be changed and instead load your native AMD-modules through requirejs, which means you need to alter them. This doesn't work if they happen to be third party code, or testers or other kind of loaders. And I think its a heavy burden by it self, even if its your own code. You should be focusing on you business logic, not how to load modules.

  • Path resolution is also problematic, relative & absolute paths are causes of problems and it breaks on testers like mocha or when you want to use multiple 'bundles' in one requiring module. Check this and this issues.

  • Copying from requirejs docs Even though RequireJS is an asynchronous loader in the browser, the RequireJS Node adapter loads modules synchronously in the Node environment to match the default loading behavior in Node. I think this can lead to problems, where asynch based code that is developed and tested on node runs ok, but fails miserably when it runs on web. Module systems should execute the same way on all sides, to the maximum possible extend.

Edit: This behaviour was fixed in RequireJS 2.1 'Enforcing async require'. uRequire endevours to match RequireJS's functionality, following its newest version's behaviour.

  • Using amdefine also leaves a lot to be desired: a single line makes 'define' available on node, but where does 'require' come from ? It comes from node. Hence no bundleRelative paths and no asynch version of require. And if you use the synch/node module = require('moduleName'), and works on the node side, you 'll need to remember to include 'require' and 'moduleName' on the dependencies array also. Finally mixing node-requirejs and amdefine is not an option either - they aren't meant to be used together - see some early failed attempts

What does urequire 'relaxed' notation solve ?

Consider this AMD example:

define(['main/dep1', 'main/helpers/dep2'], function(dep1, dep2) {
   var dep3 = require('moredeps/dep3');

   if (dep3(dep1) === 'wow'){
      require(['./dep4'], function(dep4) {
        // asynchronously do things with dep4
      });
   }

   // do stuff with dep1, dep2, dep3

   return {my:'module'}
});

This looks like a valid AMD module, but it would not work as AMD/RequireJS module. (it does only if its 'relaxed' form is massaged by uRequire and converted to UMD).

The line var dep3 = require('moredeps/dep3'); would fail on web/requirejs for two reasons:

a) require is not listed as a dependency

and

b) even if you had require listed, your app would halt because moredeps/dep3 is not listed as a dependency, i.e it is a missing require dep.

Further more, even if you fixed those two errors, if you were to run this in node, you would be missing define. You could turn to amdefine, but that would also fail on require('moredeps/dep3') because of the absolute/bunldeRelative path. Remember, with amdefine, require('') comes from node - i.e. no bundleRelative paths, no plugins, no asynchronous calls. For the last reason, the 2nd require would also fail, since this asynchronous format is not supported on node's require. For more or less the same reasons, you would have issues if you used requirejs on node.

With UMD produced by uRequire, you would overcome these issues instantly: your module is ready to run on both node and web as it is.

Hey, I like it so far, but I think its another format on its own. After all, it violates standards, it's a frankestein, its a tool that if you adopt, u have a dependency on it!

Not really.

  • If you stick to the standard AMD or nodeJs, you're fine on that side. And if you avoid using any DOM/node features (like node's require.resolve()) you get 'running on the other side' for free. Should you choose to adhere to the 100% standard syntax of AMD or nodejs, so that your pre-build source code is also valid/executable too, that's fine. uRequire will at least be usefull for performing sanity and dependency checks on your source before deploying (and get a report --verbose build:verbose}) while fixing common AMD errors like missing an array dependency.

  • If you use AMD 'relaxed' form, but want to go back to AMD strict for web's sake: At any time you can convert your 'relaxed' uRequire source to strict AMD and get done with it. You 'll never need uRequire again (but I'm sure you 'll come back!). And your code will still be able to convert to UMD so it runs on node.

  • If you use nodeJs with and have used the asynch require([], function(){}), and you want to go back to strict node format, you "ll have some more work to do converting to var a = require('a') and changing its asynch nature, but it shouldn't be so hard (the other way around is much harder).

I 've heard browserify makes node-style require() work in the browser with a server-side build step. Is it similar to this? Is it better ?

Similar? Better? not really. And at the same time, YES, absolutely!

U can think of this project as a distant counterpart to browserify, though it takes a completely different approach and has different results:

  • uRequire is better/different, because it works both sides: web-to-node and node-to-web. Also on web side, its using AMD, which seems to be the standard way to define web modules AMD. The claim is that AMD is the proper browser-optimized module system. But that should not prevent you, from running that same code on nodejs, as it is.

  • But NO, its not 'better' than browserify. It doesn't attempt to bring any of node's packages and functionality to the web (like browserify does). Only your modules are the issue here: your code that SHOULD run on both sides, WILL run. U must use non-dom, non-node stuff of course, if you want your code to work both ways.

    But hey, can I combine them ?

    See below, the FAQuestions with one answser.

Have you got any examples ?

uBerscore

Check github.com/anodynos/uBerscore project (which actually powers uRequire):

  • Just have a glance at the simple code structure of the main(MasterDefaultsConfig.coffee#bundle.main) 'uberscore.coffee'.

  • See examples/uBerscoreExample_XXX.html and spec/specRunnerXXX.html for how each build is used.

  • Check source/code/uRequireConfig.coffee & source/code/uRequireConfig_UMDBuild.json to see how easily you can define bundles and builds.

  • In Gruntfile.coffee check the urequire:xxx tasks to see some documented examples using grunt-urequire.

  • For the full config documentation see MasterDefaultsConfig.coffee.

amd-utils tutorial

Check a more real world one, UMDfying the amd-utils by millermedeiros

0) Grab a copy of amd-utils

1) Install urequire in it npm install urequire (and globally if u haven't already)

2) Run urequire UMD src -o UMD/src, which converts the main library files to uRequire UMD.

3) Copy tests/lib and test/SpecRunner.html into UMD/tests

4) Run urequire UMD tests/spec -o UMD/tests/spec, which converts the spec files to uRequire UMD.

At this point uRequire will complain that 'Bundle-looking dependencies not found in bundle' - this is expected: indeed, if you run it with jasmine-node UMD/tests/spec --matchall it will fail to find src\array\append etc because it has no idea where src\ is.

So just add a requirejs.config.json on the specs bundle root (tests/spec), copying from the requirejs config used in SpecRunner.html:

//file 'UMD/tests/spec/requirejs.config.json' on
{"paths": {"src" : "../../src"}}

Now if you run jasmine, all tests will run ok (but 3 specs requring DOM related objects).

Apart from those, the UMDfied amd-utils library now runs and tests on both browser and nodejs.

Hey, I dont want to convert my modules. Is it still usefull ?

Of course. It will run some sanity checks on your module bundles. More examples & functionality, watch this space!

FAQuestions with one answer.

Can I safely mix uRequire UMD modules with other 'native' modules, at each runtime (i.e on node and the browser) ?

Can I substitute a module at runtime with a different version, at each runtime ? i.e. can I have a different 'data/storage', at each runtime ?

Can I combine it with Browserify and make more awesome stuff ?

Will it do this or work with that in the future ?

Hey, is uRequire evolving to become a build system like grunt etc ?

Does it rock ?

Well, of course. Why not. In theory. <= v.0.1 was only a proof of concept. Now its v0.4 and does much more that I thought. I 've tried some configurations, but only a fraction of what's out there of course! They should all work, somehow, sometime. If they dont, they will. See the History / Roadmap below to get a better idea of future directions. I am eager to know and realize more usage patterns to incorporate. So, go play, try it out and make sure you let me know what issues & successes you're having!

BTW, uRequire requires U:
require ['volunteers', 'skills/solidjs/CoffeeScript', 'awesomeness'], (volunteers, jscs, awe)->
    modules = (require 'knowledgeOf/RequireJS/NodeJs/module/systems').preferable()
    (uTeam.members or= []).push v.welcome() for v in volunteers when (v jscs, modules) is awe;

  uRequire:'v1.0'

Does u in uRequire stems from UMD ?

No, from Universal. Require.