AMD: what does 'dependencies' mean when its an object, not an array? - javascript

I have inherited some code with an AMD module looks like:
define('shared/modulename', {
load: function(name, parentRequire, callback, config) {...}
})
This doesn't resemble the normal AMD syntax of an array of dependencies as documented here. The code isn't commented, and there is no explanation of why the change in syntax is needed for this module.
What does this invocation of define() actually do?
Looking at the arguments given to the load() function, they seem to be AMD internals.

This is one of the simple forms of defining AMD modules. http://requirejs.org/docs/api.html#define
In RequireJS you can define name-value pairs in this simple format:
define({foo: 'yay'})
And you can specify the module name in define too, which you are required to when you combine your modules. So that makes our example to:
define('aloha', {foo: 'yay'})
Now back to your code. The meaning is shallow. It defines a module called shared/modulename.
The exports of that module is an Object, which contains a method called load.
You can use this module like this:
require('shared/modulename').load(name, parentRequire, callback, config)

Related

RequireJs - why is Jquery injected and JSZip is not?

I'm trying to understand how requireJs works, could somebody please explain to me, why in the following example:
http://plnkr.co/edit/HEDc8F19wICMy0zeGWpH?p=preview
More specifically here:
require(['ble'], function () {
$('#someDiv').html(Ble.A());//This works fine
var zip = new JSZip();//This fails with JSZip is not defined
console.log(zip);
});
Jquery is defined, but JSZip is not? I also tried other combinations, but only one that seems to work is when I manually specify jszip in require array like this:
require(['jszip','ble'], function (JSZip) {
$('#someDiv').html(Ble.A());
var zip = new JSZip();
console.log(zip);
});
I know that documentation states:
The shim config only sets up code relationships. To load modules that
are part of or use shim config, a normal require/define call is
needed. Setting shim by itself does not trigger code to load.
But then - is jquery some kind of "special case" and I should normally, inject my dependencies manually even if they are specified in shim config section?
ASWER:
So it turns out jQuery is indeed a special case, and normally a manual injection of dependencies is required...
If you look in the source code of jQuery you will find the following:
// 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;
});
}
This means that jQuery will - when required - define itself as jquery.
require(['jszip','ble'], function (JSZip) {
In this above statement, it imports the jszip and returns a object as JSZip.
var zip = new JSZip();
Here that object is used. So with this code you did not get error.
Thus, For jszip, just require is not enough.

How to declare parameter types when type is declared as ambient external module definition

Say you've got a ViewModel (or other RequireJS module) that looks like this:
define(['plugins/dialog'], function (dialog: /* what type should go here? */) {
/* rest of module */
}
For reference, the type we are interested is the Dialog interface, which is defined like this in durandal.d.ts:
declare module 'plugins/dialog' {
interface Dialog {
owner: any;
context: DialogContext;
activator: DurandalActivator<any>;
close(): JQueryPromise<any>;
settings: composition.CompositionContext;
}
}
This type of module definition is referred to as an "ambient external module declaration." As #basarat noted here, you need to use import in order to gain access to these modules. Here's how your ViewModel needs to be updated:
import dialogModule = require('plugins/dialog');
define(['plugins/dialog'], function (dialog: dialogModule.Dialog) {
/* rest of module */
}
This works at compile time, but the generated JavaScript now looks like this:
define(["require", "exports"], function(require, exports) {
define([
/* rest of module */
});
});
You can see that the module was wrapped in an extra "define()" call. This results in a mismatched anonymous define error when you try to show the dialog (i.e., when Durandal tries to retrieve this module).
So, is it possible to "import" and make use of types inside ambient external module declarations, without it wrapping your file in an extra define()?
Ideally, the Durandal .d.ts would be written differently (such that you could access the interface without importing the module).
As a practical solution, you could compile your file with --module commonjs instead of --module amd. The require call will be optimized away and you'll still get type information.
You could also compile with --module amd and rewrite your code to not explicitly call define (just let the compiler generate that, like it's trying to), though I'm assuming you've avoided doing that for intentional reasons.

How to include anonymous functions into RequireJS dependencies?

I am starting to use RequireJS now and I was already able to add my project dependencies but I still cannot add a jQuery anonymous function yet.
For example, with my normal_file.js I do something like:
normal_file.js:
define(['dependency1'], function(Dependency) {
var Test1 = ...;
return Test1;
});
Bu from a file that has no module, like the example below, I don't know how to encapsulate it:
lib_file.js:
(function ($) {
// Do stuff...
})(window.jQuery);
the lib_file was not made by me and I'm not sure on how it really works, but I would gess it is an anonymous auto-executed function, is that so?.
Anyway, my goal is to use both files in my main code, like below:
main.js:
requirejs.config({
baseUrl:'/static/editorial/js/',
paths: {
jquery: 'third_party/jquery-1.10.2',
react: 'third_party/react-with-addons'
}
});
var dependencies = [
'third_party/react-with-addons',
'third_party/jquery-1.10.2',
'build/utils/normal_file,
'third_party/lib_file
];
require(dependencies, function(React, $, Test1, ??) {
// do my stuff
});
How should I encapsulate that anonymous function in order to add it as a dependency to my main file?
From the RequireJS docs:
Ideally the scripts you load will be modules that are defined by
calling define(). However, you may need to use some traditional/legacy
"browser globals" scripts that do not express their dependencies via
define(). For those, you can use the shim config. To properly express
their dependencies.
Read this: http://requirejs.org/docs/api.html#config-shim
It has a really good explanation of what you have to do, and gives a nice example.
Basically, you just need to set up a shim config for lib_file.js so Require knows to load the right dependencies before giving you access to that script.

requirejs: can I require a global runtime var?

I'm using requirejs in a somewhat special JS environment where an application provides a global singleton (I cannot change this fact, this isn't running in a typical browser environment). I am writing a sort of JS SDK for this application and want to provide various modules that use this global.
Can I wrap that global in a module somehow in order to require it from my modules? Something like
define([the_global_application], function(app)
Thanks for your thoughts on this.
Yes, you just have to define it.
// mysingletonapp.js
// define the module for our global var
define(['list', 'any', 'dependency', 'here'], function (l, a, d, h) {
return yourGlobalVariable;
});
(I don't think you'll have dependencies in there, since you're just wrapping a global var)
The you can use that module as usual:
require(['mysingletonapp'], function (app) {
// do something cool
});
If you want to skip all this, you can use the shim property of RequireJS. You would just need to add this to your options file:
...
shim: {
'globalApplication': {
deps: ['underscore', 'jquery'], // again, you should not need them
exports: 'yourGlobalVar'
}
}
...
shims wrap libraries that don't support AMD, so to have this setting work, you would need a js for globalApplication. This isn't your case.

require.js: how can I load a module that defines a name under a different name?

I'm trying to load underscore.js with require.js like this:
require(["libs/underscore-1.2.3.js"], function(_) {
...
});
But this doesn't work because underscore.js exports a module name: define('underscore', function() { ... }).
Without renaming lib/underscore-1.2.3.js, how can I load it with require.js?
Alright, after some more googling, I've found: https://github.com/documentcloud/underscore/pull/338#issuecomment-3245213
Where
#dvdotsenko all AMD loaders allow mapping a module ID to a partial path, usually the configuration is called 'paths', so to do what you want:
requirejs.config({
paths:
underscore: 'js/libs/underscore-1.2.3.min'
}
});
require(['underscore'], function () {});
Since underscore is used by other higher-level modules, like backbone, a common dependency name needs to be used to communicate a common dependency on underscore, and it makes sense to call that dependency 'underscore'. The paths config gives a way to do the mapping to a specific URL you want to use for that dependency.
This doesn't answer my question (ie, I still don't know how I'd go about loading underscore if all I had was a URL), but at least it's a functional workaround.
While this doesn't strike me as the most ideal solution, you can require your external files, and then require their registered module names in the inner block.
JSFiddle Example
require(
['require','http://documentcloud.github.com/underscore/underscore-min.js'],
function(require){
require(['underscore'],function(_){
var a = _.intersection([1,2,3],[2,3,4]);
document.write("Underscore is available in the closure : " + a);
})
}
)
It might not look pretty, but that might be a recommended pattern for loading up initial assets so that they can be required intuitively in dependent modules.

Categories