Динамическая загрузка модулей или компонентов в Angular

Итак, что я пытаюсь сделать, так это загрузить модули или компоненты, которые неизвестны во время компиляции.

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

Итак, что я придумал, так это то, что команда просто регистрирует URL-адрес файла JavaScript, и наше приложение динамически импортирует этот файл JavaScript. Между прочим, я все еще нахожусь в своего рода PoC-фазе, и я не могу показать вам, как я решил эту проблему в реальном приложении, поэтому я создаю минимальное приложение, которое делает то же самое.

yenteo/angular-dynamic-imports

Итак, у меня есть основное приложение, которое является обычным приложением Angular 10. В этом приложении у меня есть NormalComponent и InternalAngularElementsComponent. NormalComponent используется в app.component.ts. InternalAngularElementsComponent регистрируется как настраиваемый элемент и добавляется в HTML-код AppComponent.

Теперь это все работает корректно. Если вы просто сделаете npm start в папке основного приложения, приложение Angular запустится по адресу http://localhost:4200, и вы сможете нажимать кнопки компонентов, и вы увидите, что значение на кнопке увеличивается на 1 каждый клик .

Есть второе приложение, которое называется external-application. Это простой проект TypeScript с Rollup.js. Я определяю компонент, аналогичный двум другим, и регистрирую его в модуле. Я использую Rollup.js, поэтому я получаю модуль CommonJS, который я могу динамически импортировать в свое основное приложение (внутри app.component). При запуске npm build внутри внешнего приложения он скомпилирует все в src/index.ts в dist/index.js и скопирует этот файл в assets/external/index.js в основном приложении.

В app.component.ts в AfterViewInit делаем динамический импорт этого файла и вызываем экспортируемую функцию activate импортированного модуля. Эта функция делает следующее:

  1. Он определяет модуль Angular и импортирует наш модуль, определенный выше, который объявляет наш компонент.
  2. Он загружает этот модуль с помощью platformBrowserDynamic().bootstrapModule(ExtensionModule)
  3. Он разрешает фабрику компонентов для компонента, который мы зарегистрировали.
  4. Он регистрирует компонент как Angular Element

Теперь, когда я использую этот Angular Element, компонент работает, но у меня все еще есть некоторые проблемы. Я бы предпочел иметь возможность передать существующий инжектор моего основного приложения, чтобы я мог использовать каждого определенного там провайдера. Теперь вы можете видеть, что я сделал некоторые вещи, чтобы внедрить DataService во внешний компонент. Это работает, но шаблон не обновляется правильно. Я предполагаю, что это потому, что я создаю новый контекст Angular с platformBrowserDynamic().bootstrapModule(...).

Я попытался использовать компилятор существующего контекста Angular следующим образом:

compiler.compileModuleAndAllComponentsAsync(ExtensionModule);

но это всегда приводит к ошибкам в ExtensionModule с «Невозможно прочитать объявления свойств» с нулевым значением.

Я пробовал SystemJsNgModuleLoader, но это кажется устаревшим, потому что компилятор говорит использовать оператор import вместо загрузчика, но при использовании оператора импорта будет использоваться веб-пакет, и для AFAIK потребуется, чтобы код присутствовал во время компиляции.

Есть ли у кого-нибудь опыт в этом или знания о том, как это сделать правильно?


person YentheO    schedule 14.09.2020    source источник
comment
Вы можете проверить эту статью: medium.com/bb-tutorials-and-thoughts/   -  person yazantahhan    schedule 14.09.2020
comment
спасибо за ваш ответ @yazantahhan в целом они делают то, что я хочу сделать, но они используют SystemJS для импорта, который я не могу заставить работать внутри самого Angular (статья делает это за пределами Angular AFAIK), и я не на самом деле не вижу, что они разделяют контекст или что-то в этом роде. Я смотрю на single-spa уже пару часов, но, похоже, он не делает то, что я хочу.   -  person YentheO    schedule 15.09.2020
comment
Для SystemJ вы можете проверить этот ответ. Что касается связи, у вас может быть глобальная тема, которую можно использовать между компонентами. Вы также можете использовать для этого queryParams. Вот еще одна хорошая статья, которую вы можете проверить: angulararchitects.io/aktuelles/   -  person yazantahhan    schedule 15.09.2020