RequireJS for Dependency Management and Modularisation in HTML5 Applications
Introduction
In one of our most recent development blog posts Signagelive CTO Marc Benson explained why Signagelive chose to use the Ember.js framework to develop the new Signagelive Player Dashboard.
Continuing this trend of articles targeted slightly more towards software developers, this week one of our developers Matthew Hunt is going to talk about RequireJS, which is one of the core technologies that we make use of in the HTML5 media clients that power our Samsung SSSP, LG WebOS and Google ChromeOS solutions.
Due to the size and complexity of our media client a modular architecture was a fundamental requirement to ensure that the solution was reliable, maintainable and extendable going forward. Javascript lacks some of the common modularisation features that are native to many modern object-oriented languages such as C# or Java making this modular architecture difficult to achieve. RequireJS was the solution Signagelive chose to provide modularisation capabilities, which allowed us to architect our HTML5 media client in a modular way.
What is RequireJS?
RequireJS is simply a Javascript file and module loader. It was designed to address two fundamental limitations of the Javascript language when attempting to build large and complex applications by providing mechanisms to handle:
- Modularisation – allowing developers to break a large application down into a number of smaller, independent and reusable modules that can be saved across multiple files.
- Dependency Management – for ensuring that these modules are loaded and available at runtime to any other modules that depend on them.
RequireJS was the first major Javascript module loader to gain widespread popularity and back in 2012 when development started on our first HTML5-based Signagelive media client – the SSSP (Signagelive Samsung Smart Signage Player) – RequireJS was the clear choice.
How does RequireJS work?
RequireJS uses the AMD (Asynchronous Module Definition) standard for module definition and all modules must be defined using the define function. The example code snippet below shows how we could define two modules RequiredModule1 and RequiredModule2 that have no dependencies and then define a third Module MainModule that makes use of – and thus includes dependencies for – RequiredModule1 and RequiredModule2.
// Define RequiredModule1.js with no dependencies
define([], function() {
// Implementation for RequiredModule1
function RequiredModule1() {
}
return RequiredModule1;
});
// Define RequiredModule2.js with no dependencies
define([], function() {
function RequiredModule2() {
}
return RequiredModule2;
});
// Define MainModule.js which depends on RequiredModuled1 and RequiredModule2
define([‘RequiredModule1’, ‘RequiredModule2’], function(RequiredModule1, RequiredModule2) {
var requiredModule1 = new RequiredModule1();
var requiredModule2 = new RequiredModule2();
});
The define function takes 2 parameters: an array of dependencies and a callback function that is called once all the dependencies have been loaded. The exported dependencies are passed to the callback function as parameters in exactly the same order that they are defined and the code for the new module is implemented within the body of the callback function itself. This means that we can be 100% certain that all of the dependent modules have been loaded and are available to use within the new module at the time that the module code is executed.
In addition RequireJS also provides a require function which takes the same parameters as the define function but rather than defining a new module simply loads the dependencies and makes them available within the body of callback function.
How have Signagelive benefited from using RequireJS?
By using the modularisation capabilities of RequireJS we have been able to design our HTML5 client application using an object-oriented paradigm, which would otherwise have not been possible. Due to the size and complexity of the application itself, the importance of the role that RequireJS has played in simplifying both the initial implementation and the continued maintenance and improvement of the application cannot be understated.
Since the release of the SSSP web client, we have been able to rapidly extend the base application to build new HTML5 clients designed specifically for the LG WebOS Smart Signage platform and for the recent emergence of ChromeOS-powered Signage players. These clients all share the same common code base but implement different platform API’s, which is possible because we can switch in and out the modules that are responsible for handling these low-level interactions such as IO operations.
This hybrid approach to client development is critical to Signagelive’s strategy to support as many signage platforms as possible as we work toward our ultimate goal of having one common code base that is shared across all of our media clients. It is the reason we have been able to innovate so quickly to add client support for the LG WebOS and ChromeOS platforms and it is an enabler for us to continue to add support for new and innovative web-enabled devices and platforms in the future.
Javascript Module Loading Today
We chose to use RequireJS some 3 years ago and it continues to be a hugely important tool for us. Technology never stands still, however, and since then a number of competing technologies and standards have emerged, grown and innovated in the field of Javascript module loading.
There is an excellent blog post entitled Moving Past RequireJS in which the author Ben Mccormick provides deep insights into the current state of module loading in Javascript. I will not go into detail regarding Ben Mccormick’s article but instead encourage you to just go ahead and read it. I would especially recommend it if you are a web developer interested in understanding the best way to build modular applications today or if you are wondering if RequireJS is still the right technology for you.
On the subject of module loading today, I would also like to highlight one of the most important recent developments – the finalisation of the ECMAScript 6 standard which adds native, built-in support for modules to the Javascript standard. ES6 isn’t fully supported across all browsers yet but is already supported in some module loading frameworks such as Webpack. For those that are interested, there is a very well put together article by Axel Rauschmayer that looks at ES6 modules and how they are used in a high level of detail.
Summary
RequireJS is a proven, reliable and production-ready technology for Javascript module loading and the modularisation and dependency management features of RequireJS have been hugely important for the development and maintenance of Signagelive’s expanding catalogue of HTML5-based client solutions. It has saved us countless hours, days, perhaps even weeks of development time and effort and has been an enabler for extending the base client to support new and exciting web-enabled platforms.
Recent developments in Javascript module loading has seen the emergence of some very good alternative technologies such as Webpack and Browserify as well as the ES6 standard for native module support in Javascript. For web developers that are looking for the right module loading technology for their next development project I highly recommend taking the time to research the pros and cons of each with respect to the requirements of the application in question.
If you would like to try RequireJS their official website has an easy to follow Getting Started guide, which I recommend as the ideal starting place. Furthermore, if you have any questions about Signagelive, our supported clients or if you are interested in building your own client and don’t know where to start please get in touch.