common_tempaltes file is not a requirejs file - rather a file that defines a global variable.
common_templates needs hogan. they both are requested more or less at the same time, but race condition is in affect. common_templates sometimes wins so the code fails with "hogan not loaded yet".
require(['module1', 'hogan', 'common_templates'], function(Module){
Module.do_stuff() // this module also requires hogan and common_templates to be loaded
});
other than nested require, is there a built in way to tell require to block until hogan is fully downloaded?
nested:
require(['hogan'], function(Fn, Ui){
require(['common_templates'], function(){
require(['module1'], function(Module){
Module.do_stuff();
});
});
});
This approach seems a bit hacky. is there a built in way to work around these race conditions?
If common_templates is not an AMD module (doesn't contain a define([deps]) call), then you need to configure it as a shim:
require.config({
shims: {
common_templates: {
deps: ["hogan"]
}
}
});
Now, require(['module1', 'hogan', 'common_templates']) and require(['module1', 'common_templates']) should work.
I had this exact same issue. I needed to essentially 'block' my program flow to ensure that an initial list of dependencies were loaded before a second list of dependencies, and then finally my main application code. Here is how I solved it. This is the Require.js call I made in my index.html file:
<script src="/js/lib/require_2.1.22.js"></script>
<script>
//debugger;
//Load common code that includes config, then load the app
//logic for this page. Do the requirejs calls here instead of
//a separate file so after a build there are only 2 HTTP
//requests instead of three.
requirejs(['/js/common_libs.js'], function (common) {
//debugger;
//Ensure the the AdminLTE code and its dependencies get loaded prior to loading the Backbone App.
requirejs(['/js/lib/adminlte.js'], function (common) {
//debugger;
//The main file for the Backbone.js application.
requirejs(['/js/app/main_app.js']);
});
});
</script>
The common_libs.js file contains the requirejs.config({shim:...}) stuff. The adminlte.js library does it's own dependency checking and will complain on the console if it does not detect it's dependencies. My problem was that it was getting loaded asynchronously with its dependencies and was causing a race condition.
I was able to wrap the existing code in adminlte.js like this:
//My experiments with Require.js to prevent race conditions.
define([
'jQuery-2.1.4.min',
'bootstrap.3.3.6',
'jquery.slimscroll.min'
], function($, Bootstrap, SlimScroll ) {
//Existing code goes here
...
//I knew to return this value by looking at the AdminLTE code. Your mileage may vary.
return $.AdminLTE;
});
That allowed me to load this library separately with its dependencies. The code in adminlte.js is only execute after its dependencies are loaded. Then, and only after that is complete, will main_app.js be loaded, along with its dependencies.
Structuring your code this way allows you to explicitly load your dependencies in batches.
Editing for clarity:
The dependencies are loaded in stages. To clarify the example above:
In the first stage jQuery, Boostrap, and the SlimScroll library are loaded, then the adminlte.js file is execute.
In the second stage, all other dependencies are loaded, then the main_app.js file is executed. main_app.js will have its own defined([], ...) function that calls out the rest of the dependencies it will need loaded.
This is much more efficient than writing a nested require() call for each dependency. And, as far as I can tell from the requirejs.org website, this is the 'proper' way to load serial dependencies.
Coding Update:
I also had to wrap the code in the jquery.slimscroll library inside a define() statement in order to explicitly call out the that this library depends on jQuery. Otherwise it was setting up another chance at a race condition.
This does not make sense, you said "common_templates requires hogan" but if common_templates requires hogan then hogan will already be loaded when the common_templates code starts.
Make sure common_templates.js is defined like this:
define(['hogan'], function(){
//common_templates suff here
});
Related
When multiple JavaScript modules are define()'d using AMD and concatenated into a single file, are those modules still considered asynchronous?
Generally speaking, just concatenating a bunch of AMD modules together won't make them synchronous. However, if you can live with additional limitations and select a loader that can do it, you can load AMD modules synchronously.
RequireJS
I don't know of a case where RequireJS will load anything synchronously, even if asynchronous loading is not needed. You could have the following in a <script> tag:
define("foo", [], function () {
});
require(["foo"], function (foo) {
});
There is nothing to load here because all the code is already present there. The foo module does not need to be fetched from anywhere. It's list of dependencies is known, etc. Yet, RequireJS will handle it asynchronously.
One source of confusion for some wondering about RequireJS' capability to load modules synchronously could be RequireJS' synchronous form of require. You can do:
define(function(require) {
var foo = require("foo");
});
The call to require here looks like it is synchronous but RequireJS transforms it behind the scenes into this, by adding "foo" to the list of define's required modules:
define(["foo"], function(require) {
var foo = require("foo");
});
So while the require call looks synchronous, RequireJS still handles it asynchronously.
Almond
Almond is a loader made by James Burke, who is also the author of RequireJS, that can load AMD modules synchronously. Now, Almond comes with a series of limitations. One such limitation is that you can't load anything dynamically. That is, the entire list of modules you want to load has to be part of the optimized bundle you create with r.js and give to almond for loading. If you can live with the limitations of almond, then it is quite possible to load a bunch of AMD modules synchronously. I've provided details on how to do this in this answer.
Yes, they are still considered async.
While the module itself doesn't have to be loaded from disk, the modules do need to be executed and there is a call back made.
Because you can combine SOME modules into a single file doesn't mean you have to combine all -- nor does RequireJS assume all there.
It will run what it can from your preload and async load the rest.
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
}
I looked at many examples on the internet how to start develop BB applications with requireJS but I am a kind of lost.
I think AMD has a goal that it load files only if they really needed. Not sooner.
Why I am seeing examples only where the developer put almost every files as a dependency at the beginning of his/her main file?
Here is an example:
https://github.com/jcreamer898/RequireJS-Backbone-Starter/tree/master/js
This application instantly loads main.js which depends on app.js which loads routers/home.js which requires views/view.js which loads the view's template and models/model.js which ... and end.
I can't see how to extend this application for example with more views where views' dependencies (its models, templates, collections, third party APIs, etc) load only when the router calls and initialize them. Other way this would be nonsense to use AMD where you load all your files when initializing your app.
Similar example here:
http://backbonetutorials.com/organizing-backbone-using-modules/
see router.js file.Actually it loads 'views/projects/list' and 'views/users/list' dependencies while the router does not know yet whether the user will need them in the future or not.
Please advise, thanks in advance!
It's a bit hard to see in such a small sample app, because you have to load something on the initial route, and loading something in Backbone usually means a model, a collection, and a view. Since the sample you linked has only one of each, then yes you're loading almost everything.
Where you start to see the "on demand" feature is where you add additional routes/views/models/etc. Keep in mind, however, that on-demand loading is probably a secondary goal of AMD/RequireJS. The primary goal is modularity. They then give you lots of options for either loading things on demand, or bundling everything up via the optimizer
Also there is nothing which says you have to put all the require() at the beginning of the file. You can do them later (e.g. when initiating a route). Here is a modified version of home.js from your first linked example. If you're using Chrome dev tools you can look at the network tab when the "debugger;" statement pauses execution. Then continue execution and see how the rest of scripts get loaded.
define([
'jquery',
'backbone',
'underscore'
],
function($, Backbone, _){
var Router = Backbone.Router.extend({
initialize: function(){
Backbone.history.start();
},
routes: {
'': 'home'
},
'home': function(){
debugger;
require(['views/view'], function (mainView) {
mainView.render();
});
}
});
return Router;
});
See this person's article for more background and where you might go next with it.
I tried unsuccessfully to add a google map(externally loaded script) to a meteor app, and I noticed there were two kinds of problems:
If I do the simple thing and add the main API script to my <head></head>, then it gets rendered last.
When this happens, I am obliged to insert any scripts that depend on the API again in my template's <head> - after the main API script. (otherwise scripts complain they don't see the API blabla..)
Then the time for the actually function call comes - and now putting it inside <head> after the rest won't work. You need to use Template.MyTemplate.rendered.
Basically my question is:
What's the cleanest way to handle these kinds of things?
Is there some other variable/method I can use to make sure my Google main API file is called very first in my HTML?
I just released a package on atmosphere (https://atmosphere.meteor.com) that might help a bit. It's called session-extras, and it defines a couple functions that I've used to help with integrating external scripts. Code here: https://github.com/belisarius222/meteor-session-extras
The basic idea is to load a script asynchronously, and then in the callback when the script has finished loading, set a Session variable. I use the functions in the session-extras package to try to make this process a bit smoother. I have a few functions that have 3 or 4 different dependencies (scripts and subscriptions), so it was starting to get hairy...
I suppose I should add that you can then conditionally render templates based on whether all the dependencies are there. So if you have a facebook button, for example, with helpers that check the Session variables, you can give it a "disabled" css class and show "loading facebook..." until all the necessary scripts have loaded.
edit 03/14/2013
There is also an entirely different approach that is applicable in many cases: create your own package. This is currently possible with Meteorite (instructions), and the functionality should soon be available in Meteor itself. Some examples of this approach are:
jquery-rate-it: https://github.com/dandv/meteor-jquery-rateit
meteor-mixpanel: https://github.com/belisarius222/meteor-mixpanel
If you put a js file in a package, it loads before your app code, which is often a good way to include libraries. Another advantage of making a package is that packages can declare dependencies on each other, so if the script in question is, for example, a jQuery plugin, you can specify in the package's package.js file that the package depends on jQuery, and that will ensure the correct load order.
Sometimes it gets a little more interesting (in the Chinese curse sense), since many external services, including mixpanel and filepicker.io, have a 2-part loading process: 1) a JS snippet to be included at the end of the body, and 2) a bigger script loaded from a CDN asynchronously by that snippet. The js snippet generally (but not always!) makes some methods available for use before the bigger script loads, so that you can call its functions without having to set up more logic to determine its load status. Mixpanel does that, although it's important to remember that some of the JS snippets from external services expect you to set the API key at the end of the snippet, guaranteed to be before the bigger script loads; in some cases if the script loads before the API key is set, the library won't function correctly. See the meteor-mixpanel package for an example of an attempt at a workaround.
It's possible to simply download the bigger js file yourself from the CDN and stick it in your application; however, there are good reasons not to do this:
1) the hosted code might change, and unless you check it religiously, your code could get out of date and start to use an old version of the API
2) these libraries have usually been optimized to load the snippet quickly in a way that doesn't increase your page load time dramatically. If you include the bigger JS file in your application, then your server has to serve it, not a CDN, and it will serve it on initial page load.
It sounds like you're loading your Javascript files by linking it with HTML in your template. There's a more Meteor way of doing this:
From the Meteor Docs:
Meteor gathers all JavaScript files in your tree with the exception of
the server and public subdirectories for the client. It minifies this
bundle and serves it to each new client. You're free to use a single
JavaScript file for your entire application, or create a nested tree
of separate files, or anything in between.
So with that in mind, rather than link the gmaps.js into head, just download the un-minified version of gmaps and drop it in you application's tree.
Also from the Meteor Docs:
It is best to write your application in such a way that it is
insensitive to the order in which files are loaded, for example by
using Meteor.startup, or by moving load order sensitive code into
Smart Packages, which can explicitly control both the load order of
their contents and their load order with respect to other packages.
However sometimes load order dependencies in your application are
unavoidable. The JavaScript and CSS files in an application are loaded
according to these rules:
Files in the lib directory at the root of your application are loaded
first.
[emphasis added]
And if the sequence is still an issue, drop the js file into client/lib and it will load before all the Javascript you've written.
I've used meteor-external-file-loader and a bit of asynchronous looping to load some scripts, which will load javascript (or stylesheets) in the order you specify.
Make sure to have meteorite and add the package above >> mrt add external-file-loader
Here's the function I wrote to make use of this package:
var loadFiles = function(files, callback) {
if (!callback) callback = function() {};
(function step(files, timeout, callback) {
if (!files.length) return callback();
var loader;
var file = files.shift();
var extension = file.split(".").pop();
if (extension === "js")
loader = Meteor.Loader.loadJs(file, function() {}, timeout);
else if (extension === "css") {
Meteor.Loader.loadCss(file);
loader = $.Deferred().resolve();
}
else {
return step(files, timeout, callback);
}
loader.done(function() {
console.log("Loaded: " + file);
step(files, timeout, callback);
}).fail(function() {
console.error("Failed to load: " + file);
step(files, timeout, callback);
});
})(files, 5000, callback);
}
Then to use this, add to one of your created methods for a template like so:
Template.yourpage.created = function() {
var files = [
"//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js",
"javascripts/bootstrap.min.js"
];
loadFiles(files, function() {
console.log("Scripts loaded!");
});
}
Quick edit: Found it's just a good idea to place the functionality from the .created method in the /lib folder in Meteor.startup();
Meteor.startup(function() {
if (Meteor.isClient) {
// Load files here.
}
});
Caveat: Lots of javascript files = really long load time.... Not sure how that will be affected by the normal meteor javascript files, and the load order there. I would just make sure that there are no conflicts until users take action on the website (or that if there is, they are loaded first).
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...)