Creatio development guide
PDF
This documentation is valid for Creatio version 7.16.0. We recommend using the newest version of Creatio documentation.

AMD concept. Module definition

Glossary Item Box

Introduction

Starting from version 7.0, the client part of the Creatio application has a modular structure: it is designed as a set of functional blocks, implemented in separate modules. While the application is running, the modules and their dependencies are loaded in accordance with the Asynchronous Module Definition (AMD) approach.

The AMD approach declares the mechanism for defining and asynchronous loading of modules and their dependencies, which allows you to load only the data needed to work with the system at the moment. The AMD concept is supported by various JavaScript frameworks. In Creatio, the RequireJS loader is used to work with modules.

Modules

A module is a code fragment encapsulated in a separate block that can be downloaded and executed independently.

In JavaScript, modules are created in accordance with the "Module” programming pattern. A classic implementation of this pattern is using anonymous functions that return specific values (object, function, etc.) associated with the module. The module value is exported to the global object. Example:

// Immediately-invoked functional expression (IIFE). Anonymous function,
// which initializes the "myGlobalModule" property of the global object with a function,
// that returns module value. Thus, the module actually loads, 
// which can later be accessed through the "myGlobalModule" global property.
(function () {
    // Access to a module on which the current module depends.
    // This module already should be loaded to the  
    // "SomeModuleDependency" global variable at the moment of access.
    // "this" context in this case is a global object.
    var moduleDependency = this.SomeModuleDependency;
    // The declaration in the property of the global function object that returns the module value.
       this.myGlobalModule = function () { return someModuleValue; };
}());

When interpreter finds a functional expression like this, it immediately resolves it. As a result, a function that will return the module value will be placed in the myGlobalModule property of the global object.

The main disadvantages of this approach are the complexity of declaration and use of the dependency modules for the modules of such type. In particular, the disadvantages are:

  1. All module dependencies must already be loaded at the moment of anonymous function execution.
  2. The dependency modules are loaded via the <script><script/> HTML element at the page header. Global variable names are then used to access the modules. At the same time, the developer must clearly understand and implement the order in which all dependency modules are loaded.
  3. As a result, the modules are loaded before the page is rendered, therefore the modules cannot access the page controls to implement custom logic.

This means that the modules cannot be loaded dynamically; no additional logic can be applied at page loading, etc. In large projects like Creatio, the complexity of managing a large number of modules with many dependencies that can overlap each other is a problem.

The “RequireJS” loader

RequireJS is an AMD-based module declaring and loading mechanism that helps avoid the disadvantages of working with large numbers of modules. Basic principles of the RequireJS loader operation:

  1. Modules are declared in a special define() function, which registers a factory function to instantiate a module. At the same time, it does not load the module immediately when function is called.
  2. The module dependencies are passed as a string array and not through the properties of the global object.
  3. The loader executes the loading of all dependency modules passed as arguments to define(). The modules are loaded asynchronously, and the loader determines their loading order arbitrarily.
  4. After the loader completes loading of all specified module dependencies, it will call the factory function that will return the module value. The downloaded dependency modules will be passed to the factory function as arguments.

Module declaration. The “define()” function

For the loader to work with an asynchronous module, this module must be declared in the source code by the define() function in the following way:

define(
        ModuleName,
        [dependencies],
        function (dependencies) {
        }
);

The parameters of the define() function are listed in Table 1.

Table 1. - The parameters of the define() function

Argument Value
ModuleName

Module name string. Optional parameter.

If the parameter is not specified, the loader will assign the module name, based on its location in the application script tree. However, to access the module from other parts of the application (including the cases when this module must be asynchronously loaded as a dependency of another module), the parameter must be specified.

dependencies

An array of module names that this module depends on. Optional parameter.

RequireJS loads all dependencies passed in the array. Note that the order of dependencies in the dependencies array enumeration must correspond to the order of parameters in the enumeration passed to the factory function. The factory function will be called only after all dependencies listed in the dependencies parameter have been loaded. The loading of dependency modules is asynchronous.

function(dependencies)

Anonymous factory function that instantiates the module. Required parameter.

The objects that are associated by the loader with the dependency modules listed in the dependencies argument are passed to the function as arguments. Access to the properties and methods of the dependency modules within the created module is carried out through these arguments. The order of modules in the dependencies enumeration must correspond to the order of the factory function arguments.

The factory function will be called only after all dependency modules of the current module (listed in the dependencies parameter) have been loaded.

The factory must return a value that the loader will associate as the exported value of created module. The return value can be:

  • An object, which is the module for the system. After this module is initially download by the client, it is saved in the browser cache. If the module declaration has been modified after it was downloaded to the client (for example, during the configuration logic implementation), then the cache needs to be cleared and the module must be loaded again. An example of module declaration that returns the declared module as an object is provided below.
  • The module constructor function. The context object in which the module will be created is passed as an argument to the constructor. Loading this module will result in creating of the module instance (instantiated module) on the client. Reloading of this module to the client with the require() function will create another instance of the module. These two instances of the same module will be treated by the system as two different independent modules. An example of declaring an instantiated module is the CardModule module from the NUI package.

An example of using the define() function to declare a SumModule, which adds two numbers.

// The "SumModule" module has no dependencies.
// So, an empty array is passed as the second argument, and
// parameters are not passed to the anonymous factory function.

define("SumModule", [], function () {
    // The body of the anonymous function contains internal functionality implementation of the module.
    var calculate = function (a, b) { return a + b; };
    // The value returned by the function is an object, which is the module for the system.
    return {
         // Object description. In this case, the module is an object with the "summ" property.
         // The value of this property is a function with two arguments, returning the sum of these arguments.      

  summ: calculate
    };
});

The factory function returns the object as the module value, which the module will be for the system.

© Creatio 2002-2020.

Did you find this information useful?

How can we improve it?