10 March 2009 ~ 7 Comments

Enabling Dynamic Plugin Support for your JavaScript Application

Hi fellow reader,

I recently came through a problem while working on a javascript framework on top of jQuery.  At one point, having one big javascript file containing all the application objects becomes hard to both naviguate and maintain.

From here you want to ease your developement process by splitting your main class in small, specialized, classes stored in different files and then includes all these files using <script> tags. This is not convenient, you will have HTTP connections overhead even before your page DOM is loaded and displayed.

You could eventually make use of a server side tool like the PHP library Minify to combine, minify and cache your javascript files. Hovewer I’ll talk about a system that dynamically and on-demand loads components using jQuery’s Ajax implementation.

Simple Javascript Class

Let’s start a simple Javascript Class :

var shinyObject = function() {

};

Extending our classe  with the saySomething() method :

shinyObject.saySomething = function() {
  alert("Something");
}

Ok,  in firebug console we can now type shinyObject.saySomething();  and the revelant code will be executed.

Plugin support

Warning, the following code is for concept demonstration pupose only on should not be used in production. Please disregard security concerns, this is not the point.

Onto creating our plugin module loader for our main class. Here is the new method :

shinyObject.loadPlugin = function(options) {
  this.plugin_path = "./";

  $.ajax(
    {
      type      : "get",
      url       : shinyObject.plugin_path + options.name + ".js",
      dataType  : "text",
      success   : function(code) {
        if(typeof shinyObject[options.name] != 'object') {
          var plugin = eval(code);
          if(typeof plugin == 'object') {
            shinyObject[options.name] = plugin;
          }
          else {
            alert("Impossible to load " + options.name + " module. Please check your module code syntax.");
          }
        }
      }
    }
  )

This snippet is rather easy to understand, the loadPlugin method take a single JSON object as argument, this is convenient because we will want to add more parameters later.  The name of an existing file is passed to the ajax() jQuery method and the results of this HTTP request is passed to a callback function.

If  shinyObject do not already have an instance of this particular plugin in its register table, then we evaluate the code. If the evaluated source code is a valid javascript object, we are affecting  it to a new entry in it’s register table, otherwise,  warn the developper of possible mistake in the plugin.

Creating a Plugin

To create a plugin for our appplication let’s create a new file in shinyObject.plugin_path  named saySomethingElse.js and put the following snippet inside :

(function () {
  var a_local_variable = "local variable is local";

  return {
    saySomethingElse = function() {

      alert("Something Else Matters!")
      alert("And you can use local variables because : " + a_local_variable);

    }
  }
})();

The important thing here is the self executing function notation :


(function () {
  /* code */
})();

This notation is making the difference between a simple library and an autoexecuting piece of code that returns an object.

Loading a Plugin

Will are now adding the loadPlugin() call to our the onReady event of the page:


$(document).ready(function() {
  shinyObject.loadPlugin({'name': 'saySomethingElse'});
}); 

Once the DOM ready for action, our shinyObject will automatically load its dependencies. If the code contained in your plugin do not have to deal with the DOM at all, you can safely make this call directly from the <head> part of your html document. Call me obessional programmer if you want, but I personaly find it more convenient to have everything initialized a the same place.

Using our Plugin

Once loaded successfuly, you can access your plugin’s public methods and properties like this :

/* Simple Method call */
shinyObject.saySomethingElse.saySomethingElse();
/*
Object.ModuleName.Method();
*/

As simple as 1, 2, 3.

Conclusion

What we achieved here is rather simple but can be extremely useful in nowadays web applications, even regarding performances. Let’s say we are building a big application with hundred of plugins that may be optional widgets for our users. The solution described at the begining of this article will generate a great overhead in both bandwith and HTTP requests prior page rendering.

Benefits of our dynamic plugins:

  • Fast Page rendering
  • Decoupled loading using Asyncronous HTTP
  • Saves a part of the Bandwidth
  • Easier library management for developpers

What about you dear reader ? What are your solutions for huge javascript libraries management and plugin support ? I’m really interested to know about it !

Spread the word:
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • Twitter
  • DZone
  • Facebook
  • FriendFeed
  • HackerNews

7 Responses to “Enabling Dynamic Plugin Support for your JavaScript Application”

  1. Brian 13 March 2009 at 9:53 pm Permalink

    Any thought to an alternative to eval()?

    http://blogs.msdn.com/ericlippert/archive/2003/11/01/53329.aspx

  2. Brian 13 March 2009 at 10:06 pm Permalink

    P.S. How about implementing this within the confines of jquery.livequery.js? For example, say i want to run my $().alternate() plugin on all tables? Currently I use this…

    $(‘table’).livequery(function(){
    $(this).alternate();
    });

    How might i use your concept to only load the alternate plugin when it’s needed here?

  3. Nicolas Crovatti 13 March 2009 at 11:52 pm Permalink

    @Brian
    Hi Brian !
    Thanks for the pointer to a great article!

    Here is an excerpt from Eval is Evil article, first paragraph:

    There are a few scenarios in which eval is invaluable. For example, [...] when you are serializing object state to a string so that it can be stored or transmitted, and reconstituted later.

    I think we are in that particularly invaluable usage of eval :)

  4. Brian 14 March 2009 at 12:06 am Permalink

    @Nicolas Crovatti

    Thanks for the reply Nicolas! I’ve come across the “eval() is evil” comment on several occasions so I was curious. Obviously i have things to learn ;)

  5. Nicolas Crovatti 14 March 2009 at 12:10 am Permalink

    @Brian
    The concept exposed here is based on a Javascript Framework that makes some use of core jQuery implementation, it’s not built using jQuery plugins systems.

    To apply the very same concept for jQuery plugins system, you might want to create first a plugins that deals with plugins management like exposed here ;)

  6. Webkatalog 19 March 2009 at 2:08 am Permalink

    Thank you for your help!


Additional comments powered by BackType