Declaring SystemJS modules

4.18 Declaring SystemJS modules

SystemJS is another module definition syntax and module loader that we should avoid at design time. We can say that SystemJS are an improved version as it is able to load any kind of module format and supports transpiration. This means that we can use plugins to load TypeScript files directly from the runtime environment, compile them and process the resulting modules on the fly.

Getting Ready

All you need to implement in this recipe is an installation of TypeScript version 2.0 or higher, Gulp, SystemJS and the gulp-typescript plugin.

How to do it

If we have a ES6 module like the following one:

import { IArrays } from '../../interfaces';

class Arrays implements IArrays {
  // …
}

export default new Arrays();

We can compile the preceding into a SystemJS module using the module compilation flag as we can see in the following Gulp task:

gulp.task('build-es6-to-systemjs', function () {
    const tsProject = ts.createProject('tsconfig.json', {
        typescript: require('typescript'),
        module: 'system'
    });

    const input = './src/module_definitions/design_time/external/es6/*.ts';
    const output = './src/module_definitions/run_time/external/systemjs/';

    return gulp.src(input)
        .pipe(tsProject())
        .pipe(gulp.dest(output));
});

Note that the paths in the preceding Gulp tasks are the ones used in the companion source code. The ES6 modules are located un the the following module:

/src/module_definitions/design_time/external/es6/

The resulting UMD modules are located under the following folder:

/src/module_definitions/run_time/external/systemjs/

How it works

After compiling our ES6 module into JavaScript, the resulting SystemJS module will look as follows:

System.register([], function (exports_1, context_1) {
    "use strict";
    var __moduleName = context_1 && context_1.id;
    var Arrays;
    return {
        setters: [],
        execute: function () {
            Arrays = (function () {

                // ...

            }());
            exports_1("default", new Arrays());
        }
    };
}); 

The SystemJS modules are somehow similar to the AMD modules. SystemJS uses a function named register which is almost identical to the function named defined in AMD modules. Both functions take two arguments:

  • An array containing the paths of the dependencies of the module being defined
  • A callback function However, in SystemJS modules, the callback function doesn’t take the list of dependencies as its arguments. Another important difference is that instead of using the exports keyword, SystemJS modules return an object with two properties named execute and setters. Let’s take a look to the code generated for the ndrscr module to see the setters in action:
    System.register(["./arrays", "./collections", "./functions", "./objects", "./utility"], function (exports_1, context_1) {
      "use strict";
      var __moduleName = context_1 && context_1.id;
      var arrays_1, collections_1, functions_1, objects_1, utility_1, VERSION;
      return {
          setters: [
              function (arrays_1_1) {
                  arrays_1 = arrays_1_1;
              },
              function (collections_1_1) {
                  collections_1 = collections_1_1;
              },
              function (functions_1_1) {
                  functions_1 = functions_1_1;
              },
              function (objects_1_1) {
                  objects_1 = objects_1_1;
              },
              function (utility_1_1) {
                  utility_1 = utility_1_1;
              }
          ],
          execute: function () {
              exports_1("arrays", arrays_1.default);
              exports_1("collections", collections_1.default);
              exports_1("functions", functions_1.default);
              exports_1("objects", objects_1.default);
              exports_1("utility", utility_1.default);
              VERSION = '1.0.0';
              exports_1("VERSION", VERSION);
          }
      };
    });
    

    As we can see, in SystemJS the dependencies are declare in the context of a closure:

    var arrays_1, collections_1, functions_1, objects_1, utility_1;
    

    And __moduleName local variable provides a fully normalized name of the current module which can be useful for dynamically loading modules relative to the current module via:

    SystemJS.import('./local-module', __moduleName);
    

    And the callback returns an object that contains a reference to that context and a set of setter functions to allow its modification:

    return {
          setters: [
              function (arrays_1_1) {
                  arrays_1 = arrays_1_1;
              },
              function (collections_1_1) {
                  collections_1 = collections_1_1;
              },
              function (functions_1_1) {
                  functions_1 = functions_1_1;
              },
              function (objects_1_1) {
                  objects_1 = objects_1_1;
              },
              function (utility_1_1) {
                  utility_1 = utility_1_1;
              }
          ],
          execute: function () {
              exports_1("arrays", arrays_1.default);
              exports_1("collections", collections_1.default);
              exports_1("functions", functions_1.default);
              exports_1("objects", objects_1.default);
              exports_1("utility", utility_1.default);
              VERSION = '1.0.0';
              exports_1("VERSION", VERSION);
          }
      };
    

Source Code

Declaring SystemJS modules

See also

Please refer to the recipes about ES6 modules to learn about the declaration of external modules. Refer to chapter one to learn more about Gulp.

Running UMD modules

4.17 Running UMD modules

In the preceding recipes we learned how to declare and import CommonJS modules in this chapter we will learn how to run CommonJS modules.

Getting Ready

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

How to do it

Just like in the case of CommonJS modules, UMD modules can be used natively imported from a Node.js application. This is showcased in the companion source code (check out the file named umd.js under the directory named node):

const _ = require('../src/module_definitions/run_time/external/umd/ndrscr.js');

const result1 = _.arrays.first([5, 4, 3, 2, 1], 3);
console.log(result1);

const result2 = _.arrays.last([5, 4, 3, 2, 1], 3);
console.log(result2);

//...

The main advantage of UMD modules is that they can also be used in a web browser in combination with RequireJS. This means that the same module will work in both Node.js and RequireJS environments.

How it works

The companion source code showcases how we can run the UMD modules in a web browser using RequireJS just as we did previously in this chapter. The RequireJS configuration file included in the examples (check out the file named require_umd.config.js located under the /src/module_loaders/requirejs folder) looks as follows:

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

The configuration above is almost identical to the one that we used in the recipe about RequireJS. The only significant difference is that we have used a different base URL in order to point to the folder which contains the UMD modules. The companion source code also includes a file named requirejs_umd.html under the /browser/external folder/ this file showcases how to load the RequireJS configuration file:

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

Source Code

Running UMD modules

See also

Please refer to the recipes about ES6, AMD and CommonJS modules to learn about the declaration of external modules. Refer to chapter one to learn more about Gulp.

Importing UMD modules

4.16 Importing UMD modules

In the preceding recipe we learned how to declare UMD modules in this chapter we will learn how to import UMD modules.

Getting Ready

All you need to implement in this recipe is an installation of TypeScript 2.0 or higher, Gulp and the gulp-typescript module.

How to do it

Let’s take a look to the ES6 ndrscr module included in the companion source code:

import arrays from './arrays';
import collections from './collections';
import functions from './functions';
import objects from './objects';
import utility from './utility';

const VERSION = '1.0.0';
export { VERSION, arrays, collections, functions, objects, utility };

When compiled into an UMD module it looks as follows:

(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "./arrays", "./collections", "./functions", "./objects", "./utility"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var _arrays = require("./arrays");
    var _collections = require("./collections");
    var _functions = require("./functions");
    var _objects = require("./objects");
    var _utility = require("./utility");
    var VERSION = '1.0.0', arrays = _arrays.default, collections = _collections.default, functions = _functions.default, objects = _objects.default, utility = _utility.default;
    exports.VERSION = VERSION;
    exports.arrays = arrays;
    exports.collections = collections;
    exports.functions = functions;
    exports.objects = objects;
    exports.utility = utility;
});

How it works

As we can see in the preceding code snippet, UMD modules use a function named require to import other external modules and the exports object to declare the public parts of the module being defined. This may seem identical to CommonJS modules but we need to keep in mind that if we run an UMD module in Node.js or in a website with RequireJS the internal implementations of the require function and the exports object will not be identical.

See also

Please refer to the recipes about ES6, AMD and CommonJS modules to learn about the declaration of external modules. Refer to chapter one to learn more about Gulp.

Declaring UMD modules

4.15 Declaring UMD modules

UMD stands for Universal Module Definition. Just like in the case of AMD and CommonJS modules we should avoid using UMD at design time and leave its generation to the TypeScript compiler. UMD modules usually support bow AMD and CommonJS module loaders and bundles but some implementations (Like the Browserify stand alone mode) also support the usage of an UMD module as a global variable.

Getting Ready

All you need to implement in this recipe is an installation of TypeScript 2.0 or higher, Gulp and the gulp-typescript module.

How to do it

If we have an ES6 module like the following one:

import { IArrays } from '../../interfaces';

class Arrays implements IArrays {
  // …
}

export default new Arrays();

We can compile the preceding into an UMD module using the module compilation flag as we can see in the following Gulp task:

gulp.task('build-es6-to-commonjs', function () {
    const tsProject = ts.createProject('tsconfig.json', {
        typescript: require('typescript'),
        module: 'commonjs'
    });

    const input = './src/module_definitions/design_time/external/es6/*.ts';
    const output = './src/module_definitions/run_time/external/commonjs/';

    return gulp.src(input)
        .pipe(tsProject())
        .pipe(gulp.dest(output));
});

Note that the paths in the preceding Gulp tasks are the ones used in the companion source code. The ES6 modules are located un the the following module:

/src/module_definitions/design_time/external/es6/

The resulting UMD modules are located under the following folder:

/src/module_definitions/run_time/external/umd/

How it works

After compiling our ES6 module into JavaScript, the resulting AMD module will look as follows:

(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", {value: true});
    var Arrays = (function () {
        /// ...
    })();

    exports.default = new Arrays();
});

As we can see UMD modules are a mix between AMD a CommonJS modules. UMD module check if some objects are defined in the global scope to try to determine if the application is being used with a AMD module loader or a CommonJS loader and use the import and export methods accordingly.

Source Code

Declaring UMD modules

See also

Please refer to the recipes about ES6, AMD and CommonJS modules to learn about the declaration of external modules. Refer to chapter one to learn more about Gulp.

Running CommonJS modules with Browserify

4.14 Running CommonJS modules with Browserify

In the preceding recipes we learned how to declare and import CommonJS modules in this chapter we will learn how to run CommonJS modules.

Getting Ready

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

How to do it

The companion source code showcases (check out the file named common.js under the node directory) how CommonJS can be imported from a Node.js script without no further steps required:

const _ = require('../src/module_definitions/run_time/external/commonjs/ndrscr.js');

const result1 = _.arrays.first([5, 4, 3, 2, 1], 3);
console.log(result1);

const result2 = _.arrays.last([5, 4, 3, 2, 1], 3);
console.log(result2);

//…

The main problem of CommonJS modules is that they cannot be used natively in a web browser. The good news is that we can use a module bundler to solve this problem. In some of the previous recipes in this chapter we learned that we can use the RequireJS optimizer to create a bundle file which contains all the AMD modules in an application. In a similar manner, we can use a tool known as Browserify to generate a bundle file, which contains all the CommonJS files in an application. The bundle file can then be imported in a web browser. We can use the following Gulp task to transform CommonJS modules into a single bundle file using Browserify:

gulp.task('bundle-commonjs-with-browserify', function () {
    const mainJsFilePath = 'src/module_definitions/run_time/external/commonjs/ndrscr.js';
    const outputFolder = 'src/module_loaders/browserify/';
    const outputFileName = 'bundle.js';

    const bundler = browserify({
        entries: mainJsFilePath,
        standalone: 'ndrscr'
    });

    return bundler.bundle()
        .pipe(source(outputFileName))
        .pipe(buffer())
        .pipe(gulp.dest(outputFolder));
}); 

How it works

As we can see we have configured the applications root module: const mainJsFilePath = ‘src/module_definitions/run_time/external/commonjs/ndrscr.js’; The output folder:

const outputFolder = 'src/module_loaders/browserify/';

Finally, we configured the name of the bundle file:

const outputFileName = 'bundle.js';
We also configured used the standalone Browserify option to generate a module that can be used on its own without using a module loader:
const bundler = browserify({
        entries: mainJsFilePath,
        standalone: 'ndrscr'
    });

The stand alone option take a string, this string is used as the name of a variable that takes the public parts of the application as its value. After doing this we will be able to import the generated bundle.js file from a web browser without the need of a module loader:

<script src="../../src/module_loaders/browserify/bundle.js"></script>

The variable ndrscr is declared in the global scope when we import the module using a script tag so we can access it from other JavaScript files loaded after the bundle file was loaded:

<script>
  const _ = ndrscr;

    const result1 = _.arrays.first([5, 4, 3, 2, 1], 3);
    console.log(result1);

    const result2 = _.arrays.last([5, 4, 3, 2, 1], 3);
    console.log(result2);

  // ...

</script>

Source Code

Running CommonJS modules with Browserify

See also

Please refer to the recipes about ES6 to learn about the declaration of external modules. Refer to the recipes about AMD and UMD to learn more about these module definition syntaxes. You can also refer to the first chapter to learn more about Gulp.

Importing CommonJS modules

4.13 Importing CommonJS modules

In the preceding recipe we learned how to declare CommonJS modules in this recipe we will learn how to import CommonJS modules.

Getting Ready

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

How to do it

Let’s take a look to the ES6 ndrscr module included in the companion source code:

import arrays from './arrays';
import collections from './collections';
import functions from './functions';
import objects from './objects';
import utility from './utility';

const VERSION = '1.0.0';
export { VERSION, arrays, collections, functions, objects, utility };

When compiled into a CommonJS module it looks as follows:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var arrays_1 = require("./arrays");
var collections_1 = require("./collections");
var functions_1 = require("./functions");
var objects_1 = require("./objects");
var utility_1 = require("./utility");

var VERSION = "1.0.0";

exports.VERSION = VERSION;
exports.arrays = arrays_1.default;
exports.collections = collections_1.default;
exports.functions = functions_1.default;
exports.objects = objects_1.default;
exports.utility = utility_1.default;

How it works

As we can see in the preceding code snippet, CommonJS modules use a function named require to import other external modules and the exports object to declare the public parts of the module being defined. One of the main things that we should notice is that (as opposed to AMD modules) there are no callbacks here because CommonJS modules are not loaded asynchronously.

See also

Please refer to the recipes about ES6 to learn about the declaration of external modules. Refer to the recipes about AMD and UMD to learn more about these module definition syntaxes. You can also refer to the first chapter to learn more about Gulp.

Declaring CommonJS modules

4.12 Declaring CommonJS modules

CommonJS modules are in many ways very similar to AMD modules. When working with TypeScript we should avoid using CommonJS at design time. We should work with ES6 modules and leave the generation of CommonJS modules in the hands of the TypeScript compiler. One of the main advantages of CommonJS is that thy are natively supported by Node.js as opposed to AMD modules, which forces us to use a module loader like RequireJS in both web browsers and Node.js.

Getting Ready

All you need to implement in this recipe is an installation of TypeScript 2.0 or higher.

How to do it

If we have a ES6 module like the following one:

import { IArrays } from '../../interfaces';

class Arrays implements IArrays {
  // …
}

export default new Arrays();

We can compile it into a CommonJS module using the module compilation flag as we can see in the following Gulp task:

gulp.task('build-es6-to-commonjs', function () {
    const tsProject = ts.createProject('tsconfig.json', {
        typescript: require('typescript'),
        module: 'commonjs'
    });

    const input = './src/module_definitions/design_time/external/es6/*.ts';
    const output = './src/module_definitions/run_time/external/commonjs/';

    return gulp.src(input)
        .pipe(tsProject())
        .pipe(gulp.dest(output));
});

Note that the paths in the preceding Gulp tasks are the ones used in the companion source code. The ES6 modules are located un the the following module:

/src/module_definitions/design_time/external/es6/

The resulting CommonJS modules are located under the following folder:

/src/module_definitions/run_time/external/commonjs/

How it works

After compiling our ES6 module into JavaScript, the resulting AMD module will look as follows:

"use strict";
var Arrays = (function () {
    // ...
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = new Arrays();

CommonJS modules use an object named exports to declare the public parts of the module being defined. The preceding CommonJS module exports an object that has a property named default which takes the arrays object as its value. The TypeScript compiler adds an additional line:

Object.defineProperty(exports, "__esModule", { value: true });

As we learned in the recipes about AMD modules, this line is used to avoid compatibility issues with ES6 module loaders.

Source Code

Declaring CommonJS modules

See also

Please refer to the recipes about ES6 modules to learn about the declaration of external modules.

Running AMD modules with Require.js

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.

Importing AMD modules

4.10 Importing AMD modules

In the preceding recipe we learned that we can use the function named define to declare AMD modules in this recipe we are going to learn how we can use a function named require to import AMD modules.

Getting Ready

All you need to implement in this recipe is an installation of TypeScript 2.0 or higher.

How to do it

We can import a AMD module using a function named require:

require(['ndrscr', 'jquery'], function(_, $) {

  // Using Array module
  const result1 = _.arrays.first([5, 4, 3, 2, 1], 3);
  console.log(result1);

  const result2 = _.arrays.last([5, 4, 3, 2, 1], 3);
  console.log(result2);

  ///…
  
});

How it works

This function is defined by the AMD module loader and takes two arguments:

  • An array which contains the list of files that we wish to import.
  • A callback function which is invoked when all the dependencies have been loaded. As we can see in the preceding code snippet, we can change the name of the modules when they are passed to the callback function. For example, we changed ndrscr to _ and jquery to $. Remember that the define function is also able to import dependencies. Some developers wonder whether they should use require or define. In a real world application, the root module uses the require function and the rest of the modules use define function.

There’s more

It is also possible to conditionally import modules but you should try to avoid this as much as you can because it creates some problems with AMD module bundlers and is considered a bad practice:

require(['require', 'ndrscr'], function(require, _) {

  if(typeof $ === 'undefined') {
    const $ = require('jquery');
  }

  // ...
  
});

The best way to handle optional dependencies is via the AMD module loader configuration. We will learn more about it later in this chapter in the recipe about RequireJS.

See also

Please refer to the recipes about the declaration of AMD modules and RequireJS in this chapter to learn more about AMD modules.

Declaring AMD modules

4.9 Declaring AMD modules

In the preceding recipes we have learned about the TypeScript internal and external module definition syntaxes that we can use at design-time, we will now learn about the ones that we can use at run-time. Note that there are ways to use the AMD, CommonJS, UMD or SystemJS syntaxes at design time as well but it is considered a bad practice. If we use ES6 modules and design time, we can configure the TypeScript compiler to generate AMD, CommonJS, UMD or SystemJS modules. This is a great feature because we can abstract our code from the module system that will be used at runtime. However, if we use a module syntax AMD at design time and then we need CommonJS modules instead we will have to manually migrate from AMD to CommonJS.

Getting Ready

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

How to do it

If we have an ES6 module like the following one:

import { IArrays } from '../../interfaces';

class Arrays implements IArrays {
  // …
}

export default new Arrays();

We can compile it into an AMD module using the module compilation flag as we can see in the following Gulp task:

gulp.task('build-es6-to-amd', function () {
    const tsProject = ts.createProject('tsconfig.json', {
        typescript: require('typescript'),
        module: 'amd'
    });

    const input = './src/module_definitions/design_time/external/es6/*.ts';
    const output = './src/module_definitions/run_time/external/amd/';

    return gulp.src(input)
        .pipe(tsProject())
        .pipe(gulp.dest(output));
});

Note that the paths in the preceding Gulp tasks are the ones used in the companion source code. The ES6 modules are located in the following module:

/src/module_definitions/design_time/external/es6/

The resulting AMD modules are located under the following folder:

/src/module_definitions/run_time/external/amd/

How it works

After compiling our ES6 module into JavaScript, the resulting AMD module will look as follows:

define(["require", "exports"], function (require, exports) {
    "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
    var Arrays = (function () {
        // …
    })();
    exports.default = new Arrays();
});

As we can see a function named define in invoked. As we can guess by its name, the define function is used to declare a module. This function is part of the AMD module loader and takes two arguments arguments:

  • The first argument is an array of the dependencies of the module being declared.
  • AMD stands for Asynchronous Module Definition and that’s why the second argument is a callback. The AMD dependencies are loaded asynchronously and the callback in invoked when all the dependencies have been resolved.

In this case there are two dependencies:

  • The require function, which is part of the AMD module loader as well and can be used to require additional modules.
  • The exports object, which is used to declare the public parts of the module being defined. These two dependencies are always requested by the AMD modules generated by the TypeScript compiler but we can examine the ndrscr.js file to see how an AMD module with multiple dependencies and exports looks like:
    define(
      [
          "require", "exports", 
          "./arrays", "./collections", 
          "./functions", "./objects", 
          "./utility"
      ],
      function (
          require, exports, 
          _arrays, _collections, 
          _functions, _objects, 
          _utility
    ) {
       "use strict";
    
          var VERSION = "1.0.0", 
              arrays = _arrays.default, 
              collections = _collections.default, 
              functions = _functions.default, 
              objects = _objects.default, 
              utility = _utility.default;
            
          exports.VERSION = VERSION;
          exports.arrays = arrays;
          exports.collections = collections;
          exports.functions = functions;
          exports.objects = objects;
          exports.utility = utility;
    });
    
AMD modules can not be used at runtime without first loading an AMD module loader like RequireJS. The module loader will define the functions define and require, which are necessary to process with AMD modules at runtime. Also note that we don’t declare the file extensions because they are automatically appended by RequireJS. We will learn how to work with RequireJS towards the end of this chapter.

You may have noticed that the TypeScript compiler added the following line at the end of the module:

Object.defineProperty(exports, "__esModule", { value: true });

This line is necessary when working with some module loaders, in order to support the loading of AMD and CommonJS.

There’s more

AMD also allow us to import dependencies that will be used as global variables. These kind of dependencies are only required once in the entire application life cycle and they are not passed to the callback that is invoked when all the dependencies have been loaded. Usually, global dependencies are required in the root module but not necessarily used on it, which turns out to create a problem. Consider the following example:

import $ from 'jquery';
import Other from './other';

let x = new Other();

When compiled into JavaScript the compiler will not add a reference to jquery because it was not used in the file:

define(["require", "exports", "./other"], function(require, exports, Other) {
    var x = new Other();
});

The solution is to use an AMD dependency reference:

import 'jquery';
import Other from './other';

let x = new Other();
The preceding code snippet generates the following code:
define(["require", "exports", "./other", "jquery"], function(require, exports, Other) {
    var x = new Other();
});

Source Code

Declaring AMD modules

See also

Please refer to the ES6 modules recipes in this chapter to learn more about the declaration of external modules. Refer to the recipes about RequireJS in this chapter to learn how to configure and use RequireJS. You can also refer to chapter chapter 1: Accelerating your development with the best TypeScript tools to learn about Gulp.