How does AMD (specifically RequireJs) handle dependancies across multiple modules - requirejs

I have my main initialization script which calls require() and one of the dependencies is a utilities framework, but some of the other modules that I'm specifying via require() also themselves have defined this framework as a dependency.
For example (init.js):
require(['module-a', 'module-b', 'module-c'], function(a, b, c){
// where module-c is the framework
});
And then in 'module-a' I have:
define(['module-c'], function(c){
// utilize module-c framework
});
So how does AMD/RequireJs handle this scenario, does it load the same framework twice?
Any help appreciated.
Kind regards,
Mark

It will only be loaded once, both of the above modules will get the same module value for 'module-c'.

Incase its useful to others - Here's a situation I came across where a module was loaded twice:
For the following project structure:
~/prj/js/app/fileA.js
~/prj/js/app/util/fileB.js
~/prj/js/ext/publisher.js
where the RequireJs baseurl is ~/prj/js/app
fileA.js refers to the external (ext) dependancy publisher.js as:
//fileA:
define(['../ext/publisher'], function(){});
But fileB.js refers to the same dependancy with a different path:
//fileB:
define(['../../ext/publisher'], function(){});
In short, for both files, the dependency paths are different although the dependancy is in the same location. In this case, publisher.js gets loaded twice.
Use Firebug's Net tab to see it loading twice:
This is easily fixed using paths to configure the external folder path (as explained in the require_js docs):
requirejs.config({
paths: {ext: '../ext'}
});
After setting paths, the dependency is loaded just once with fileA.js and fileB.js both using the same dependency path as follows:
//fileA:
define(['ext/publisher'], function(){});
and
//fileB:
define(['ext/publisher'], function(){});

Related

RequireJS Multi Injecting

I am building a modular single page application which consumes multiple require config files from different sources. I would like a way in my application to be able to consume a list of all modules of a specific type. something like this:
define('module-type/an-implementation',...)
define('module-type/another-implementation',...)
require('module-type/*', function(modules){
$.each(modules,function(m){ m.doStuff(); });
})
This is similar patterns dependency injectors use with multiple dependency injection (eg. https://github.com/ninject/ninject/wiki/Multi-injection)
Is there a way to do this (or something similar) with require?
RequireJS doesn't know which modules exist until something requires them. Once a module is required / depended upon RequireJS will figure out where to request the module from based on module's name and RequireJS's configuration. Once the module is loaded it can be examined / executed to find out its dependencies and handle them in turn, until all dependencies are loaded and all module bodies are executed.
In order to be able to "consume a list of all modules of a specific type" something would need to be able to find all such modules. RequireJS doesn't have any means to know which modules exist, so it alone wouldn't be enough to implement "Multi Injection".
Speculation
Some kind of module registry could be created and populated with help of the build system: e.g. a file (say module-registry.js) could be generated each time a file in the source directory is added / removed or renamed, then multi inject could be possible like:
multiRequire('module-type/*', function(modules){
$.each(modules,function(m){ m.doStuff(); });
})
which in turn would call
require(findModules(pattern), function() {
callback(Array.prototype.slice.call(arguments, 0));
});
(where multiRequire and findModules are provided by the module registry).

Re-declaring libraries as dependencies within every single module

I'm working on the project that uses require.js and I was faced with a simple question about declaring libraries as dependencies within every single modules. I saw many examples with require.js and in every of them libraries like Backbone, jquery, underscore etc was declared in every module. And it would be fine if your application consists of only couple of modules. But if your application has 40-50 modules it becomes a bit tedious to define jquery every single time.
On the other hand we can load all libraries into the require() this way:
// Just an example
require.config({
paths: {
jquery: '../bower_components/jquery/jquery',
underscore: '../bower_components/underscore/underscore',
backbone: '../bower_components/backbone/backbone'
}
});
require(['jquery', 'underscore', 'backbone'], function () {
require([
'app',
'bootstrap'
], function (App) {
var app = new App();
document.body.appendChild(app.el);
});
});
And then we can use Backbone, '_' and '$' into the App without declaring them as dependencies.
So I'm trying to understand why we should define them every time. Is it just a strict adherence to the Module pattern or something else?
Thanks.
Having your libraries passed in as arguments to your require factory function is a form of dependency injection. Now, depending on exactly how AMD-friendly your library dependencies are, you may even be able to use several different versions of the library at once in an application. Writing your modules in this way with explicit library dependencies can allow you future flexibility of mixing modules which require jQuery 1.8 and jQuery 2.0, for instance. A different jQuery version can be passed to each module.
When you don’t define all your dependencies explicitly every time, then you’re relying on the global variable (window.$ or window._) created as a side effect of loading the library. In that case, all the modules have to depend on the same version of the library.

RequireJS Path With JS Extension Not Resolving

I am using a library that (very selfishly, IMHO) assumes that the baseUrl will point to the company's CDN:
baseUrl: "[http protocol slash slash]cdn.wijmo.com/amd-js/"
At first I thought that I would just copy the contents of the above Url to my own folder (such as /scripts/wijmo/amd-js), but that doesn't work because the good folks at Wijmo hardcoded path references in their AMD define statements, such as this:
define(["./wijmo.widget"], function () { ... });
What the above means (if I understand things properly) is that if you have any other non-Wijmo AMD modules then you must either:
(a) place them under the amd-js path, perhaps in a sub-folder named "myScripts"
(b) use hard-coded RequireJS path references to your own AMDs, like this:
paths: {
"myAMD_1": "http://www.example.com/scripts/myScripts/myAMD_1",
"myAMD_2": "/scripts/myScripts/myAMD_2.js"
}
(a) works, but it means that the baseUrl cannot point to the Wijmo CDN because I don't have access to the Wijmo CDN site so I must move the files published under amd-js to my own server.
(b) sort of work, and here is my problem: If I use syntax myAMD_1 then all is well. But that doesn't let me test on my local development machine, which uses localhost. (I don't want to get into detecting which server I'm running on and customize the paths value... I want the path to remain the same before and after I publish to my http server.)
Now, according to the RequireJS documentation:
There may be times when you do want to reference a script directly and not conform to the "baseUrl + paths" rules for finding it. If a module ID has one of the following characteristics, the ID will not be passed through the "baseUrl + paths" configuration, and just be treated like a regular URL that is relative to the document:
* Ends in ".js".
* Starts with a "/".
* Contains an URL protocol, like "http:" or "https:".
When I try to end (terminate) my path reference with .js (as shown in AMD_2 above), RequireJS doesn't find my AMD and because it ends up looking for myAMD_2.js.js (notice the two .js suffixes). So it looks like RequireJS is no longer honoring what the docs say it employs as a path-resolution algorithm. With the .js suffix not working properly, I can't easily fix references to my own AMDs because I don't know for sure what server name or physical path structure they'll be published to--I really want to use relative paths.
Finally, I don't want to change Wijmo's AMD modules not only because they're are dozens of them, but also because I would need to re-apply my customizations each time they issue a Wijmo update.
So if my baseUrl has to point to a hard-coded Wijmo path then how can I use my own AMDs without placing them in a subfolder under the Wijmo path and without making any fixed-path or Url assumptions about where my own AMDs are published?
I can suggest a couple of approaches to consider here--both have some drawbacks, but can work.
The first approach is to provide a path for each and every Wijmo module that needs to be loaded. This will work, but you have touched on the obvious drawbacks of this approach in the description of the question: Wijmo has many modules that will need to be referenced, and maintaining the module list across updates in the future may be problematic.
If you can live with those drawbacks, here is what the RequireJS config would look like:
require.config({
paths: {
'wijmo.wijgrid': 'http://cdn.wijmo.com/amd-js/wijmo.wijgrid',
'wijmo.widget': 'http://cdn.wijmo.com/amd-js/wijmo.widget',
'wijmo.wijutil': 'http://cdn.wijmo.com/amd-js/wijmo.wijutil',
// ... List all relevant Wijmo modules here
}
});
require(['wijmo.wijgrid'], function() { /* ... */ });
The second approach is to initially configure the RequireJS baseUrl to load the Wijmo modules. Then once Wijmo modules have been loaded, re-configure RequireJS to be able to load your local app modules. The drawback of this approach is that all the Wijmo modules will need to be loaded up front, so you lose the ability to require Wijmo modules as needed within your own modules. This drawback will need to be balanced against the nastiness of listing out explicit paths for all the Wijmo modules as done in the first approach.
For example:
require.config({
baseUrl: 'http://cdn.wijmo.com/amd-js',
paths: {
// ... List minimal modules such as Jquery and Globalize as per Wijmo documentation
}
});
require(['wijmo.wijgrid'], function() {
require.config({
baseUrl: '.'
});
require(['main'], function() {
/* ... */
});
});

Typescript/RequireJS having issues with an MVC application

I have the following code in Visual Studio, in an MVC application;
/scripts/bin/models/ViewModel.ts
export class ViewModel {
// view model code
}
Now, I have downloaded requirejs, and set the build mode for typescript to AMD type, so that its output looks such as....
define(["require", "exports"], function(require, exports) {
And so on ...
So then I declare my app/config.js file like so;
require.config({
baseUrl: '/scripts/bin'
});
And I try to load this up, I have requirejs loaded into the scripts, and attempt to call it...
require(['models/ViewModel'], function (viewModel) {
console.log("test");
});
And I am simply told that it is an invalid call. No other details. The path that it shows is completely correct, too. Is there some kind of additional configuration required? The requirejs documentation is extremely vague about this.
SOLUTION
This turned out to have nothing to do with requirejs, but instead had to do with IIS.
By default, IIS has a rule known as hiddenSegments. It does not allow you to bring in any code from a folder with bin in the path. I simply renamed the folder from bin to something else, and it worked fine.
Using require.js with TypeScript is a combination of your .html, require.config, module exports and imports.
For a step-by-step guide on moving from CommonJs TypeScript to AMD and require.js, have a look here.
Have fun.
The TypeScript compiler doesn't have any knowledge of your require.config - so when you use paths relative to that baseUrl they look invalid to the compiler.
Until something is done to bridge that slight mismatch (i.e. make the compiler super-clever so it can look for require.config sections and use them to check paths) it is easier not to set a baseUrl and use the full path in your import statements:
import vm = require('./scripts/bin/models/ViewModel');
Are you sure that the require call is done with [] and not just
require('models/ViewModel', function (viewModel) { // this is an error
console.log("test");
});
See : http://requirejs.org/docs/errors.html#requireargs

RequireJS - loading multiple config files

I am trying to load several RequireJS configs. In my html I am loading my main config via
<script src="../lib/require.js" data-main="../app/requireConfig"></script>
and once the document is ready I want to load all my plugin configs. So I created a new define file which holds a function that calls require.config:
define(['sharedServices/logger'], function (logger) {
function configVideo() {
logger.info('Adding video modules');
require.config({
path: {
Capabilities: 'videoProvider/Capabilities',
VideoProviderEnums: 'videoProvider/VideoProviderEnums',
VideoProviderCommon: 'videoProvider/VideoProviderCommon',
VideoProviderInstance: 'videoProvider/VideoProviderInstance',
DummyVideoInstance: 'videoProvider/DummyProvider/DummyVideoInstance'
}
});
}
return {
configVideo: configVideo
};
})
However, I get the following error:
Uncaught Error: Mismatched anonymous define() module: function (logger) {
The error you're getting isn't directly related to the stated problem (loading multiple configurations), but is caused by the way your code loading is organized. As the manual says:
To avoid the error:
Be sure to load all scripts that call define() via the RequireJS API. Do not manually code script tags in HTML to load scripts that have define() calls in them.
If you manually code an HTML script tag, be sure it only includes named modules, and that an anonymous module that will have the same name as one of the modules in that file is not loaded.
So the problem now is that when loading the module manually (as you state "when the document is ready", could you clarify how the quoted source is actually loaded?) requirejs doesn't know where the module came from, so it can't assign it a name. If the module were loaded via requirejs api (e.g. if it appeared in a dependencies list of a define call) and it were requirejs itself that determined its script path, it would name the module after the file.
In general it is advisable to have just a single script tag loading all the requirejs-managed javascript. This makes the development setup more closely match the eventual optimized situation (where all the scripts are concatenated together). It is still possible to make require.config calls inside individual modules if necessary and make some code execute only after document is ready. As an example, many our apps do something like the following in their main.js (the module loaded by the requirejs script tag):
// sort of bootstrap config
require.config({
packages: [{
name: "our-framework",
location: "../../our-framework/src/"
}],
// here some app-specific requirejs options
waitSeconds: 5
});
// load the framework, the "our-framework/rjs-config" contains
// framework specific requirejs config (another require.config call)
require(["our-framework/rjs-config"], function() {
// in this context both require configs are loaded
require(["application"], function(application) {
application.init().run();
});
});

Resources