Module naming in RequireJS - javascript

We can use AMD compatible versions of BackboneJS and UnderscoreJS
I had a look in the AMD compatible library for both (https://github.com/amdjs/) and below is the relevant code to make them AMD compatible.
BackboneJS (AMD);
else if (typeof define === 'function' && define.amd) {
// AMD
define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
// Export global even in AMD case in case this script is loaded with
// others that may still expect a global Backbone.
root.Backbone = factory(root, exports, _, $);
});
UnderscoreJS (AMD);
// AMD define happens at the end for compatibility with AMD loaders
// that don't enforce next-turn semantics on modules.
if (typeof define === 'function' && define.amd) {
define('underscore', function() {
return _;
});
}
Now to use these AMD compatible libraries in our code, we say;
requirejs.config({
enforceDefine: true,
paths: {
"jquery": "libs/jquery-1.8.3",
"underscore": "libs/underscore-amd",
"backbone": "libs/backbone-amd"
}
});
Now I read that the name for the backbone module can be anything, but the name for underscore must be “underscore” and for underscore, the capitalization is important.
Why is the difference based on how the library is defined?

The define function can be called with or without a name for the module being defined. This call does not have the module name. It starts with an array of dependencies:
define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
RequireJS will assign a module name on the basis of the base name of the file in which the define appears or on the basis of the name you give in the paths configuration. You could put paths: { platypus: '... path to file' } and your module would be named platypus.
This call has a module name:
define('underscore', function() {
It names the module as underscore. (The first argument is not an array, so RequireJS interprets it as a module name.) And when the name is set with define, it does not change, ever. So when you put it as a dependency it has to be called underscore. (You could use map in your RequireJS config to remap the name but ultimately the module name is fixed to underscore.) If you tried the platypus example above with this module, RequireJS would generate an error because it would find a module named underscore but none named platypus.
Specifying module names in define calls without an explicit and substantial reason to do so is bad practice. The documentation for RequireJS recommends not doing it:
These [i.e. module names] are normally generated by the optimization tool. You can explicitly name modules yourself, but it makes the modules less portable -- if you move the file to another directory you will need to change the name. It is normally best to avoid coding in a name for the module and just let the optimization tool burn in the module names. The optimization tool needs to add the names so that more than one module can be bundled in a file, to allow for faster loading in the browser.

Related

Are RequireJS "shim" needed for Backbone.js?

It seems that recent versions of Backbone.js and Underscore.js support AMD.
So am I correct in assuming that it is no longer needed to "shim" these libraries in the require.js configuration?
Yes, you are correct, no shim needed. And it's easy to test, here's the simplest setup:
requirejs.config({
/**
* Paths to lib dependencies.
*
* Use non-minified files where possible as they will be minified (and
* optimized via uglify) on release build (r.js)
*/
paths: {
"jquery": "libs/jquery/dist/jquery",
"underscore": "libs/underscore/underscore",
"backbone": "libs/backbone/backbone",
},
deps: ["app"] // starts the app
});
And to make sure it works and it's not the global Underscore that's used:
// I'm using Underscore as to avoid conflicting with the global _
// but you could use _ as the name for the local variable as well.
define(['backbone', 'underscore'], function(Backbone, Underscore) {
console.log("Backbone:", Backbone.VERSION)
console.log("Local Underscore:", Underscore.VERSION);
console.log("Global Underscore:", _.VERSION, _ === Underscore);
});
For Backbone, it's clear in the source that it supports AMD by default:
// Set up Backbone appropriately for the environment. Start with AMD.
if (typeof define === 'function' && define.amd) {
define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
// Export global even in AMD case in case this script is loaded with
// others that may still expect a global Backbone.
root.Backbone = factory(root, exports, _, $);
});
As for Underscore, it is registering itself at the end:
// AMD registration happens at the end for compatibility with AMD loaders
// that may not enforce next-turn semantics on modules. Even though general
// practice for AMD registration is to be anonymous, underscore registers
// as a named module because, like jQuery, it is a base library that is
// popular enough to be bundled in a third party lib, but not be part of
// an AMD load request. Those cases could generate an error when an
// anonymous define() is called outside of a loader request.
if (typeof define === 'function' && define.amd) {
define('underscore', [], function() {
return _;
});
}
Same thing with jQuery:
// 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.
// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
} );
}
As #ggozad mentioned:
Well, if underscore is already loaded and available, you do not need
the shim at all. Backbone will happily load. If not, it's probably
because underscore is not actually loaded.
It sounds however wrong to be only partially using require.js, you
might as well AMD-load them all.
I guess that explain why you don't need to load it using require.js

RequireJS not loading module properly [duplicate]

I am attempting to get started with RequireJS, and am running into an annoying issue. . .
require.config({
baseUrl: 'app_content/scripts',
paths: {
// the left side is the module ID,
// the right side is the path to
// the jQuery file, relative to baseUrl.
// Also, the path should NOT include
// the '.js' file extension. This example
// is using jQuery 1.9.0 located at
// js/lib/jquery-1.9.0.js, relative to
// the HTML page.
'jQuery': 'lib/jQuery/jQuery-2.0.3'
}
});
This, using uppercase Q, does not work, But if I change it to jquery, it does. Also, this is true in my required areas...
<script type="text/javascript">
require(["jQuery"], function ($) {
console.log($);
});
</script>
This returns undefined, but if I change everything to straight up jquery, it works.
Is this expected behavior, and is there anything I can do about it?
Yes, jQuery defines itself as 'jquery', all lowercase. That's normal.
If you open the source to jQuery you'll find:
// 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; } );
}
So you have to refer to it as "jquery" everywhere in RequireJS calls. The issue here is that the define that jQuery uses is a "named define" which is something we normally do not use when creating modules. The RequireJS optimizer adds these names for us when we run it.
At any rate, when a "named define" is used the module name is set to the name given to define rather than by file names (as is otherwise the case when we don't use a named define).
It is possible to rename "jquery" to "jQuery", like this:
require.config({
baseUrl: "./js",
paths: {
"jquery": "jquery-1.10.2"
}
});
define("jQuery", ["jquery"], function ($) {
return $;
});
require(["jQuery"], function ($) {
console.log($);
console.log($("body")[0]);
});
I'm making use of the version of define that takes a name as the first parameter. Full example here.

How to use require.js with complicated source tree, or import something else from CommonJS'es main.js?

My JS code is Backbone.js based, so I think it is a good idea to separate "classes" with this logic as shown on picture (though I'm not sure where to place templates - in this packages or in global templates folder, and do not mind main.js - it is not related to CommonJS packages) :
Now since there is fairly lot of them - I've decided to use require.js to deal with this bunch of <script src=... tags but got stuck with app.js config file (which is the only one that I include like this -
<script data-main="/static/js/app.js" src="/static/js/libmin/require.js"></script>
What do I mean with stuck - of course I can iterate all this js files in require statement using names like PlayerApp/PlayerAppController.js, or using paths directive (not sure if it will make the code look not that ugly), but it would be cool if I can use something like python's from package import *, and of course there is no such thing in require.js.
The most similar thing is packages directive, but seems like it allows you to import only main.js from each package, so then the question is - what is the most correct way to load other files of concrete package from CommonJS's main.js? I have even found a way to determine current .js file's name and path - like this, and given that I can make up other files names in current package(if I will keep naming them with the same pattern), but still do not know how to import them from main.js
Edit:
There might be an opinion that it is not very clear what exactly am I asking, so let me get this straight: how on Earth do I import a huge amount of javascript files with that project structure in the most nice way?
You are mis-understanding the purpose of a module loader. require.js is not there to make it easy for you to import all of your packages into the current namespace (i. e. the browser). It is there to make it easy to import everything you need to run app.js (based on your data-main attribute). Don't try to import * - instead, just import thingYouNeed.
Configuration
What you will want to do is set up your require.config() call with all the necessary paths for libraries like Backbone that don't support AMD and then update your code to explicitly declare its dependencies:
require.config({
// Not *needed* - will be derived from data-main otherwise
baseUrl: '/static/js/app',
paths: {
// A map of module names to paths (without the .js)
backbone: '../libmin/backbone',
underscore: '../libmin/underscore',
jquery: '../libmin/jquery.min',
jqueryui.core: '../libmin/jquery.ui.core'
// etc.
}
shim: {
// A map of module names to configs
backbone: {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
},
underscore: {
exports: '_'
},
jquery: {
exports: 'jQuery'
},
// Since jQuery UI does not export
// its own name we can just provide
// a deps array without the object
'jqueryui.core': ['jquery']
}
});
Dependencies
You will want to update your code to actually use modules and declare your dependencies:
// PlayerAppModel.js
define(['backbone'], function(Backbone) {
return Backbone.Model.extend({modelStuff: 'here'});
});
// PlayerAppView.js
define(['backbone'], function(Backbone) {
return Backbone.View.extend({viewStuff: 'here'});
});
// PlayerAppController.js
define(['./PlayerAppModel', './PlayerAppView'],
function(Model, View) {
// Do things with model and view here
// return a Controller function of some kind
return function Controller() {
// Handle some route or other
};
});
Now, when you require(['PlayerApp/PlayerAppController'], function(Controller) {}) requirejs will automatically load jQuery, underscore, and Backbone for you. If you never actually use mustache.js then it will never be loaded (and when you optimize your code using the r.js compiler, the extra code will be ignored there as well).

Explicit vs. implicit dependency handling in require.js

I'll use what I'm actually doing as an example. I have a knockout custom binding that depends on a jquery plugin that itself depends on jQuery UI that of course depends on jQuery. There is another file that depends on another plugin, and another file that depends on jQuery UI, etc. In require.config.js I have:
shim: {
"jquery-ui": {exports: "$", deps: ["jquery"]},
"jquery-plugin1": {exports: "$", deps: ["jquery-ui"]},
"jquery-plugin2": {exports: "$", deps: ["jquery-ui"]}
}
This works, and then in corresponding files I may do:
define(["jquery-plugin1"], function ($) {
However, I could also do:
define(["jquery", "jquery-ui", "jquery-plugin1"], function ($) {
There is also the case where a file may depend on both plugins:
// which one?
define(["jquery-plugin1", "jquery-plugin2"], function ($) {
define(["jquery", "jquery-ui", "jquery-plugin1", "jquery-plugin2"], function ($){
There may also be other dependencies such as knockout custom bindings (which don't need to export anything) so I may end up with:
define(["jquery-plugin1", "model1", "model2",
"ko-custom1", "ko-custom2", "ko-custom3",
"jquery-plugin2"],
function ($, m1, m2) {
This file may also depend on jQuery UI (which depends on jQuery), but those are both loaded implicitly via the plugins.
My question is is it better to be explicit about all requirements (i.e. include jQuery and jQuery-UI in define) and possibly leave off the exports, or is the less-verbose nested dependency handling preferred?
This is a great question and becomes very relevant when using something like AngularJS dependency injection as those dependencies need to exist before the module is registered. So this won't work:
define(['angular'],function (angular) {
return angular.module('myModule', ['mySubmodule']);
});
// Error: [$injector:nomod] Module 'mySubmodule' is not available!
You need to define the AMD dependency as well:
define(['angular','./mySubmodule'],function (angular) {
return angular.module('myModule', ['mySubmodule']);
});
It might be subjective but I find it easier to reason about it by having each module define it's own dependencies explicitly and letting requireJS resolve them instead of leaving it up to faith that an out-of-scope module has already defined them which breaks modularity.
By doing this you also know that your AMD modules can be tested independently without rewiring the missing dependency.

best practices for cross commonjs/browser development

Currently, I use a few defines via the Google Closure Compiler along the lines of IS_CJS and IS_BROWSER, and just have different files that get built (browser.myproject.js, cjs.myproject.js, etc).
Is this the standard way of doing things? If not, what is it and what are the advantages?
I've been using the following preamble in all my projects, for libraries that are loaded by both browser and server code:
if (define === undefined) {
var define = function(f) {
require.paths.unshift('.');
f(require, exports, module);
};
}
define(function(require, exports, module) {
...
// main library here
...
// use require to import dependencies
var v = require(something);
...
// use exports to return library functions
exports.<stuff> = { some stuff };
...
});
This works to load the library with a require(<library>) call running on my node server, as well as with a require(<library>) call with RequireJS. On the browser, nested require calls are pre-fetched by RequireJS prior to library execution, on Node these dependencies are loaded synchronously. Since I'm not using my libraries as stand-alone scripts (via a script tag in the html), and only as dependencies for scripts loaded via the script tag, this works well for me.
However, looking at stand-alone libraries, it looks like the following preamble seems to be the most flexible. (cut and paste from the Q promise library
(function (definition, undefined) {
// This file will function properly as a <script> tag, or a module
// using CommonJS and NodeJS or RequireJS module formats. In
// Common/Node/RequireJS, the module exports the Q API and when
// executed as a simple <script>, it creates a Q global instead.
// The use of "undefined" in the arguments is a
// micro-optmization for compression systems, permitting
// every occurrence of the "undefined" variable to be
// replaced with a single-character.
// RequireJS
if (typeof define === "function") {
define(function (require, exports, module) {
definition(require, exports, module);
});
// CommonJS
} else if (typeof exports === "object") {
definition(require, exports, module);
// <script>
} else {
Q = definition(undefined, {}, {});
}
})(function (serverSideRequire, exports, module, undefined) {
...
main library here
...
/*
* In module systems that support ``module.exports`` assignment or exports
* return, allow the ``ref`` function to be used as the ``Q`` constructor
* exported by the "q" module.
*/
for (var name in exports)
ref[name] = exports[name];
module.exports = ref;
return ref;
});
While wordy, it's impressively flexible, and simply works, no matter what your execution environment is.
You can use uRequire that converts modules written in either AMD or CommonJS to either AMD, CommonJS or UMD through a template system.
Optionally uRequire builds your whole bundle as a combinedFile.js that runs in ALL environments (nodejs, AMD or module-less browser < script/>) thats using rjs optimizer and almond under the hood.
uRequire saves you from having to maintain any boilerplate in each module - just write plain AMD or CommonJS modules (as .js, .coffee, .coco, .ls etc) without gimmicks.
Plus you can declaratively add standard functionality such as exporting a module to global such as window.myModule along with a noConflict() method, or have runtimeInfo (eg __isNode, __isAMD) selectively or replace/remove/inject a dependency while building, automatically minify, manipulate module code and much more.
All of these configuration options can be turned on and off per bundle OR per module, and you can have different build profiles (development, test, production etc) that derive(inherit) from each other.
It works great with grunt through grunt-urequire or standalone and it has a great watch option that rebuilds ONLY changed files.
Have you tried this: https://github.com/medikoo/modules-webmake#modules-webmake ?
It's the approach I'm taking, and it works really well. No boilerplate in a code and you can run same modules on both server and client side

Categories

Resources