Javascript Development with the Xataface Javascript Compiler

Javascript is a wonderful language, but I always felt as if it wasn’t terribly scalable. Not so much in the performance sense, but in the component sense. When working on large projects (like Xataface) Javascript can seem a little too “scripty” to build components in. I’m always fighting between the two conflicting goals of library size and library functionality.

If you build a useful library in Javascript it is usually either comprehensive and large, or small and single-purpose. It is possible to build the library in pieces and just include the parts that you want, but then you end up with a cumbersome set of script includes in your HTML page every time you want to use your library’s functionality. This is error-prone as it is easy to forget which scripts you need to load for any particular function to work.

In server-side languages you don’t have this problem. When you write a script in C, PHP, Python, Java (or any other language), you can just include your dependencies at the top of your file using an import, include, or require statement (syntax depends on the language). Then using your library is as simple as including one file – and all of that file’s dependencies will automatically be imported as well.

To solve this problem, I developed a Javascript compiler as part of Xataface. Some features of this compiler include:

  • Compiler directives to process dependencies.
  • Javascript Compression – to minimize the footprint.
  • Duplicate Dependency tracking (i.e. If multiple scripts all require the same script as a dependency, then the dependency will only be included once).
  • Compiler directives to include CSS files.
  • Compiler directives to import files as strings.
  • Configurable source paths. (i.e. Just like with other languages, you can specify multiple paths where source files will be located).

This doesn’t sound like a lot, but these features really improve the Javascript development experience. It allows me to develop reusable components that can be shared and imported into many different projects without having to deal with the complexities of including script tags in an HTML page, or making sure that the proper CSS files are included. Once you have built a component, it is done. All you need to do in order to use it in your application, is include it using the //require directive.

Let’s look at an example…

All of these features are provided by the Dataface_JavscriptTool class in Xataface. So you begin by obtaining an instance of this, and adding the source path where you want it to look for Javascripts.

import('Dataface/JavascriptTool.php');
$jt = Dataface_JavascriptTool::getInstance();
$jt->addPath('/path/to/javascripts', 'http://www.example.com/url/to/javascripts');

At this point the compiler knows to look in the /path/to/javascripts directory for scripts. But you haven’t told it to include any particular script. That’s our next step:

$jt->import('myscript.js');

If you were write this code inside the context of a Xataface application, your myscript.js file would run because Xataface handles the rest of the rendering at the end of the body of any template extending the Dataface_Main_Template.html template (which is pretty much all templates).

Note that by default the following directories are included in your javascript paths:
– DATAFACE_SITE_PATH/js
– DATAFACE_PATH/modules/XataJax/js
– DATAFACE_PATH/js

So you are able to use any script in those directories without needing to call the addPath() method of the JavscriptTool.

A look at the Javascript

myscript.js:

alert('hello world');

This just pops up an alert. Let’s get to some best practices right away though. The general structure of a script usually goes as follows:

//require <myotherscript.js>
(function(){
    alert('hello world');
})();

Note the //require statement on the first line. This tells the compiler to include the script myotherscript.js in its place. The compiler will look first in the /path/to/javascripts directory, then in DATAFACE_SITE_URL/js, then in DATAFACE_URL/modules/XataJax/js, then in DATAFACE_URL/js to see if it can find a script by that name. If it cannot find one it will throw an exception with a stacktrace. If it finds it, it will include the contents of the script in place of the require statement.

Example: Requiring jQuery

Xataface comes with lots of libraries included in its source paths. jQuery is one that is used in almost every script:

//require <jquery.packed.js>
(function(){
    var $ = jQuery;
    alert('Hello world');
   
})();

Note that on the first line, we make a reference $ to jQuery. This is because in Xataface jQuery.noConflict() is set so that it doesn’t conflict with other libraries that want to use the $ variable. By declaring it inside our wrapping function(){}, we are able to still use the $ shorthand without polluting the global namespace.

Using jQuery UI

The following example is meant to show why we need to be able to bind CSS with your javascript libraries. We are going to use jQuery UI’s dialog to display our ‘Hello world’ message, and this requires a CSS file in order to look proper:

//require <jquery.packed.js>
//require <jquery-ui.min.js>
//require-css <jquery-ui/jquery-ui.css>
(function(){
    var $ = jQuery;
    var dlg = $('<div>').append('Hello World').appendTo('body');
    dlg.dialog();
})();

These examples are just the tip of the iceberg of possibilities that a Javascript compiler brings. More cool examples will be forthcoming as Xataface 2.0’s release nears.

comments powered by Disqus