Re-declaring libraries as dependencies within every single module - requirejs

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.

Related

Require.js Optimizer incorrectly ordering shim dependencies

I have a web application that uses Require in order to load dependencies. I have a set of JS libraries that are included using the Require config.shim object.
Two such example libraries are:
require.config({
shim: {
"libs/leaflet": {
exports: "L"
}
"libs/leaflet-dvf": {
deps: ["libs/leaflet"],
exports: "L"
}
}
The second library, leaflet-dvf requires the first, leaflet. The second is a plugin to the first that depends on the global scope variable L that the first library defines.
When I run the application using Require normally, everything works fine. I can include either library from the shim, and everything works great. No problems.
The problem comes when I run this code through the Require r.js Optimizer. The Optimizer, when it builds the single optimized JS file, will incorrectly order the dependencies. In the built file, the leaflet-dvf code will come before the leaflet code. This causes a JS runtime error because the dependant plugin cannot find the L global scope variable that is required.
My build config looks like:
({
baseUrl: "../js",
paths: {
"requireLib": "../js/libs/require"
},
include: ["requireLib"],
name: "Main",
out: "bin/Main-built.js",
optimize: "none",
wrapShim: true
})
When I run the Optimizer, using Rhino, it builds my output file. In the Main-built.js file, the code for the plugin will come before the required library. This causes an L undefined error.
How do I get the Optimizer to respect the dependency order of my Shims, in order to properly order the library files in my Optimized JS file?
I had a similar problem a while back with knockout extensions and shim didn't work correctly. This is how we solved it.
Create a module called: leafletLib
define(["libs/leaflet","libs/leadleft-dvf"],function(leftlet,dvf){
return leaflet;
});
LeafletLib has the main library and all of the extensions. On modules that have leaflet or leaflet-dvf as a dependancy you call leafletLib. It is kind of hacky but it might work for you.
define(["leafletLib"],function(leafletLib){});

Why do I need to add a "shim" for AngularJS when using Require.js?

I have seen several examples that use this:
main.js
/*global require*/
'use strict';
require.config({
paths: {
angular: './angular',
app: './Content/app',
ngAnimate: './Scripts/angular-animate',
uiRouter: './Scripts/angular-ui-router'
},
shim: {
angular: {
exports: 'angular'
}
}
});
require(['angular', 'app'], function (angular) {
angular.bootstrap(document, ['app']);
});
Can someone explain to me why the shim is needed? My application uses other modules such as angular-ui router, jQuery etc. Do I need to do something similar and add a shim for these?
The rule is pretty simple: if a library/script/package/plugin is AMD-aware, then you don't need a shim. (Actually, you must not use a shim for it.) If it is not AMD-aware, then you need a shim.
A library/etc is AMD-aware if it detects that an AMD loader is present and calls define to make itself known to the loader.
jQuery from about 1.8 onwards has not needed a shim because it calls define. Angular, on the other hand, does not call define.
To know whether a specific piece of code needs a shim, you can read its documentation or if the documentation is not clear on this, then you can check the source code for a call to define. For instance jQuery 1.11.0 has this code:
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
});
}
How it looks like will vary from one case to the other but the basic think you want to look for is the check that define exists, is a function, has the amd property set and the call to define.
(Note that jQuery is a special case where they decided to hard code the name of the module in the define call (first parameter: jquery). Generally the name of the module won't be present in the define call but will be left for RequireJS to infer on the basis of the file name.)

requirejs with existing globals

I have a built library (concatenated, minified and included before require.js) of several globals (jQuery + plugins, constructor functions, etc ). This library is used as a base on which apps are built on top of, with assumed dependencies. i.e, if I include my app scripts after the library, then I can freely use jQuery and constructors without any issues.
For bigger apps I'm considering using requirejs (to manage the different modules within the app), while still using this built library. How might I add existing globals like jQuery to the dependency list in require?
<script src="pathto/lib.js" type="text/javascript"></script>
<script src="require.js" data-main="../js/app" type="text/javascript"></script>
requirejs.config({
shim: {
'jquery': {
exports: '$'
}
},
// jQuery is already loaded with lib.js, no need for any path...
path : {
jquery : 'jquery.js'
}
});
Is this possible? Or should I just continue with assumptions that certain globals will exist within the app modules because lib.js was included before require / the app js?
Using require to load the lib.js is not possible, because it is part of a CMS.
-- EDIT --
What about using a named module, and just return a handle on the global object, as that is where the lib content sits anyway?
define("lib", function () {
return this;
});
require(["lib"], function (lib) {
// use existing globals found in lib via
lib.jQuery
// or simply
jQuery
});
That allows me to follow the require() convention of naming dependencies, rather than assuming.
I am doing the exact same thing for my project where I load jquery from a CDN, so my path configuration looks like this
path: {
'jquery': '//path/to/the/cdn'
}
In your case, I think you should do as you updated (define and then return), because in some 3rd-party libraries, they might define jquery as the dependencies. If you don't have jquery in your RequireJS configuration, you have to modify the source code of the 3rd party libraries

Do RequireJS modules "inherit" dependencies?

If I have a module that requires an application namespace, e.g.:
define(["app"], function(App){
[...]
});
... and the namespace requires libraries used by all of my modules, e.g.:
define(["jquery", "underscore", "backbone"], function($, _, Backbone){
[...]
});
... then all of my modules have access to the libraries required by the namespace, i.e. I can use $, _, and Backbone.
I like this behavior because I can avoid being repetitious, but I suspect that I'm cheating somehow, and that I should require libraries in each module.
Can anyone set me straight here?
Yeah, that's kinda hacky. You only have access to jQuery, underscore and backbone because they're also defined onto the global scope. Backbone and undersocre aren't real AMD module, they have to use a shim config. jQuery declare himself on the global scope and as an AMD module so it works everywhere.
So, yes it work like that, but it's not optimal. Real AMD module (non-shimmed) won't work this way as they need to be passed in the define functions arguments, and you won't be able to pull only one module to test it in a separate environment, etc. This way, you cannot load different versions of a scripts to work with different module/app section/page.
The goal of AMD is to bring modularity to your code so every module declare it's own dependencies and will work out of the box it without relying on the global scope (which is a good thing to prevent name collision and conflict with third party/other dev working on the same project).
If you find it's redundant to redeclare everytime your base dependencie, create a boilerplate file that you just copy/paste when creating another module (it's better than nothing). And, maybe some command line tools can build AMD module wrapper for you.
Soooo, yes it works, but it won't scale if your project ever get bigger or need to be updated pieces by pieces.
Hope this help !
good news for the above answer: underscore 1.6.0 now is wrapped as a amd module :)
see "lib.chartjs" for exporting globals in not amd wrapped "shimmed" javascript libraries
requirejs.config({
paths: {
"moment": "PATH_TO/js/moment/2.5.0/moment.min",
"underscore": "PATH_TO/js/underscore/1.6.0/underscore",
"jquery": "PATH_TO/js/jquery/1.10.2/jquery.min",
"lib.jssignals": "PATH_TO/js/jssignals/1.0.0-268/signals.min",
// WORKAROUND : jQuery plugins + shims
"lib.jquery.address": "PATH_TO/js/jqueryaddress/1.6/jquery-address"
"lib.jquery.bootstrap":"PATH_TO/js/bootstrap/3.0.3/bootstrap",
"lib.chartjs": "PATH_TO/js/chartjs/0.2/Chart.min",
},
shim: {
"lib.jquery.address": {deps: ["jquery"]},
"lib.jquery.bootstrap": {deps: ["jquery"]},
"lib.chartjs": {deps: ["jquery"], exports: "Chart"},
}
});

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

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(){});

Resources