AMD: what is the purpose in javascript context? - javascript

Regarding AMD (Asynchronous Module Definition ) I read the phase like this:
The AMD format comes from wanting a module format that was better than
today's "write a bunch of script tags with implicit dependencies that
you have to manually order" and something that was easy to use
directly in the browser.
What is the the purpose in javascript context? Can you make some example? pro et contro of using AMD?

Long before JavaScript gained a native module system, the only way to put scripts onto a page were <script> elements. These executed in sequence, in the order they appear on the HTML. This means that if your script relied on jQuery, then jQuery's <script> has to come before your script's <script>. Otherwise, it blows up.
It's not uncommon to logically split an app into multiple files, especially as the app grows. But using this system of manually ordering scripts becomes a nightmare quickly. Your scripts have implicit dependencies whose management is defined elsewhere. This is where AMD comes in.
AMD is a module specification and RequireJS is an implementation of such system. Simply put, it's a wrapper around your code that 1) keeps your script inert until invoked, 2) allows your script to explicitly define its dependencies and, 3) allows the module system to work out which dependencies execute in what order.
Here's a rough example:
// your-app.js
define(['jquery', 'underscore'], function($, _){
// Your script sits in this "wrapper" function.
// RequireJS now knows app.js needs jquery and underscore.
// It loads and executes them first before your script.
})
// jquery.js
define('jquery', [], function(){
// jQuery stuff
return jQuery
})
// underscore.js
define('underscore', [], function(){
// underscore stuff
return underscore
})
// Then on your HTML, load up your app.
<script data-main="path/to/app.js" src="path/to/require.js"></script>

It's common for Javascript libraries that depend on each other to require that they are loaded in a specific order. For example, the script tag that includes the jQuery library has to come before the script tag that includes the jQuery UI library.
If the libraries were using AMD, they could be included in any order. The AMD library would take care of initialising the libraries in the correct order, because you specify which library depenends on which.
(Somewhat ironically, the script tag that includes the AMD library of course has to come before the code that include any libraries using AMD...)

Related

What is the "order!" directive for in this requirejs/amd module?

I'm looking into what appears to be a case of javascript loading out of order in a legacy application. The application uses Require.js to load several modules, and one of our company's modules is executing prior to its dependencies being loaded.
My experience with Require.js and AMDs is very limited, and in researching I noted that in some areas dependencies are prefixed with an order! string, such as:
define(['order!jquery', ...
Whereas in other areas the prefix isn't used:
define(['jquery', ...
So far I can't find documentation of this directive. What's its effect?
Full information copied from here
Normally RequireJS loads and evaluates scripts in an undetermined
order. However, there are some traditional scripts that depend on
being loaded in a specific order. For those cases you can use the
order plugin. Download the plugin and put it in the same directory as
your app's main JS file. Example usage:
require(["order!one.js", "order!two.js", "order!three.js"], function () {
//This callback is called after the three scripts finish loading.
});
Scripts loaded by the order plugin will be fetched asynchronously, but
evaluated in the order they are passed to require, so it should still
perform better than using script tags in the head of an HTML document.
The order plugin is best used with traditional scripts. It is not
needed for scripts that use define() to define modules. It is possible
to mix and match "order!" dependencies with regular dependencies, but
only the "order!" ones will be evaluated in relative order to each
other.
Notes:
The order! plugin only works with JavaScript files that are cacheable by the browser. If the JS file has headers that do not
allow the browser to cache the file, then the order of scripts will
not be maintained.
Do not use the order! plugin to load other plugin-loaded resources. For instance. 'order!cs!my/coffescript/module' is not recommended.
You will get errors in some versions of IE and WebKit. This is due
to the workarounds the order plugin needs to do for those browsers
to ensureordered execution.

Avoid loading DOM relient modules while testing

I'm using the intern for testing javascript in a project. The javascript we are trying to test does not require the DOM, and should be able to be run within a node process without trouble. However, the modules that I'm loading for the test also load jquery (as an example), which hits the dom on load.
//file.js
require([..., 'jquery'], function(..., $) {
// non-jquery code to test
})
//intern test
require(['intern!object', 'file'], function(registerSuite, file) {
registerSuite({
...
Loading jquery in the module causes intern to break immediately when run in a node process, even though I want to test something completely different. Is there a correct way to get around this? I tried just pointing the jquery module to an empty file, but this doesn't work for all cases.
Thank you.
If any code has a hard dependency on the complete, pre-built copy of jQuery, then it must run in a DOM environment, as jQuery is a DOM library. If the code itself doesn’t require a DOM, then it shouldn’t have jQuery as a dependency, at which point it will load fine in Node.js.
If you need a non-DOM utility library, try Dojo or Lo-Dash or something else that isn’t a DOM library like jQuery.
If you have a module that may use the DOM, Dojo comes with the dojo/has module that can be used as an AMD loader plugin to conditionally load DOM dependencies only when the module is loaded in a browser.
Finally, note that any AMD module (like file.js in your example) should contain a define call, not a require call.

Understanding dojo's require in combination with diji/layout

I'm trying to understand dojo in combination with dijit layouts. More specifically: do I need to require the layout widgets in JS or is using html data attributes enough?
I've read the Layout documentation and it seems like you need 3 things:
JavaScript: require the layout widgets you want to use
HTML markup
CSS
But it's not clear to me why I would need to require the layout widgets in JavaScript with:
require(["dojo/parser", "dijit/layout/BorderContainer", "dijit/layout/ContentPane"]);
Which is stated in this example.
I've created a demo without requiring "dijit/layout/BorderContainer" and "dijit/layout/ContentPane" and that's working fine.
Is it safe to leave these out of the require statement?
You should require your modules rather than letting the parser load them because ideally you want all of your modules loaded before the parser runs so that you can bundle all of your dependant modules into a layer file.
This means that you can create a layer with all of your common modules so that you don't need to have 100s of tiny .js requests hit your server, and instead you can load a bulkier one.
Also, if you have custom modules you should load all of the dependant widgets inside of the custom module instead of letting the parser detect.
dojo/parser loads all dependencies for you, so you don't need to require them programmatically in JavaScript, but you need them there once you decide to build your code, i.e. put all the dependencies into a single file, which is the reason, why parser warns you, when it loads dependencies for you:
This auto-requiring is also the reason, why parser.parse() returns a promise, it's because it might be asynchronously loading dependencies:
parser.parse().then(function(/* Array */ widgetInstances) {
});

Using requirejs for a modular game engine

I'm an experienced javascript programmer, and I'm trying to write my own modular game engine from scratch. I haven't used requirejs before, but after reading a bit about it, it sounds like it's probably the best way to manage all the components of the engine and load them into one coherent structure.
My main problem is that I'm not really sure how to really use requirejs. I've been looking over their API documentation, but I'm not sure how to integrate it with the way I've laid out my project.
Currently, my project uses the following structure:
src
engine.js //This contains the common engine stuff, most notably the engine namespace
resource
resource-module.js //This is the module constructor, which handles all the common stuff between the different
substructures
sprites.js //This is a substructure that contains sprite loading code
render
etc...
third-party
jquery
requirejs
I want to be able to load the modules independently of each other. It should be possible for instance to remove the audio module from the engine, and it still work. It should also be easy to substitute modules, or add new modules.
Also, I'm using jQuery for event handling, so it needs to be loaded before the engine is initiated.
You can find my current source here: https://github.com/superlinkx/lithium-engine
I know the current code is messy, and there isn't a whole lot built yet, but I'm mostly still figuring out how to best structure it. Any help/advice would be appreciated, but my main concern is how to structure it with requirejs so that it will be easier to compile into a single file for production use.
Require.js does not enforce any specific structure of your files. You can either specify the full paths in the require configuration, or just use the full path in the require() or define() calls. Both will work, however the latter will save you some typing and makes it easier to move stuff around when you include something from a lot of different places:
var $ = require("third-party/jquery");
require.config({
paths: {
"jquery": "third-party/jquery"
}
});
var $ = require("jquery");
I want to be able to load the modules independently of each other. It should be possible for instance to remove the audio module from the engine, and it still work. It should also be easy to substitute modules, or add new modules.
This is not something require.js does four you. You can decide when and when not to load it, but you would have to make sure that it won't break the rest of your code.
Also, I'm using jQuery for event handling, so it needs to be loaded before the engine is initiated.
You can do this in several different ways.
require() it in your main.js so that it is always loaded (you can also use the require-jquery.js, which has jQuery included).
Specify jQuery as a dependency of your engine
require.config({
paths: {
"jquery": "path.to.jquery",
"engine": "path.to.engine"
},
shim: {
"engine": {
"deps": ["jquery"]
}
}
});
Pass jQuery to the define() call in your module (probably the best choice)
define(["jquery"], function ($) {
// your engine code
}

Using RequireJS with legacy code

I'm working with a very large project that uses:
Legacy JSP pages that includes javascript files with script tags
Backbone models and views that uses other javascript modules without RequireJS
We now want to start using RequireJS with jQuery, BackboneJS and UnderscoreJS for everything we develop from now on, but we don't have the resources to rewrite all the legacy JSP pages. We may have time to rewrite the Backbone models and views we have already developed.
The problem is that for our legacy code (both 1 and 2 above) we include all our javascript files in a huge file and ship to the browsers. This huge file must be able to co-exist with our new RequireJS templates, but how can I e.g. separate certain parts of the huge file, so I can use them with the templates using RequireJS? Without having to rewrite all pages that uses this part of the file, or having duplicate code.
Thanks!
I don't know if I fully grasp the problem at hand, but I think a the shim or map functions of RequireJS will help you out.
Extract the parts you want in a new module from your huge javascript file. Then tell RequireJS that your huge javascript file is a dependecy for this new module using shim. Something like:
requirejs.config({
shim: {
'new-module': {
deps: ['huge-javascript-file'],
exports: 'NewModule'
}
});
Shim documentation: http://requirejs.org/docs/api.html#config-shim
The map function might be useful when only portions of your new code have to use your old huge file. Check out this documentation: http://requirejs.org/docs/api.html#config-map
I don't think there is One True Way to achieve this, but I've approached a similar problem by defining module "facades" around the globally scoped code. Let's say your legacy scripts define a global variable called foo. You can define a AMD module and export that variable from it:
//foo.js
define(function() {
return window.foo;
});
//bar.js
define(['foo'], function(foo) {
//do something with foo
});
This way you only need to write a single-line facade every time you need to use a new piece of the existing, globally defined code, without breaking existing code which expects the same code to be globally defined. Over time you can move and refactor the actual implementation into the module without breaking consumer code.

Categories