Dojo FAQ: How can I conditionally load AMD modules?

By on February 25, 2014 7:31 pm

DojoFAQ

AMD: Beyond the Basics

If you’ve been using Dojo 1.7+, you know the basic method of loading modules with AMD:

require([
	'dojo/dom',
	'dojo/query'
], function (dom, query) {
	// dojo/dom and dojo/query modules are 
	// loaded and available for use
});

There are times when you may not know the specific modules you want to load during development. There are a few approaches that can be used to determine which modules to load dynamically at run-time.

Conditional Loading with dojo/has

The dojo/has module is Dojo’s feature-detection API. It provides a simple, consistent, and easily extensible approach for evaluating existing feature tests, and for creating your own custom feature tests. dojo/has also implements the AMD loader plugin API, which allows you to use it to conditionally load modules. The syntax is as follows:

dojo/has!<testName>?<moduleIdIfTrue>:<moduleIdIfFalse>

For example, your application may have different modules that provide similar functionality depending on whether the browser supports a touch interface. You can load one or the other:

require([
	'dojo/has!touch?myPackage/touch:myPackage/mouse'
], function (myWidget) {
	// myWidget will be the appropriate module depending
	// on the presence of touch support at run-time
});

Conditional Loading with Nested require

Using the dojo/has module is simple and convenient, but sometimes you may want to choose from numerous modules, or you may even want to be able to determine the module ID more dynamically. AMD’s require function can be used within a require callback, so you can create code that determines a module ID at run-time and then call require to load the module. Module IDs are, after all, simply strings! The following example loads a different module depending on the type of device: desktop, tablet, or mobile phone.

require([
	'dojo/has'
], function (has) {
	var ui;
	var moduleId = 'myApp/ui/';

	// Assume 'has' tests for mobile and tablet
	// have been defined
	if (has('mobile')) {
		moduleId += 'Mobile';
	}
	else if (has('tablet')) {
		moduleId += 'Tablet';
	}
	else {
		moduleId += 'Desktop';
	}

	require([moduleId], function (UiModule) {
		ui = new UiModule();
		ui.placeAt(document.body);
		ui.startup();
	});
});

This example has been kept simple to keep the focus on demonstrating nested require and dynamic module IDs, but it is actually simple enough that nested dojo/has loader plugins could handle it:

require([
	'dojo/has!mobile?myApp/ui/Mobile:dojo/has!tablet?myApp/ui/Tablet:myApp/ui/Desktop'
], function (UiModule) {
	var ui = new UiModule();
	ui.placeAt(document.body);
	ui.startup();
});

Further information

As you can see AMD not only allows you to create modular code, but also enables a flexible, dynamic application structure. In our Dojo workshops, we cover these issues in depth, as well as device-specific builds for minimizing HTTP traffic and delivering optimal performance, implementing your own AMD loader plugin, and more!