requireJS - a few questions - javascript

sorry for beeing a little lazy and not trying it all out myself, but I thought a nice answer on Stackoverflow might help some other guys too. I'm pondering whether or not to use requireJS to load my modules. Currently I'm doing that on my very own, so I have some questions about requireJS.
How does requireJS deal with multiple references (does it cache files/modules) ?
More precisely, if you have calls like require(["some/module", "a.js", "b.js"], function...}); and you again reference a.js or b.js in later .require or .define calls, how does requireJS handle those? My guess is, it will entirely ignore those additional references, is that correct? If so, is it possible to force requireJS to reload a script ?
Does requireJS always transfer files over the wire or you can load modules statically ?
What I normally do is, to concatenate all of my js files (modules included), except for those which need to get loaded dependent on run-time conditions. As far as I read the requireJS doc, you can define own names for modules. So my question is, can you load a module which is already present in the script, without transferring it over the wire ?
As far as I understood the doc, names are created automatically for modules, based on their path location and filename, so this would make no sense for my requirement here.

requirejs.undef() should do the trick

Normally, a module will only be loaded once by require.js. require.js will always resolve dependencies and load the modules in the right order so that you don't have to care about that. Subsequent calls to require for the same module will yield it immediately.
It is not possible to reload a module. If you really have a need for loading the same module more than once (which would unfortunately indicate that there is something wrong with your module's design) you can have a look at the Multiversion support.
I am not sure I understand what you mean by "load modules statically". But if I am guessing right you want to load several modules as one and use them seperately. This is possible:
Typically in your modules you will be doing something like:
define(['moduleA', 'moduleB', 'moduleC'], function (a, b, c) {
...
return exports;
});
where exports can be more or less anything, a function, an object, whatever. So you can also do something like:
define(['moduleA', 'moduleB', 'moduleC'], function (a, b, c) {
...
return {moduleA: a, moduleB: b, moduleC: c};
});
exporting them all together.
Note however that you should really have a look at the optimization tool. It can group related modules together.
Finally, the automatic naming is a misunderstanding, you can be explicit on the names of your modules.

Related

Why does requirejs allow you to specify a string id?

In requirejs it is possible to define an anonymous module or to give it a string id. According to this article, you would normally not use the string id:
You would not normally use the id when you define your module. It is typically used by tools when optimizing a RequireJS application.
I currently define my modules anonymously and use require.config.paths for the mappings. What I don't understand is: why does requirejs allow you to specify string id's if they're not needed?
why does requirejs allow you to specify string id's if they're not needed?
They only are not needed if require can figure out what module it is that just called define. This is the standard when require() did load the script file that contains the module, whose name and path it knows.
However, the optimizer will put multiple modules in a single file, and there needs to be a different way to figure out what modules are define()d. From the docs:
These [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.
I can't answer as to James Burke's motivations, but I can point out instances of its usefulness.
Define your own single page "layer" for testing, using JSBin or JSFiddle. The following code can be easily executed without having to stand up endpoints for each module or to use r.js to create a layer.
define('A',[], function(){ console.log('A loaded');});
define('B',[], function(){ console.log('B loaded');});
define('c',['A','B'], function(){ console.log('C loaded');});
Define a "local override" for troubleshooting. Add a define right before your require to easily preempt a module definition add a new module so you don't have to touch several files while you're working
define('plugin/fancySelect',[], function(){/* ... */});
require([ /* ... */], function(){
// your main application code
});

Can UglifyJS be a replacement for RequireJS?

I honestly don't understand the benefit of RequireJS. If I minify and concatenate all my files using UglifyJS and place the single resulting JS file just before the closing </body> tag, do I still need to use RequireJS? Besides adding 15KB to my page-size, what benefit does RequireJS offer that you cannot get with UglifyJS?
The main point on using requireJs is to have a sane way to modularize your code. Lets say you have an app with some thousand lines of code, you don't want to handle this all in one file. So if you start split it into different files you need a way to load all the single files in the right order. Sure you can create 20 script tags and make sure they are in the right order by yourself, but as your code grows you have to add more script tags and for every file you have to find the right place. This is what requireJs is good for.
Lets say you have a 3 script A.js depends on B.js which depends on C.js
with script tags it would looks like this:
<script src="C.js"></script>
<script src="B.js"></script>
<script src="A.js"></script>
//A.js
console.log('A' + B)
//B.js
B = 'B' + C
//C.js
C = 'C'
})
with requireJs
<script src="require.js" data-main="A.js"></script>
and in every script you declare the dependecies:
//A.js
require(['B.js'], function (B) {
console.log('A' + B)
})
//B.js
define(['C.js'], function (C) {
return 'B' + C
})
//C.js
define([], function () {
return 'C'
})
This is a very simple example but the point is that you don't have to care about the order of your modules as requireJs load the in the right order.
Back to your question the optimizer is more an add on, so if you have a small code base which fits in a single file and is still maintainable, just use uglifyJs. But if you want to split your code in modules requireJs is the way to go.
UglifyJS and RequireJS have very distinct purposes, and both could apply to your situation.
The idea behind RequireJS, and Asynchronous Module Definition in general, is to break your code into smaller chunks, to make it easier to manage. In terms of performance, it has two main benefits:
faster load because you can load multiple chunks in parallel
smaller footprint because you only load the parts of your code that you really need in the current context
A good example is a charting library. Browsers use different standards to render graphics: svg, vml, canvas, etc. A charting library will have code for each of these standards, but at runtime it will only load the part that is relevant to the specific device and browser.
Well, if you use a single file for each page on your site, it would be terrible for code reuse.
You wouldn't want to copy/paste the same code onto each and every page. The files wouldn't be cached, either, which would drastically increase your page load times.
See also: RequireJS's "why" page
With requirejs you can have in JS the same development process you have in other programming languages.
You can write modules, and these modules can be easily reused for other projects, by simply referring their containing file.
Ultimately, when writing for web, requirejs has an optimizer that will uglify and combine the modules together in one script.

when to define a module and when to only require files using requireJS

I'm struggling to get requireJS to work properly. Page is running fine, but I think I'm doing things in an oh-so wrong way.
For example, on page xzy I'm adding the following JavaScript at the end of the page (the JS must stay on the page for now, so no external js-files possible)
<script type="text/javascript" language="javascript">
//<![CDATA[
(function () {
require([
'async!http://maps.google.com/maps/api/js?v=3&sensor=false',
'maps/jquery.ui.map.full.min.js',
'maps/jquery.ui.map.extensions.min'
], function() {
// ... do stuff with Google Maps
}
);
}());
//]]>
</script>
Doing this makes google.map and the $.().gmap method globally available, which probably shouldn't be available globally.
Questions:
Should I convert this into a requireJS module? Why?
If so, will the module be available on other pages as well or do I just "re-define" on page 123 and the dependency files will already have been cached?
And finally - will I have to convert the code inside my require call into module.methods, which I then call via module_name.method_name(pass_some_parameters)?
Just looking at the JS:
http://maps.google.com/maps/api/js?v=3&sensor=false
You can see that window.google is a global. There's not much you can do about that without Google releasing an AMD version.
Your decision regarding should you create a module should firstly be a question of readability/maintainability of the JS code. Modules are (should be), readable, reusable chunks of code/reusable abstractions that the rest of your code can consume. You should also derive testing benefits from this - each module should be easier to test in isolation.
You can end up with many more JS files if you choose a modular approach, and you might think this leads to performance issues - i.e. multiple HTTP requests. But this is mitigated by using the RequireJS Optimiser to optimise your modules to a single file.
If you convert to a module, yes you can require it from other pages, and if your HTTP caching headers are set up, then the browser may choose to use a cached version, thus saving you a HTTP request (same caching heuristics apply if you've optimised every module into a single file).
If you re-define (I assume you mean copy and paste the code block), then those dependencies listed in the call to require should all be cached by the browser, and therefore instantly available (depending on your web server and its HTTP caching headers).
Finally, yes you may have to refactor the code a bit to expose the new module's API. If that means exposing a single object with methods, then that's what you should do. This process almost inevitably leads to better code though in my experience. As you've had to think more about what the module's purpose is, and this often leads to your breaking the coupling between pieces of code.

require.js: Access all loaded modules

Is there any way to access all loaded modules of require.js?
Background:
I want to automatically call an init() function of my javascript-modules after all of them are loaded, see require.js + backbone.js: How to structure modules that have an initialize function?
Without require.js I looped over my own module-storage and called each init() function.
I now want to do this with require.js. I'm aware that calling a my_custom_init_function_favoritecolor_petname_love123 of every loaded module (including external libraries) is dangerous. I hope that this will cause less trouble than manually keeping a list of all modules (and the requirements of these modules) up-to-date. Forgetting one module init() is much more likely than a third-party library having my custom function name (though the latter is probably harder to debug).
Or does anyone have a better idea of how to accomplish that?
Yes, require.s.contexts._.defined is an object which its keys are the module names and the values include the value returned from that module.
require.s.contexts._.defined includes all the modules (either define() or require() such as the Javascript file that is the starting point of the program and is indicated using data-main for RequireJS).
Just finished a similar behavior within my RequireJS project. require.s.contexts['_'].registry holds the list of the registered modules.
I am using Underscore.js for getting, filtering and iterating the list of modules. Maybe the following code fragment helps you:
var modules_registered = _.keys(require.s.contexts['_'].registry);
var modules_to_be_initialized = _.filter(modules_registered, function(module_title) {
return module_title.indexOf('modules') > -1;
});
_.each(modules_to_be_initialized, function(module_name) {
require([module_name], function(current_module) {
current_module.init();
});
});
I'm lazy, so I just did this:
var modulesToLoad = Object.keys(require.s.contexts['_'].registry);
require(modulesToLoad);
Based on other answers here.

Questions about Dojo modules from Dojo newb?

I'm new to Dojo so I don't quite understand all of Dojo's features. Here are some questions, but I'm sure some of them seem really stupid since I don't quite get how Dojo is structured yet:
How do you create multiple modules within a single js file and access the module in the file it's created? Also, how do you access specific modules from a file containing multiple modules?
What is the difference between require and define?
I successfully required a module from a file, but I can't figure out how to get the variables out of the file, how do you do this?
I was looking at how Dojo required its modules and notice that it does a http request for each file, but isn't that really inefficient when you're dealing with lots of modules and/or on a large site, you really would like to minimize the number of http requests necessary? What's the way around this?
Reading through The Dojo Loader will provide answers.
Basically module = file and very often (as a matter of best practice) module = file = class (more precisely public class defined via dojo/_base/declare).
Ad #4: You will need to employ The Dojo Build System, that will resolve all the dependencies and put all your modules into a single file (or more files, this depends on your build profile). Have a look at Dojo Boilerplate project, it may help with building your application.
How do you create multiple modules within a single js file?
While this is possible to do, and is done by the build system when it creates layer files, it is not recommended. Putting multiple modules in a single file means you have to use a different form of define that gives an explicit ID to eahc of them. This is less flexible then having the module IDs automatically derived from the file name and path (this, together with relative paths makes it much easier to move and rename AMD modules, compared to old-style modules)
What is the difference between require and define?
define is a beefed up version of require that defines a new module with its return value.
I successfully required a module from a file, but I can't figure out how to get the variables out of the file.
I am not sure wha toyu mean with this (without giving a concrete runnable example) but all you have to do is create an object to be the value of your module and return it from define. This is not very far off from how you would define modules the old way, with manual "namespaces"
//foo.js
define([], function(){
var M = {}; //the exported stuff will go here
var myVariable = 16; //private function variables are private (like they are everywhere else)
//and cannot be seen from the outside
M.anumber = myvariable + 1; //things on the returned object can be seen from the outside
return M; //people who require this module will get this return value
});
//bar.js
define(['foo'], function(foo){
console.log( foo.anumber );
});
I was looking at how Dojo required its modules and notice that it does a http request for each file...
As phusick pointed out, the build system can be used to bundle all the modules into a single file (giving you the best of both worlds - modularity during development and performance during deployment). It can also do other cool stuff, like bundling CSS and passing the Javascript through a minifier or through the Closure compiler, checking ifdef for creating platform-dependent builds, etc.

Categories