4.11 Running AMD modules with Require.js

We have learned how the AMD module definition syntax works, now is the time to learn how we can use AMD modules. It is possible to use AMD modules in Node.js but it is wrong to do so. Node.js was designed to work natively with CommonJS modules and we should take advantage of that. On the other hand, web browsers lack native support for modules and AMD has been a powerful tool to overcome this missing feature. To load AMD modules in a web browser we need to import a AMD module loader. The most popular one is RequireJS. RequireJS declares the define and require functions and includes an optimizer that can be used to bundle all our modules into one single optimized file.

Getting Ready

All you need to implement in this recipe is an installation of TypeScript 2.0 or higher, Gulp and the RequireJS plugin.

How to do it

To use RequireJS we need to import three JavaScript files:

  • The RequireJS library
  • The RequireJS configuration
  • The application’s root module

So you should have something like the following in your HTML page:

<script src="../../node_modules/requirejs/require.js"></script>
<script src="../../src/module_loaders/requirejs/require.config.js"></script>
<script src="../../src/module_loaders/requirejs/app.js"></script>

The following code snippet showcases a basic require configuration file:

requirejs.config({
    baseUrl: '../../src/module_definitions/run_time/external/amd',
    waitSeconds: 15,
    paths: {
      "jquery" : "../../../../../node_modules/jquery/dist/jquery.min"
    }
});

How it works

The applications root module in the companion source code looks as follows:

require(['ndrscr', 'jquery'], function(_) {
// ...
}

The root module uses the require function to load two dependencies (ndrscr and jQuery). We didn’t have to use the full path of the ndrscr file because we configured the base URL:

baseUrl: '../../src/module_definitions/run_time/external/amd'

In a similar way, we didn’t use the the full path of jQuery because we create an alias for it using the paths configuration field:

  paths: {
      "jquery" : "../../../../../node_modules/jquery/dist/jquery.min"
  }

The RequireJS configuration file is the best place to manage optional dependencies. For example, imagine that we want to load jQuery only if it is not already declared:

require.config({ /* … */});

if (typeof jQuery === 'function') {
  define('jquery', function() { return jQuery; });
}

require([/*...*/], function(/*...*/) {
  // ...
});

There are many options options available but unfortunately, it is impossible to cover all of theme in this book.

Please refer to http://requirejs.org/docs/api.html#config to learn more about the available RequireJS configuration options.

There’s more

The companion source code includes two versions of the same RequireJS application: The first one loads the modules as needed on the fly. The second one uses a Gulp task and the RequireJS optimizer to create a bundle, which contains all the modules in the application. The Gulp task looks as follows:

const gulp = require('gulp'),
    tslint = require('gulp-tslint'),
    source = require('vinyl-source-stream'),
    buffer = require('vinyl-buffer'),
    ts = require('gulp-typescript'),
    webserver = require('gulp-webserver'),
    rjs = require('gulp-requirejs'),
    browserify = require('browserify'),
    webpack = require('gulp-webpack');

gulp.task('bundle-amd-with-requirejs', function () {
    rjs({
        baseUrl: './src/module_definitions/run_time/external/amd',
        waitSeconds: 15,
        out: 'bundle.js',
        include: ['../../../../module_loaders/requirejs/app.js'],
        paths: {
            'jquery': '../../../../../node_modules/jquery/dist/jquery.min'
        }
    }).pipe(gulp.dest('./src/module_loaders/requirejs/'));
});

The preceding Gulp task uses the RequireJS configuration as well but the paths are relative to the gulpfile.js and we have used an additional configuration file named out to configure the name of the generated bundle file. After generating a bundle, we can remove the references to the configuration file and root module and replace them with our bundle file:

<script src="../../node_modules/requirejs/require.js"></script>
<script src="../../src/module_loaders/requirejs/bundle.js"></script>

Bundle files help us to reduce the number or requests and are optimized so the amount of data transferred is also smaller. For these reasons it is highly recommended to use bundled files in production environments.

Source Code

Running AMD modules with Require.js

See also

Please refer to the recipes about the declaration of AMD modules and RequireJS in this chapter to learn more about AMD modules. You can also refer to chapter one to learn about Gulp.


Shiv Kushwaha

Author/Programmer