Engineering
Releases
News and Events

JavaScript modularity (without the buzzwords)

Almost ten years ago Adrian Colyer wrote a memorable blog post, giving the best explanation on aspect oriented programming (AOP) out there: clear and simple style, accurate content, no buzzwords. If you’ve taken a look at the the earlier two posts in this series, you may have noticed some of our architecture choices in the client module of the Sagan application, including the use of JavaScript modules.

In this post, I want to walk you through the basics of JavaScript modules in the style of Adrian’s post: clear, simple, accurate, no buzzwords!

Why JavaScript needs modularity too

If, like me, you have a Java background, some JavaScript language features may look a bit odd to you:

  • its strong prototypal nature
  • no software component unit: no packages nor modules built in the language
  • difference of programming style between browser applications and server applications

Simple web applications usually look like this:

<html>
<head>
	<!-- scripts are loaded **sequentially** -->
	<script src="jquery.js"></script>
	<script src="widget.js"></script>
	<!-- all objects are in the global namespace, 
			 no way to isolate the code completely! -->
	<script>
		window.$; // this is jquery
	</script>
</head>
</html>

Developers often try to reuse blocks of functionality and manage dependencies between them. That’s really hard to achieve in the previous case: you have to declare scripts in the right order and avoid name collisions without any metadata about dependencies. With a growing application, this task becomes a nightmare: imagine managing your Java applications without the benefit of packages or dependency management infrastructure!

Understanding JavaScript authoring formats: commonJS and AMD

Fortunately, the JS community is well aware of the need for modularity and over the last few years, a couple widely-adopted approaches to solving this problem have emerged:

AMD (Asynchronous Module Definition) is one of them:

// defining a module that depends on "graphmodule",
// injected in the function definition as an argument
define(["graphmodule"],
  function (graph) {
    // this module exports a "draw" function
    return function draw(data) {
      return graph.piechart(data);
    }
  }
);

The AMD format is often used in browser applications, since:

  • it allows variables to be scoped inside the factory function (vs. having everything in the window global scope)
  • dependencies may not be available synchronously, e.g., they need to be fetched via asynchronous network request
  • modules are defined in a callback, then run once all dependencies are loaded

CommonJS is another authoring format, often used in Node.js applications on the server side, but also in browser applications.


/** * Our module's dependencies and API **/ // we fetch the graph module as a dependency var graph = require('graphmodule'); // we decorate the `exports` variable to export our function exports.draw = drawFunc; /** * API implementation **/ function drawFunc(data) { return graph.piechart(data); }

You probably spotted some differences with AMD:

  • this authoring format can be used in the browser and on the server!
  • thus you can test your modules in headless browsers and Node.js unit tests!
  • module definitions aren’t wrapped in a define

What’s next?

The next version of JavaScript (technically called ECMAScript 6) will standardize JavaScript modularity, albeit using a slightly different syntax than either the AMD or commonJS formats we’ve seen above.
More, EcmaScript 6 will solve many problems in that space but will also make available syntactic sugar to define OO-like classes.

Wherever you’re putting JavaScript to use, be it client or server, consider taking the modular approach — for all the same reasons we do in Java. There is a small learning curve to getting proficient with JS module technology, but the results are well worth it.

If you’re brand new to JavaScript modularity, I recommend checking out the “Authoring CommonJS modules” tutorial and the module loader we’re using in Sagan: curl.
And once you’re feeling familiar, take a look at our module definitions in the Sagan app.

comments powered by Disqus