JavaScript modularity (without the buzzwords)

Engineering | Brian Clozel | April 11, 2014 | ...

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.

Get the Spring newsletter

Stay connected with the Spring newsletter

Subscribe

Get ahead

VMware offers training and certification to turbo-charge your progress.

Learn more

Get support

Tanzu Spring offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.

Learn more

Upcoming events

Check out all the upcoming events in the Spring community.

View all