В этой статье я покажу вам, как создать Angular UMD-плагин с поддержкой AOT (Ahead-of-Time) и автономным развертыванием. Когда я сказал об автономном развертывании, я имел в виду, что основное приложение не имеет прямой связи с библиотекой плагинов и имеет независимый собственный цикл выпуска. Я попытался найти некоторые решения, и все они используют компилятор angular в производстве, но я не хочу включать компилятор в производственный комплект.

Этот пример основан на стандартном способе сборки angular library, который angular cli поддерживает начиная с версии 6 и простой rollup команда для сборки пакета UMD. Весь исходный код вы можете найти там https://github.com/iwnow/angular-plugin-example 👀.

Сначала давайте начнем с создания основного приложения angular и библиотеки плагинов.

ng new angular-plugin-example
cd angular-plugin-example
ng generate library plugin

Теперь у нас есть основное приложение и плагин. Мы хотим загрузить плагин во время выполнения, но основное приложение не должно ничего знать о библиотеке плагинов, поэтому ленивый модуль - не наш путь.

Для этого мы должны создать пакет UMD, который экспортирует наш плагин с фабрикой модулей и фабрикой компонентов (AOT), поэтому давайте создадим нашу библиотеку.

ng build plugin

После сборки нас интересуют файлы в каталоге dist / plugin / esm2015 / lib /. По умолчанию у нас нет файлов .ngfactory.js, это означает, что у нас нет фабрик для наших компонентов. Для создания фабрик нам нужно отредактировать projects / plugin / tsconfig.lib.json и установить для skipTemplateCodegen значение false.

"angularCompilerOptions": {
  "annotateForClosureCompiler": true,
  "skipTemplateCodegen": false,
  "strictMetadataEmit": true,
  "fullTemplateTypeCheck": true,
  "strictInjectionParameters": true,
  "enableResourceInlining": true
}

Теперь, если мы запустим сборку, мы получим фабрики для нашего модуля и компонентов.

После сборки фабрик нам нужно объединить все файлы фабрик в один комплект UMD, для этого я буду использовать свертку с простой командой:

rollup dist/plugin/esm2015/lib/plugin.module.ngfactory.js \
  --file src/assets/plugin.module.umd.js \
  --format umd \
  --name 'app.plugin'

Эта команда объединяет все необходимые файлы в один файл и копирует его в папку с ресурсами для простой загрузки из основного приложения. Теперь у нас есть файл, содержащий нашу библиотеку плагинов с фабриками экспорта для модуля и компонентов angular.

Все, что нам нужно, это просто загрузить этот файл в наше основное приложение и создать NgModuleRef с помощью этой команды:

const pluginModuleRef = pluginModuleFactory.create(appInjector);

Итак, как мы получаем ссылку на фабрику подключаемых модулей? Для этого мы можем загрузить файл с помощью fetch API, например, следующим образом:

fetch('/assets/plugin.module.umd.js')
  .then(response => response.text())
  .then(source => { 
    //eval source and get plugin module factory from exports object
  });

В файле мы видим, что наша фабрика экспортируется как PluginModuleNgFactory:

Таким образом, весь код, создающий экземпляр компонента из плагина, может выглядеть так:

В приведенном выше коде вы увидите, как мы загружаем модуль UMD с помощью фабрики компонентов AOT angular и создаем компонент в viewContainerRef основного приложения. Демо доступно на github: https://github.com/iwnow/angular-plugin-example. Надеюсь, это поможет вам найти правильный путь! 👻