We love RequireJS and AMD during development, where we can edit a module, hit reload in our browser, and immediately see the result. But when it comes time to concatenate our modules into a single file for production deployment, there apparently has to be an AMD loader still present, whether that loader is RequireJS itself or its smaller partner “almond” as explained here:
http://requirejs.org/docs/faq-optimization.html#wrap
My confusion is: why is a loader necessary at all? Unless you have very unusual circumstances that make it necessary for you to make require() calls inside of your modules, it would appear that a series of AMD modules could be concatenated without a loader present at all. The simplest possible example would be a pair of modules like the following.
ModA.js:
define([], function() {
return {a: 1};
});
ModB.js:
define(['ModA'], function(A) {
return {b : 2};
});
Given these two modules, it seems that a concatenator could simply produce the following text, and not burden the production server or browser with the extra bandwidth or computation required by either RequireJS or Almond.
I imagine a concatenator that produces (and I am using chevron-quotes «,» to show where the snippets from the two modules above have been inserted):
(function() {
var ModA = «function() {
return {a: 1};
}»();
var ModB = «function(A) {
return {b : 2};
}»(ModA);
return ModB;
})();
This, so far as I can see, would correctly reproduce the semantics of AMD, with a minimum of extraneous glue JavaScript. Is there such a concatenator available? If not, would I be a fool for thinking that I should write one — are there really very few code bases that consist of simple and clean modules written with define() and that never need further require() calls inside that kick off later asynchronous fetches of code?
An AMD optimiser has the scope to optimise more than the number of files to be downloaded, it can also optimise the number of modules loaded in memory.
For example, if you have 10 modules and can optimise them to 1 file, then you have saved yourself 9 downloads.
If Page1 uses all 10 modules then that's great. But what if Page2 only uses 1? An AMD loader can delay the execution of the 'factory function' until a module is require'd. Therefore, Page2 only triggers a single 'factory function' to execute.
If each module consumes 100kb of memory upon being require'd, then an AMD framework that has runtime optimisation will also save us 900kb of memory on Page2.
An example of this could be an 'About Box' style dialog. Where the very execution of it is delayed until the very last second as it won't be accessed in 99% of cases. E.g. (in loose jQuery syntax):
aboutBoxBtn.click(function () {
require(['aboutBox'], function (aboutBox) {
aboutBox.show();
}
});
You save the expense of creating the JS objects and DOM associated with the 'About Box' until you are sure it's necessary.
For more info, see Delay executing defines until first require for requirejs's take on this.
The only real benefit is if you use modules across sections so there's a benefit to caching modules independently.
I had the same need, so I created a simple AMD "compiler" for that purpose that does just that. You can get it at https://github.com/amitayh/amd-compiler
Please note that it has many features missing, but it does the job (at least for me). Feel free to contribute to the codebase.
In case you compile you code with require.js into a single large file for production, you can use almond.js to completely replace require.
Almond only handles the module references management not the loading itself which is no longer needed.
Be careful of the restrictions almond imposes in order to work
There is no reason why there couldn't be a build tool such as the one you propose.
The last time* I looked at the optimizer's output, it converted the modules to explicitly named modules, and then concatenated those together. It relied on require itself to make sure that the factory functions were called in the right order, and that the proper module objects were passed around. To build a tool like you want, you would have to explicitly linearize the modules -- not impossible, but a lot more work. That's probably why it hasn't been done.
I believe** that the optimizer has a feature to automatically include require itself (or almond) into the built file, so that you only have to have one download. That would be larger than the output of the build tool you want, but otherwise the same.
If there was a build tool that produced the kind of output you're asking for, It would have to be more careful, in case of the synchronous require, the use of exports instead of return, and any other CommonJS compatibility features.
*That was a few years ago. 2010, I think.
**But can't seem to find it right now.
Related
I've been reading about es6 module loaders and I just don't quite understand how it works and am hoping someone can enlighten me.
In the practical workflows link above they have an example like this
System.import('app/app').then(function(app) {
// app is now the Module object with exports as getters
});
No problem with that - I get it. But then I see stuff like this
var $ = require('jquery');
and get really confused. What happens if at the time of this call jquery has not yet been transferred to the browser? Does the thread just spin? Does the browser parse your script behind-the-scenes and reform it into a callback like RequireJs does? Is what it does configurable? Are there specific limitations?
Can someone give me a rundown?
The ES6 Module Loader will fetch the source, determine dependencies, and wait until those dependencies have loaded before executing the module. So by the time the require executes, the dependency is already sitting there waiting to be executed.
When loading CommonJS through an ES6 module loader, we rely on statically parsing out the require statements from the source, and only executing the source once those requires have loaded.
In this way we can support CommonJS in the browser loaded dynamically. Circular references are treated identically to the way they are handled in Node.
The regular expressions parsing out the require are actually pretty reliable and quick, while taking into account comments and surrounding tokens. See https://github.com/systemjs/systemjs/blob/master/lib/extension-cjs.js#L10 for the one used by SystemJS.
There is one remaining limitation with this approach and that is dynamic and conditional CommonJS requires like if (condition) require('some' + 'name') aren't detected properly. This is a necessary cost though to make CommonJS behave as a fully asynchronous module format in the browser.
I'm wondering what is the proper approach for using RequireJS in a project with multiple modules, regarding performance of multiple require calls with less dependencies vs a single require with all the dependencies.
Let's take the case where, for an app, I need to load some modules: gmaps, jquery, module1, module2, module3. The use for some of the modules is quite independent. So, the question is which of the following alternatives is recommended (supposedly this code is the main module loaded into the page):
require(['gmaps'], function(gmaps){
gmaps.use();
});
require(['jquery','module1'], function(jquery, module1){
module1.use();
});
require(['jquery','module2'], function(jquery, module2){
module2.use();
});
require(['jquery','module3'], function(jquery, module3){
module3.use();
});
vs
require(['jquery','module1','module1','module1','gmaps'], function(jquery, module1,module2,module3,gmaps){
module1.use();
module2.use();
module3.use();
gmaps.use();
});
In other words, what is the performance penalty of require and which is the best practice.
The answer to the question here is "it depends." I'm speaking as someone who has used RequireJS in a large application but who has not thoroughly read the code of RequireJS. (Just pointing out that people who know the innards of RequireJS inside and out might explain differently than I do.) The cost of require can be broken down into 3 cost scenarios:
If the module has never been loaded, require loads a file from a server, executes the file, executes the factory function for the module and returns a reference to the module. (The cost of loading files from the network usually dwarfs other costs.)
If the module has already been loaded but never required, require executes the factory function for the module and returns a reference to the module. (This will normally happen in an optimized application.)
If the module has already been loaded and required, require returns a reference to the module.
Cost scenario 1 > cost scenario 2 > cost scenario 3.
First, let's consider the case where there is one module per file. The application is not optimized. I have a module named module1 which is required once in a blue moon. It's usage in a main application could be modeled like this:
define(["module1", <bunch of other required modules>],
function (module1, <bunch of other modules variables>) {
[...]
if (rare_condition_happening_once_in_a_blue_moon)
module1.use();
[...]
});
Here I always pay the price of cost scenario number 1 even if I don't use the module. It would be better to do:
define([<bunch of required modules>],
function (<bunch of module variables>) {
[...]
if (rare_condition_happening_once_in_a_blue_moon)
require(["module1"], function (module1) {
module1.use();
});
[...]
});
This way, I'd pay the price of loading the module only once in a blue moon.
Now, what if I need to use module repeatedly? This can be modeled as:
define(["module1", <bunch of other required modules>],
function (module1, <bunch of other modules variables>) {
[...]
for(iterate a gazillion times)
module1.use();
[...]
});
In this case, cost scenario number 1 is paid once, and that's all. If I use require like this:
define([<bunch of required modules>],
function (<bunch of module variables>) {
[...]
for(iterate a gazillion times)
require(["module1"], function (module1) {
module1.use();
});
[...]
});
I'm paying cost scenario number 1 once and a (gazillion times - 1) cost scenario number 3. At the end of the day, whether the module1 should be included among the requirements of the define call or in a separate require call depends on the specifics of your application.
The analysis changes if the application has been optimized by using r.js or a home-made optimization. If the application is optimized so that all modules are in one file, every time you paid cost scenario 1 in the cases above, you'd pay cost scenario 2 instead.
For the sake of completeness, I'll add that in cases where you do not know ahead of time the module you might want to load, using require is necessary.
define([<bunch of other required modules>],
function (<bunch of other modules variables>) {
[...]
require(<requirements unknown ahead of time>, function(m1, m2, ...) {
m1.foo();
m2.foo();
[...]
});
[...]
});
It depends on what loading behavior you want.
When you require a module that has not been required yet, a HTTP request will be made to load the required module. If the required module has been loaded atleast once, it is stored in require's cache, and so when you require the module the second time, it will use the cached value.
So, its a choice between lazy or eager loading.
The problem that require is trying to solve, is that each module can define it's dependencies - so your first approach would probably be "best practice". In the end, you'd want to use r.js to build your application into a single JS file.
Second approach is in my opinion against the main purpose of the require js, which is the separation of different program logic. Why would you use requirejs if you put your code in the one "module" anyway? .In terms of performance it is important to define what is your definition of performance. If it is the speed of your code execution, then there should be no visible difference. The code will execute as soon as all required modules are loaded. If on the other hand, what you mean by performance is: when the code execution starts - then obviously in the second approach you will have additional overhead caused by additional requests for files where your required code is located.
EDIT:
After taking a closer look to the question, the first part of my answer did not fit it well. The code is actually referencing external modules, so the second option is not against the purpose of the requirejs library and is actually the better approach as long as the module which combines its dependencies is not trying to do too much.
I'm currently building an app where the frontend is doing a lot of the heavy lifting.
To keep everything neat and organised I'd like to use requirejs. However, to use require.js to its' full extent all the modules I use should be AMD compliant.
Which means that every time a module that I use is updated I need to either wait for an AMD-compliant version to appear or make one myself ( Which I currently don't know how to ).
This is a real turnoff.
Looking at this https://github.com/jrburke/backbone/blob/optamd/backbone.js it seems to me that making a module like Backbone AMD-compliant isn't as straightforward as wrapping the plugin into a generic function.
Is there a more or less straightforward way of making a module AMD-compliant?
Well his version is pretty bullet-proofed so it'll run under a variety of circumstances. Since you know the environment you are running in and what is available/what isn't then you can make some assumptions that will let you do something that is much more straightforward.
Check out this gist where I make bacbkonejs an AMD module assuming jQuery, underscore and define are in the global scope and I don't need commonjs support:
https://gist.github.com/2762813
I just add
define(function() {
var obj = {};
obj._ = window._;
obj.jQuery = window.jQuery;
to the top and
.call(obj);
return obj.Backbone;
});
to the bottom.
Thanks to #SimonSmith for bringing UseJS to my attention. UseJS is an AMD loader plugin that will allow you to load non-amd formatted modules without modifying them. I haven't used use myself yet but it looks promising: https://github.com/tbranyen/use.js/
UPDATE
RequireJS 2.0 now directly supports the functionality you are looking for via shim configs: https://github.com/jrburke/requirejs/wiki/Upgrading-to-RequireJS-2.0#wiki-shim
I’m currently testing various asynchronous-resource-loaders to see which one I want to use. At the moment Curl is throwing a ‘Promise already completed’ error…and their documentation says ‘this should never happen’.
I “suspect” I must to use a ‘define’ within each file being loaded (hope not). Further, their documentation says Curl can work with non-AMD javascript files. But...I am new to AMD and since Curl is far-faster than the other ones I'm testing...I am willing to put some time into understanding this better.
Lastly...
Even though FireBug shows the errors...all the files STILL LOAD asynchronously! But, BECAUSE there are errors...the 'then' portion of the code never gets called.
So My Questions Are:
Do I have to update all the JavaScript file-objects to be contained in a 'define'? (...hope not)
Can you see any other problem syntactically?
The Head’s Code Looks Like This:
<script type="text/javascript">
///<summary>Configuration</summary>
curl = { baseUrl: 'Includes/JavaScript/' };
</script>
<script src="Loaders/Curl/curl.js" type="text/javascript"></script>
<script type="text/javascript">
function onSuccess() {
}
function onError(ex) {
//alert(ex);
}
require(["MooTools/Core/mootools-1.2.2-core-jm",
"MooTools/mGeneral",
"jQuery/Core/jquery-1.3.2",
"jQuery/Core/jquery.tools.min",
"jQuery/ThirdPartyPlugIns/jquery.tmpl"])
.then(onSuccess, onError);
//require(["jQuery/TopUp/top_up-min"], null);
require(["jQuery/ThirdPartyPlugIns/jquery.dimensions",
"jQuery/ThirdPartyPlugIns/jQuery.Color.Animations",
"jQuery/ThirdPartyPlugIns/jquery.corners.min",
"jQuery/ThirdPartyPlugIns/jquery.tipsy",
"jQuery/ThirdPartyPlugIns/jquery.numberformatter-1.1.0",
"jQuery/ThirdPartyPlugIns/jquery.tipsy"]);
require(["general",
"WindowCenter",
"ThirdPartyPlugin/KeyBoardCapture",
"ThirdPartyPlugin/bsn.AutoSuggest_2.1.3",
"ee/8Ball",
"ee/EE"]);
</script>
Again...I'm sure it is caused by inexperience with AMD-styled code, but I still need help...so any is appreciated.
Typically, you should wrap your modules in a define() or append a define() at the end of the file if those modules have no dependencies. It seems, though, that those modules all depend on jQuery, if not other modules/files.
Since you're not using standard AMD require()/define() protocol, AMD is not really helping you with these modules. Unless you plan to write your own modules using define(), then you could use just about any async loader.
That said, there is a way to make curl.js work with non-AMD modules/files. Use the js! plugin. Here's your first block of files translated to use the js! plugin (note I also added the ".js" ext back on which I like to do with non-modules):
// we load the core files first, then get the next block that depends on them
curl([
"js!MooTools/Core/mootools-1.2.2-core-jm.js",
"js!jQuery/Core/jquery-1.3.2.js"
]).next([
"js!MooTools/mGeneral.js",
"js!jQuery/Core/jquery.tools.min.js",
"js!jQuery/ThirdPartyPlugIns/jquery.tmpl.js"
]).then(onSuccess, onError);
If any of those files within each array depend on each other, you can also use the !order suffix on them to ensure they wait for other files before executing/evaluating (be sure you're setting proper cache headers, though). Actually, the !order suffix is the fastest method as long as there are no caching issues (mobile browsers add some additional constraints on file size).
Were there any other error messages? Specifically, I would expect curl.js to throw at least one error besides just "Promise not completed".
Also, please check the Net tab (Firebug) or the Network tab (Chrome) to check that curl.js is looking in the correct location for the modules.
FWIW, I am planning to remove the alias require --> curl. The reason is that the global require function is non-standard (and explicitly not standardized in the AMD proposal). I suggest you use curl() instead of require().
curl.js also allows it's top-level api to be aliased explicitly via the "apiName" config param if you really, really want to use the name "require". :)
<script>curl = { apiName: "require" }; </script>
<script src="path/to/curl.js"></script>
<script>require(["some/modules"]).then(success, failure);</script>
More FWIW: the standard require is typically only needed in a module and can be requested by including it as a dependency:
define(["require"], function (require) {
require(["another/module"], function (another) {
// use another module here
});
});
-- John
If you're only doing normal javascript file loading (not modules), as it appears, i would encourage you to check out LABjs (http://labjs.com). LABjs focuses on being the most performance optimized loading solution (to the exclusion of some other features like module/dependency style stuff).
In fact, LABjs 2.0a (https://github.com/getify/LABjs/blob/master/next/LAB.src.js), which will be fully released in the next few days, is really exceptionally fast (even more than 1.2) at loading general scripts in parallel. I encourage you to give it a try, unless (as John eludes to above) you plan to go to module syntax... then stick with Curl or RequireJS.
We develop an application in an embedded environment. It is a high level computing environment with a complete webbrowser on top of a busybox Linux system. The only exception is that the system has a limited amount of system memory.
Our application is built in JavaScript and runs inside a Webkit based webbrowser and consists of a lot of javascript modules that are loaded in sequence (Which is not very efficient).
Some modules provide common functionality that is used by several modules. We are in the process of converting our current javascript loader with requirejs, but there is one specific need we have to address first.
Is it possible to unload a module when it has been loaded using requirejs? Assume that we dynamically loads a module using :
require(["somemodule.js"], function(m) { m.run(); } );
That works well for loading and running 'somemodule' and also resolving all dependencies for 'somemodule' and the requirejs framework will store a reference to 'somemodule' for future requests.
If we at some point need to reclaim memory, e.g to be able to load and run an infinite number of modules, we have to start removing some of them after some time. Is that possible with requirejs without altering the internal implementation?
Has anyone dealt with this kind of problem before? Most single page JS apps runs in a webbrowser on a desktop PC where memory usage usually is not a major concern.
RequireJS does not have a built-in unload feature, but it could be added perhaps as an additional part you could build into it. If you would like to have that feature, feel free to propose it in the mailing list or as a GitHub issue.
If you wanted to experiment to see if it helps your situation, what you need to do is the following:
1) Remove the defined module from the RequireJS module cache. If you are not using the multiversion support, you can do something like:
var context = require.s.contexts['_'];
delete context.defined[moduleName];
delete context.specified[moduleName];
delete context.loaded[moduleName];
2) Then you can try removing the script tag to see if that helps:
var scripts = document.getElementsByTagName('script');
for (var i = scripts.length - 1; i >= 0; i--) {
var script = scripts[i];
if (script.getAttribute('data-requiremodule') === moduleName) {
script.parentNode.removeChild(script);
break;
}
}
Note that the module may not be garbage collected if another module holds on to it via the closure function(){} that defines that other module. That other module would need to be removed too.
You can try to limit that impact by not passing in the module as a function argument, but just use require("somemodule") inside the function definition whenever you want to get a hold of dependent modules, and not holding on to that require return value for too long.
Also, in your example above, for modules that use require.def to define themselves, it should look like this (without the .js suffix):
require(["somemodule"], function(m) { m.run(); } );
Try this: require.undef(moduleName)