Концепция AMD
Front-end часть приложения Creatio представляет собой набор блоков функциональности, каждый из которых реализован в отдельном модуле. Согласно концепции Asynchronous Module Definition (AMD), в процессе работы приложения выполняется асинхронная загрузка модулей и их зависимостей. Таким образом, концепция AMD позволяет подгружать только те данные, которые необходимы для работы в текущий момент. О концепции AMD читайте на Википедии.
Концепция AMD поддерживается различными JavaScript-фреймворками. В Creatio для работы с модулями используется загрузчик RequireJS. Подробнее читайте на официальном сайте RequireJS.
Модульная разработка в Creatio
Модуль — фрагмент кода, инкапсулированный в обособленный блок, который самостоятельно загружается и выполняется.
Создание модулей в специфике JavaScript декларируется паттерном программирования "Модуль". Подробнее читайте в статье JavaScript Module Pattern: In-Depth. Классическая реализация паттерна — использование анонимных функций, возвращающих определенное значение (объект, функцию и т. д.), которое ассоциируется с модулем. При этом значение модуля экспортируется в глобальный объект.
Интерпретатор, обнаруживая в коде такое функциональное выражение, сразу вычисляет его. В результате выполнения в свойство myGlobalModule глобального объекта помещается функция, которая возвращает значение модуля.
Особенности подхода:
- Cложность декларирования и использования модулей–зависимостей.
- В момент выполнения анонимной функции все зависимости модуля должны быть загружены.
- Загрузка модулей–зависимостей выполняется в заголовке страницы через HTML-элемент <script>. Обращение к модулям–зависимостям осуществляется через имена глобальных переменных. При этом разработчику необходимо реализовывать порядок загрузки модулей–зависимостей.
- Как следствие предыдущего пункта — модули загружаются до начала рендеринга страницы, поэтому в модулях невозможно обращаться к элементам управления страницы для реализации пользовательской логики.
Особенности использования подхода в Creatio:
- Отсутствие возможности динамической загрузки модулей.
- Применение дополнительной логики при загрузке модулей.
- Сложность управления большим количеством модулей со многими зависимостями, которые могут перекрывать друг друга.
Загрузчик RequireJS
Загрузчик RequireJS предоставляет механизм объявления и загрузки модулей, который базируется на концепции AMD, и позволяет учесть особенности, которые описаны выше.
Принципы работы механизма загрузчика RequireJS:
- Объявление модуля выполняется в функции define(), которая регистрирует функцию–фабрику для инстанцирования модуля, но при этом не загружает его в момент вызова. Подробнее о функции define() читайте на сайте GitHub.
- Зависимости модуля передаются как массив строковых значений, а не через свойства глобального объекта.
- Загрузчик выполняет загрузку модулей–зависимостей, которые переданы в качестве аргументов функции define(). Модули загружаются асинхронно. Порядок загрузки произвольный и определяется загрузчиком.
- После загрузки указанных зависимостей модуля вызывается функция–фабрика, которая возвращает значение модуля. При этом в нее в качестве аргументов передаются загруженные модули–зависимости.
Назначение функции define() — объявление асинхронного модуля в исходном коде. Загрузчик работает с этим модулем.
Параметры
Строка с именем модуля. Необязательный параметр.
Если не указать параметр, загрузчик самостоятельно присваивает модулю имя в зависимости от его расположения в дереве скриптов приложения. Имя необходимо для обращения к модулю из других частей приложения (в том числе, для асинхронной загрузки в качестве зависимости другого модуля).
Массив имен модулей, от которых зависит текущий модуль. Необязательный параметр.
Загрузчик RequireJS выполняет асинхронную загрузку модулей–зависимостей, которые переданы в качестве аргументов функции define(). Порядок зависимостей в массиве dependencies соответствует порядку перечисления параметров, которые передаются в фабричную функцию. Фабричная функция вызывается после загрузки зависимостей, которые перечислены в массиве dependencies.
Анонимная фабричная функция, которая инстанцирует модуль. Обязательный параметр.
Объекты, которые ассоциируются загрузчиком с модулями–зависимостями, передаются в качестве параметров функции. Зависимости перечисляются в массиве dependencies. Через аргументы массива выполняется доступ к свойствам и методам модулей–зависимостей внутри текущего модуля. Порядок зависимостей в массиве dependencies соответствует порядку перечисления параметров, которые передаются в фабричную функцию.
Фабричная функция возвращает значение, которое загрузчик ассоциирует как экспортируемое значение текущего модуля.
Виды возвращаемого значения фабричной функции:
- Объект, которым является модуль для приложения. Модуль сохраняется в кэше браузера после первичной загрузки на клиент. Если объявление модуля изменено после загрузки на клиент (например, в процессе реализации конфигурационной логики), то очистите кэш и заново загрузите модуль.
- Функция-конструктор модуля. В качестве аргумента в конструктор передается объект контекста, в котором создается модуль. Загрузка модуля приведет к созданию на клиенте экземпляра модуля (инстанцируемого модуля). Повторная загрузка модуля на клиент функцией require() приведет к созданию еще одного экземпляра модуля. Эти экземпляры одного и того же модуля приложение воспринимает, как самостоятельные модули. Примером объявления инстанцируемого модуля является модуль CardModule пакета NUI.