How to load multiple named AMD modules defined in a single file? - requirejs

My understanding is that it shouldn't happen, but it does. What is the most appropriate workaround for these libraries?
Notes:
I figured running these scripts after require.js manually (using a script tag) should work, and indeed it seems like it does. However, the RequireJS documentation explicitly warns that the data-main script is run asynchronously. While require.js should have properly defined the define function needed by the scripts defining multiple named modules, I also assume that without the proper configuration loaded from the data-main script, bad things may happen in a non-deterministic way. Is this correct?
I also fail to see how any combination of the shim, map, bundles and paths configuration properties can help in this case, although I hope I'm missing it.
Clarification on the first note: (My bad, it's really not clear)
What I describe here is simply to manually execute (using an HTML script tag) the script that defines multiple modules after RequireJS and the data-main script. With the knowledge that the latter is run async, my worries should become more obvious (but feel free to ask me to detail some more). The bulk of it is that although it seems like I can require each named module successfully, I'm not sure that the behavior is deterministic (also, it's not pretty, I'd much rather avoid additional script tags and properly load everything asynchronously).
<script src="scripts/require.js" data-main="app/main.js"></script>
<script src="scripts/datajs-1.1.2.js"></script>
Here, datajs-1.1.2.js defines two modules, as described in the link above and copied below:
// AMD support
if (typeof define === 'function' && define.amd) {
define('datajs', datajs);
define('OData', odata);
} ...

What will and will not work depends on the specifics of how the file which defines multiple named modules will be used in an application.
In general, if the order in which modules defined (using named defines) in a single file cannot be determined, then setting paths to map the module names to the file that defines them should prevent problems:
paths: {
'foo': 'path/to/foobar',
'bar': 'path/to/foobar'
}
If foo or bar are required, RequireJS will load the file that defines both (path/to/foobar.js), which is not a problem.
With the details that you've added to the question, I can say this. First, this code:
<script src="scripts/require.js" data-main="app/main.js"></script>
<script src="scripts/datajs-1.1.2.js"></script>
is incorrect. Loading a module that calls define through a <script> tag is generally wrong. (I would say it is always wrong, but there may be some really strange cases where to get incompatible assets to work together you have to do something that would normally be wrong. But this is unusual, and has to be justified.) As you suggested by doing this, you open yourself to timing issues. Sometimes it may work, sometimes it may not.
However, this should prevent any timing issues:
<script>
require = {
paths: {
datajs: 'scripts/datajs-1.1.2',
OData: 'scripts/datajs-1.1.2'
}
};
</script>
<script src="scripts/require.js" data-main="app/main.js"></script>
Whenever anything needs either of the two modules in datajs-1.1.2.js, either because it called require or because it called define with the appropriate module names, the file that defines both modules is going to be loaded.
(Warning: the configuration I show in the example above is an educated guess, which contains enough details to illustrate. It may not work once combined with a configuration already present in app/main.js, and I'm not suggesting that it is the best way to configure RequireJS for your specific application.)
For RequireJS version 2.1.10 and higher, there's also the bundles option, which is nicer to use:
<script>
require = {
bundles: {
"js/datajs-1.1.2": ["datajs", "OData"]
}
};
</script>
<script src="scripts/require.js" data-main="app/main.js"></script>
I suggest reading the documentation on this option to avoid possible misunderstandings as to how it works.

Related

requirejs: parse a file and return its dependencies

I have a situation where I need to load (via AJAX in a browser) a file that defines a requirejs module (without executing it) and get back a list of its dependencies.
Ie, given a file that starts with
requirejs(["foo/bar", "foo/baz"], function(bar, baz) {
I'd like the utility to return an array like
["foo/bar", "foo/baz"]
I've found some solutions that will do it using r.js (for example, the ones outlined here: https://groups.google.com/forum/#!msg/requirejs/4C0deWFqpZY/mkZFlw2r_k4J), but nothing to do it in a browser. I can just parse out the require statement myself, but that seems suboptimal. Has anyone come across any solutions for this?

RequireJS - When specify module id in define()

In RequireJS documents (http://requirejs.org/docs/api.html#modulename), I couldn't understand this sentence.
You can explicitly name modules yourself, but it makes the modules less portable
My question is
Why explicitly naming module makes less portable?
When explicitly naming module needed?
Why explicitly naming module makes less portable?
If you do not give the module a name explicitly, RequireJS is free to name it whichever way it wants, which gives you more freedom regarding the name you can use to refer to the module. Let's say you have a module the file bar.js. You could give RequireJS this path:
paths: {
"foo": "bar"
}
And you could load the module under the name "foo". If you had given a name to the module in the define call, then you'd be forced to use that name. An excellent example of this problem is with jQuery. It so happens that the jQuery developers have decided (for no good reason I can discern) to hardcode the module name "jquery" in the code of jQuery. Once in a while someone comes on SO complaining that their code won't work and their paths has this:
paths: {
jQuery: "path/to/jquery"
}
This does not work because of the hardcoded name. The paths configuration has to use the name "jquery", all lower case. (A map configuration can be used to map "jquery" to "jQuery".)
When explicitly naming module needed?
It is needed when there is no other way to name the module. A good example is r.js when it concatenates multiple modules together into one file. If the modules were not named during concatenation, there would be no way to refer to them. So r.js adds explicit names to all the modules it concatenates (unless you tell it not to do it or unless the module is already named).
Sometimes I use explicit naming for what I call "glue" or "utility" modules. For instance, suppose that jQuery is already loaded through a script element before RequireJS but I also want my RequireJS modules to be able to require the module jquery to access jQuery rather than rely on the global $. If I ever want to run my code in a context where there is no global jQuery to get, then I don't have to modify it for this situation. I might have a main file like this:
define('jquery', function () {
return $;
});
require.config({ ... });
The jquery module is there only to satisfy modules that need jQuery. There's nothing gained by putting it into a separate file, and to be referred to properly, it has to be named explicitly.
Here's why named modules are less portable, from Sitepen's "AMD, The Definite Source":
AMD is also “anonymous”, meaning that the module does not have to hard-code any references to its own path, the module name relies solely on its file name and directory path, greatly easing any refactoring efforts.
http://www.sitepen.com/blog/2012/06/25/amd-the-definitive-source/
And from Addy Osmani's "Writing modular javascript":
When working with anonymous modules, the idea of a module's identity is DRY, making it trivial to avoid duplication of filenames and code. Because the code is more portable, it can be easily moved to other locations (or around the file-system) without needing to alter the code itself or change its ID. The module_id is equivalent to folder paths in simple packages and when not used in packages. Developers can also run the same code on multiple environments just by using an AMD optimizer that works with a CommonJS environment such as r.js.
http://addyosmani.com/writing-modular-js/
Why one would need a explicitly named module, again from Addy Osmani's "Writing modular javascript":
The module_id is an optional argument which is typically only required when non-AMD concatenation tools are being used (there may be some other edge cases where it's useful too).

Is there any way to define global dependencies in Require.js?

Backstory:
I've currently got a Require.js and jQuery/Backbone.js using site. Until now, jQuery and Backbone have stayed outside of Require, letting me do:
define([], function() {
// NOTE: Using Backbone and $ without an import!
new Backbone.View(el: $('#foo');
});
That's worked really well: without that approach, just about every module in my site would have to add a Backbone/jQuery dependency.
But then the other day I needed to package up a portion of our code as an external library. I made a separate require config file for it, and everything seemed great, until I compiled ("optimized") all the files in to a single library file, and realized that Backbone/jQuery (and related plug-ins/libraries) weren't getting included.
So, I added a bunch of shims, and got Backbone, jQuery, and all the related libraries in to Require. However, I still have a ton of modules that expect $ and Backbone to just exist. That should be ok, because Backbone/jQuery both register their variables globally, but it's not because of Require's load order.
Basically, any module without dependencies is broken, because they load before Require loads the jQuery/Backbone shim. Any modules that have dependencies don't have this issue, because jQuery/Backbone have already been loaded by the time they get loaded.
It seems like my only option is to add an explicit Backbone/jQuery to every module without dependencies. I've got a bunch of modules like that though, and ideally I'd prefer not to have to import jQuery/Backbone anywhere.
Question
So, my question is: is there any way to tell Require "load these X modules/shims before you load everything else"? Or, to put it another way, is there any way to tell Require that all of my modules depend on certain other modules?
I thought putting Backbone at the top of my initial require:
require(['backbone', ...
but that didn't help; the other dependency-less modules still load before it.
I see no reason this would not work:
require(['backbone', 'jquery'], function () {
require(['main']);
});
The idea is to wrap what was your initial entry point to your application in a require call that loads Backbone and jQuery. If the modules of your application are loaded only because main is required (that is, if there is no require call elsewhere that loads any module needed by main), then with the code above both Backbone and jQuery are guaranteed to be loaded before any of the modules used by main are.

Is there a difference between `requirejs` and `require` to set RequireJS' configuration?

I've found many examples where config set in this way:
require.config({
'path':{'':''}
})
and many examples where config set in this way:
requirejs.config({
'path':{'':''}
})
Which is right? When must one use one over the other?
In general, both are correct. RequireJS defines require and requirejs as global symbols. The two symbols are equivalent.
However, if something has already defined a global function named require before RequireJS is loaded, then RequireJS will leave it alone and will only define itself as requirejs. In this case, you cannot use require to do anything with RequireJS. You have to use requirejs instead.
(However the option name is paths, not path. You have path in your question.)

require() in large, multi-file Node projects

I'm working on a large Node project. Naturally, I want to break this into multiple source files. There are many modules from the standard lib that I use in a majority of my source files, and there are also quite a few of my own files that I want to use almost everywhere.
I've been making this work by including a huge require block at the beginning of each source file, but this feels awfully redundant. Is there a better way to do this? Or is this an intended consequence of Node's admirable module system?
You can use a container module to load a series of modules. For example, given the following project structure:
lib/
index.js
module1.js
module2.js
main.js
You can have index.js import the other modules in the library.
# index.js
module.exports.module1 = require('./module1');
module.exports.module2 = require('./module2');
Then main.js need only import a single module:
# main.js
var lib = require('./lib');
lib.module1.doSomething();
lib.module2.doSomethingElse();
This technique can be expanded, reducing redundant imports.
I'd say generally that a require block is better practice than using global in Node.
You need to remember that requires are cached so when you put them in all of your code modules, you will always get the same instance not a new one each time.
Doing it this way ensures that you get the appropriate code with the expected name spaces exactly where you want it whereas using global will include things you don't need. Doing it the Node way with require will also tend to make your code slightly more portable.
Well, a couple of things, here.
First, if so many of your files are requiring the same libraries over and over again, you might want to step back and determine if you're really breaking your code up in the proper way. Perhaps there's a better organization where certain libraries are only needed by subsets of your source files?
Second, remember that the global object is shared between all of your required files in your Node.js app. Your "root" source file, say index.js, can do things like global.fs = require('fs'); and then it's accessible from all of your various files. This would eliminate the need to require a file full of requires. (In Node.js, you have to explicitly state that you're accessing a global variable by prepending global., unlike in the browser.)
This can be a good idea for CRUD-type Express apps where you have lots of code for controllers that are all almost the same but have to be slightly different for each view and you just want to split them apart not for any particular organization structure, but just to make it easier to debug (error in this file, not that file). If the structure of the app is more complex than that, take the usual warnings against global variables to heart before using that trick.
Require more than one file without absolute path through require-file-directory.
1- Can require more than one file in single statement.
2- Can require files with only their name.
Visit for solution: https://www.npmjs.com/package/require-file-directory

Resources