Javascript Namespace Inclusion, loaders and all that…!

Intro:
In its current specification, the Javascript language (ECMA-262) has no inherent facility for loading packages/modules other than the handy script tag. Developers had to make do with dynamically creating the script tag and inserting it into the DOM as shown below:

// Very simple asynchronous script-loader

// Create a new script element
var script      = document.createElement('script');

// Find an existing script element on the page (usually the one this code is in)
var firstScript = document.getElementsByTagName('script')[0];

// Set the location of the script
script.src      = "http://example.com/myscript.min.js";

// Inject with insertBefore to avoid appendChild errors
firstScript.parentNode.insertBefore( script, firstScript );

// That's it!

Equivelants such an import, include or require statements present in the design of programming languages such as Java, C/C++, Ruby, Python etc. has enabled developers to prevent namespace pollution and organize their code in a modular fashion
promoting loose coupling and re-use of components in software projects.

So what are the advantages of namespaces:

  • Architectural design pattern
  • Organize files into shareable modules
  • Create a maintainable and re-useable code base
  • Improve load speed
  • Makes code available to the current namespace

Asynchronous Module Definition (AMD)
AMD evolved as a mechanism for Javascript developers to develop modular Javascript code such that modules and their dependencies could be loaded asynchronously. This would be speed-up load times and avoid blocking or waiting of dependant script during the loading process.

So, as I was looking into developing an app using Ember.js, I was confronted with this simple problem – how to include JS function in files spread into different directories:

MyApp/
    App.js
    index.html
    app/
        assets/
               css/
               img/  
        models/
        views/
        controllers/
        stores/

As I was pondering on this point…yah…I had a list of ideal features in mind that I needed and some nice to have’s:

Requirements/Features:

  •  Framework agnostic
  • Local and remote loading eg. CDN repositories
  •  Dynamic loading
  •  Single/unique instance loading of script file
  •  Dependency management – load order
  •  Parallel or ‘Non-blocking’ loading ie. loading scripts that do not have dependencies
  •  Synchronous and Asynchronous loading
  •  Loading of assets/resource eg. HTML, CSS, images
  • Track versioning
  • File concatenation


….Googling and a few clicks….resulted in me compiling a short list of Javascript
loaders for future reference:

Resources:

  1.  Ajile – http://ajile.net/
  2. RequireJS – http://requirejs.org/docs/api.html 
  3. Inject – https://github.com/linkedin/inject
  4. jsLoad – http://code.google.com/p/jsload/
  5. Sprockets- https://github.com/sstephenson/sprockets – used at 37signals
  6. LabJS – http://labjs.com/ – used at Getify Solutions
  7. HeadJS – http://headjs.com/
  8. LoadRunner – https://github.com/danwrong/loadrunner
  9. Yahoo YUILoader – http://developer.yahoo.com/yui/yuiloader/ – Yahoo
  10. JQuery.atreq – https://github.com/phleet/jquery.atreq
  11. PyramidJS – http://joel.inpointform.net/software-development/pyramid-js-a-web-dependency-manager
  12. ControlJS – http://stevesouders.com/controljs
  13. StealJS – http://javascriptmvc.com/docs.html#!stealjs – JavascriptMVC
  14. LazyLoad – https://github.com/rgrove/lazyload
  15. NBL – http://berklee.github.com/nbl
  16. CurlJS – https://github.com/unscriptable/curl
  17. YepNopeJS – http://yepnopejs.com/
  18. PINF- https://github.com/pinf/loader-js
  19. Yabble – http://github.com/jbrantly/yabble
  20. ScriptJS – http://dustindiaz.com/scriptjs

Simple examples:

LoadRunnerJS:

1
2
3
4
5
6
7
8
9
// use some javascript files
using('javascripts/jquery.js', 'javascripts/underscore.js', function()
{
$(function() {
_(['foo', 'bar', 'baz']).each(function(i) {
$(document.body).append('<p>' + i + '</p>');
});
})
});

PyramidJS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//set the rootPath. The rootPath determines
//the base directory where all the files get loaded from.
Pyramid.rootPath = './';
//Set up file dependencies
Pyramid.newDependency({
name: 'standard',
files: [
'standardResources/jquery.1.6.1.min.js'
]
});
Pyramid.newDependency({
name:'lookAndFeel',
files: [
'styles.css',
'customStyles.css',
'createAnimations.js'
]
});
Pyramid.newDependency({
name:'main',
files: [
'createNamespace.js',
'models/person.js',
'init.js'
],
dependencies: ['standard','lookAndFeel']
});

NBL :
src=”nbl.js” data-nbl=”[ [ ‘http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js’, ‘jquery.lightbox.min.js’, ‘jquery.carousel.min.js’ ], function(e){ jquery_loaded(e) }, ‘http://www.google-analytics.com/urchin.js’, function(){ urchin_loaded() } ]”>

InjectJS:

1
2
require.setModuleRoot("http://example.com/js/modules");
require.run("program");

CurlJS:

1
2
3
4
5
6
7
8
9
10
curl = {
    baseUrl: '/path/to/my/js',
    pluginPath: 'for/some/reason/plugins/r/here',
    paths: {
        curl: 'curl/src/curl',
        cssx: 'cssx/src/cssx',
        my: '../../my-lib/'
    },
    apiName: 'someOtherName'
};

YepNopeJS:<

1
2
3
4
yepnope({ test : Modernizr.geolocation,
yep  : 'normal.js',
nope : ['polyfill.js', 'wrapper.js']
});

PINF:

1
program.json ~ { "boot": "github.com/pinf/loader-js/demos/HelloWorld/", "packages": { "github.com/pinf/loader-js/demos/HelloWorld/": { "locator": { "location": "./" } } } } package.json ~ { "uid": "http://github.com/pinf/loader-js/demos/HelloWorld/", "main": "main.js" } main.js ~ module.declare([], function(require, exports, module) { exports.main = function() { module.print("Hello World!\n"); } });

YabbleJS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require.setModuleRoot(path)
   Use this to configure the root path to find modules. Think of this as a
   single entry in require.paths.
require.useScriptTags()
   The default behavior is to use XHR+eval() and expects unwrapped modules. Call this method
   to configure Yabble to use script tags and expect wrapped modules.
require.run(programId)
   This kicks off an application using the specified module ID.
require.ensure(dependencies, callback)
   See Async/A for more details. Can be used to retrieve modules and run code without using
   require.run().

ScriptJS:

1
2
3
4
5
$script('analytics.js');
$script('library.js', function()
{
// do stuff with library.
});

More News

| 11th Dec 2018

What Marketers Can Learn From Burger King’s Geo-Conquesting Strategy Against McDonald’s

Who would've predicted that the physical space that your brand takes up could be up for grabs to competitors?

| 10th Dec 2018

Curriculums Aren’t Just for School Anymore

Selections from the CTO’s library and Isobar's core curriculum.

| 6th Dec 2018

The Move to Focused Markets

IGNITION 2018 - Day 2 Recap