jGrouse Component Model (jGrouse Loader)
Purpose
Most developers are quite got used to the fact that they are getting support for component development for granted. Think Java packages, DLLs in Windows, units in Delphi... Unfortunately very few JavaScript frameworks are providing similar functionality, Dojo being one of the exceptions.
In the absence of support for component/modular programming JavaScript developers are have to track manually the order in which their scripts are loaded and initialized. When the number of scripts in the project reaches certain threshold, tracking of all those dependencies becomes quite annoying.
This is where jGrouse comes to the rescue.
You won't need to download full jGrouse package, you can use jgrouse-loader distribution, which is less than 16K. Note: jGrouse Loader also provides support for object-oriented programming in JavaScript , which you can find quite useful.
The concept of jGrouse module is quite close to Delpi units. Essentially, jGrouse module it is a piece of code that might contain one or several class or function definitions, declares list of other modules that have to be initialized prior to the usage of the module and has initialisation block, which is executed after all the required modules are loaded and initialized.
Example
Typical module definition looks like the following sample code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
jgrouse.module({
name: 'com.mycompany.MyModule',
requires : ['jgrouse.dom.Element', 'com.mycompany.AnotherModule'],
imports : ['jgrouse.dom.Element.*', 'jgrouse.dom.Event'],
body : function(embed)
{
eval(embed);
// your code goes here
},
postInit : function(embed)
{
eval(embed);
// your code for module initialisation goes here
}
}); |
In this example, the module name is being specified by parameter name at line 2.
If the module is to be loaded dynamically, then the name of the module should match the name
of the file where the module is located. For example, if all the JavaScript code for your application
is located under folder 'path/to/my/scripts' then the full path to the file with our module should
be 'path/to/my/scripts/com/mycompany/MyModule.js'. This is mandatory parameter
The line #3 contains information about the modules that have to be loaded and initialized before the current module. Note that those modules might depend on other modules. In that case the framework would load and initialize the whole tree. If the module does not depend on any other modules, then this parameter could be omitted.
The next line, #4, contains information about JavaScript objects that should be imported into
the scope of the module. Importing in that case means that the code within the module would be able
to access those objects by using the short name. For example, if the object jgrouse.dom.Element
has two static methods getComputedStyle and addClassName then using the
imports parameter from the example is equivalent to the following code within
body function, inserted instead of call to eval at lines 7 and 13:
var getComputedStyle = jgrouse.dom.Element.getComputedStyle; var addClassName = jgrouse.dom.Element.addClassName; var Event = jgrouse.dom.Event;
If module does not import any objects into its scope, then the imports declaration
could be omitted
The body function at lines 5 to 10 indeed contains the body of the module. Within
that function application programmers would write the code that adds new elements to JavaScript namespace,
perform necessary manipulations, etc.
The last (and optional) entry is postInit entry. That function is being invoked
after the body function is executed. It is recommended to perform any module initialisation
activities within that function.
Using modules in your program
There are two typical scenarios of module usage:
- Specify module in the
requiressection of another module - Invoke
jgrouse.require(modules, callback)function that would trigger thecallbackwhen all the modules are loaded and initialized
For example:
Dynamic vs Static loading
As mentioned above, jGrouse is capable of loading and initialising modules dynamically,
but in certain cases it could be better to load all modules (or certain set of modules) in one shot.
That could be done by concatenating several JavaScript files into one. When using traditional JavaScript
approach it becomes necessary to track the order in which all those scripts being appended together.
In case of JGrouse it becomes irrelevant. The framework would trace the dependencies and initialize
all modules in correct order. One caveat - it is necessary to make a call to make a call to
jgrouse.ClassLoader.instance.setDeferLoading(true) before the combined script is included
and also make a call to jgrouse.ClassLoader.instance.setDeferLoading(false) after
the inclusion. The first call would instruct the loader not to try and load the modules dynamically
and the second call would essentially trigger initialisation of modules. If there would be any
modules that are not included into combined file, but required by modules in that file, then
those modules would be loaded and initialized dynamically.
The following example shows how you can create a "static" file using ANT script:
One might consider to combine all the files that would be required by user right after the page is loaded into one "static" file and leave the other components as standalone modules, so they would be loaded on demand.