Внедрение архитектуры плагинов/систем плагинов/сменных фреймворков в Angular 2, Angular 4 или Angular 5

Я хотел бы реализовать плагиновую (плагиновую) структуру в приложении Angular 2, Angular 4 или Angular 5.

(Моим конкретным вариантом использования для разработки этой подключаемой структуры является то, что мне нужно разработать миниатюруную систему управления контентом. По ряду причин, которые не обязательно будут развиты здесь, Angular 2/4/5 является почти идеальным решением для большинства потребностей этого система.)

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

(Эта формулировка о "без прямого доступа к исходному коду приложения или его внутренней работе" или "знание" является основной задачей.)

Примеры подключаемых фреймворков включают общие системы управления контентом, такие как WordPress или Drupal.

Идеальная ситуация (как в случае с Drupal) заключается в простой установке этих подключаемых компонентов (или плагинов) в папку, приложение автоматически обнаруживает или обнаруживает их, и они просто магически "работают". " Если это произойдет в какой-то горячей подключаемой манере, то есть во время работы приложения, было бы оптимальным.

В настоящее время я пытаюсь определить ответы (с вашей помощью) на следующие пять вопросов.

  • Практичность: Является ли плагинов для приложения Angular 2/4/5 даже практичным? (До сих пор я не нашел практического способа создания действительно подключаемой структуры с помощью Angular2/4/5.)
  • Ожидаемые задачи: Какие проблемы могут возникнуть при реализации плагина для приложения Angular 2/4/5?
  • Стратегии реализации: Какие конкретные методы или стратегии могут быть использованы для реализации платформы плагинов для приложения Angular 2/4/5?
  • Рекомендации: Каковы наилучшие методы внедрения плагиновой системы для приложения Angular 2/4/5?
  • Альтернативные технологии: Если плагин не применим в приложении Angular 2/4/5, какие относительно эквивалентные технологии (например, React) могут быть подходящими для современного высокореактивного веб-приложения?

В общем случае использование Angular 2/4/5 очень желательно, потому что:

  • это, естественно, очень быстро - это невероятно.
  • он потребляет очень мало полосы пропускания (после начальной загрузки)
  • он имеет относительно небольшую площадь (после AOT и tree shaking) - и этот след продолжает сокращаться
  • он очень функциональен, а команда и сообщество Angular продолжают быстрый рост своей экосистемы.
  • он хорошо работает со многими из лучших и новейших веб-технологий, таких как TypeScript и Observables
  • Angular 5 теперь поддерживает сервис-работников (https://medium.com/@webmaxru/a-new-angular-service-worker-creating-automatic-progressive-web-apps-part-1-theory-37d7d7647cc7)
  • подкрепляется Google, он, вероятно, будет поддерживаться и улучшаться в будущем

Я бы очень хотел использовать Angular 2/4/5 для моего текущего проекта. Если я могу использовать Angular 2/4/5, я также буду использовать Angular-CLI и, возможно, Angular Universal (для рендеринга на стороне сервера).

Вот мои мысли до сих пор касаются вышеперечисленных вопросов. Пожалуйста, просмотрите и сообщите свои отзывы и просвещение.

  • Angular 2/4/5 приложения потребляют пакеты - но это не обязательно то же самое, что разрешать плагины внутри приложения. Плагин в других системах (например, Drupal) может быть добавлен путем добавления папки плагина в каталог общих модулей, где система автоматически "подбирается" системой. В Angular 2/4/5 пакет (в качестве плагина может быть) обычно устанавливается через npm, добавляется в package.json, а затем вручную импортируется в приложение - как в app.module. Это намного сложнее, чем метод Drupal для удаления папки и система автоматически определяет пакет. Чем сложнее установить плагин, тем менее вероятно, что люди будут использовать их. Было бы намного лучше, если бы был Angular 2/4/5 способ автоматического обнаружения и установки плагинов. Мне очень интересно найти метод, который позволяет не разработчикам устанавливать приложение Angular 2/4/5 и устанавливать любые выбранные плагины без необходимости понимать всю архитектуру приложения.

  • Как правило, одним из преимуществ предоставления подключаемой архитектуры является то, что сторонним разработчикам очень легко расширить функциональность системы. Очевидно, что эти разработчики не будут знакомы со всеми сложностями кода для приложения, в которое они подключаются. После разработки плагинов другие даже менее технические пользователи могут просто установить приложение и любые выбранные плагины. Однако Angular 2/4/5 относительно сложна и имеет очень длинную кривую обучения. Чтобы еще больше усложнить ситуацию, в большинстве производственных приложений Angular 2/4/5 также используются Angular-CLI, Angular Universal и WebPack. Кто-то, кто реализует плагин, вероятно, должен иметь хотя бы некоторые базовые знания о том, как все они сочетаются друг с другом - наряду с сильным рабочим знанием TypeScript и разумным знакомством с NodeJS. Являются ли требования к знаниям настолько экстремальными, что никакая третья сторона никогда не захочет разработать плагин?

  • В большинстве плагинов, вероятно, будет некоторый компонент на стороне сервера (например, для хранения/получения данных, связанных с плагинами), а также для вывода на клиентскую сторону. Angular 2/4/5 специально (и сильно) препятствует разработчикам внедрять собственные шаблоны во время выполнения, поскольку это создает серьезную угрозу безопасности. Чтобы обрабатывать много типов вывода, которые может быть подключен плагин (например, отображение графика), кажется, что разрешение пользователям создавать контент, который вводится в поток ответов, в одной форме, вероятно, необходимо. Интересно, как можно было бы удовлетворить эту потребность без образно измельчающих механизмов безопасности Angular 2/4/5.

  • Большинство производственных приложений Angular 2/4/5 предварительно скомпилированы с использованием Ahead of Time (AOT) компиляции. (Вероятно, все должно быть.) Я не уверен, что плагины могут быть добавлены в (или интегрированы) предварительно скомпилированные приложения. Лучший сценарий будет включать компиляцию плагинов отдельно от основного приложения. Однако я не уверен, как это сделать. Отказ может заключаться в повторной компиляции всего приложения с любыми включенными плагинами, но это немного усложняет административный пользователь, который просто хочет установить приложение (на своем собственном сервере) вместе с любыми выбранными плагинами.

  • В приложении Angular 2/4/5, особенно предварительно скомпилированном, один фрагмент ошибочного или противоречивого кода может разорвать все приложение. Angular 2/4/5 приложения не всегда легче отлаживать. Применение недобросовестных плагинов может привести к очень неприятным переживаниям. В настоящее время я не знаю о механизме для грамотной обработки плагинов с неправильным поведением.

UPDATE:

11/22/2017. Теперь, когда был выпущен Angular 5, я пересматриваю, какие новые функции могут лучше облегчить реализацию подключаемой инфраструктуры.

Ответ 1

Пример приложения с рабочей плагиновой системой (спасибо Gijs за создание github repo!) https://github.com/PacktPublishing/Mastering-Angular-2-Components/tree/master/angular-2-components-chapter-10 на основе eBook Освоение Angular 2 компонента

  • для расширения основных компонентов приложения
  • файловая система (для простого добавления каталогов/файлов плагинов без редактирования каких-либо основных конфигурационных файлов или необходимости перекомпилировать ваше приложение!)
  • Загрузка и динамическое использование плагинов
  • создание рудиментарного менеджера плагинов для активации/деактивации плагинов на лету

Cheers, Никлас

Ответ 2

То, что вы ищете, - это ленивая загрузка модуля. Вот пример этого: http://plnkr.co/edit/FDaiDvklexT68BTaNqvE?p=preview

import {Component} from '@angular/core';
import {Router} from '@angular/router';

@Component({
  selector: 'my-app',
  template: `
    <a [routerLink]="['/']">Home</a> | 
    <a [routerLink]="['/app/home']">App Home</a> |
    <a [routerLink]="['/app/lazy']">App Lazy</a>

    <hr>
    <button (click)="addRoutes()">Add Routes</button>

    <hr>
    <router-outlet></router-outlet>
  `
})
export class App {
  loaded: boolean = false;
  constructor(private router: Router) {}

  addRoutes() {
    let routerConfig = this.router.config;

    if (!this.loaded) {
      routerConfig[1].children.push({
        path: `lazy`,
        loadChildren: 'app/lazy.module#LazyModule'
      });

      this.router.resetConfig(routerConfig);
      this.loaded = true;
    }
  }
}

Лучший... Том

Ответ 3

Я сделал взлом для загрузки и скомпилировал другие модули во время начальной загрузки, но я не решил проблему циклических зависимостей

 const moduleFile: any = require(`./${app}/${app}.module`),
                    module = moduleFile[Object.keys(moduleFile)[0]];

 route.children.push({
     path: app,
     loadChildren: (): Promise<any> => module
 });
 promises.push(this.compiler.compileModuleAndAllComponentsAsync(module));

то в AppModule добавьте это:

{
        provide: APP_INITIALIZER,
        useFactory: AppsLoaderFactory,
        deps: [AppsLoader],
        multi: true
},

Ответ 4

Я искал плагинную систему в angular 2/4 тоже для разработки среды RAD для корпоративного приложения на работе. После некоторых исследований я решил реализовать коллекцию компонентов pseudo- Angular, хранящихся в базе данных (но может быть в файловой системе).

Компоненты, хранящиеся в базе данных базы данных, основаны на ng-dynamic и реализация основного компонента похожа на это:

declare var ctx: any;

@Component({
    selector: 'my-template',
    template: `
<div>
    <div *dynamicComponent="template; context: { ctx: ctx };"></div>
</div>
  `,
    providers: [EmitterService],

})

export class MyTemplateComponent implements OnMount, AfterViewInit, OnChanges {


    // name
    private _name: string;
    get name(): string {
        return this._name;
    }
    @Input()
    set name(name: string) {
        this._name = name;        
        this.initTemplate();
    }

    template: string;
    ctx: any = null;

    private initTemplate() {

        this.templateSvc.getTemplate(this.name).subscribe(res => {
            // Load external JS with ctx implementation
            let promise1 = injectScript(res.pathJs);
            // Load external CCS
            let promise2 = injectScript(res.pathCss);

            Promise.all([promise1, promise2]).then(() => {

                // assign external component code
                this.ctx = ctx; //

                // sets the template
                this.template = res.template;

                this.injectServices();

                if (this.ctx && this.ctx.onInit) {
                    this.ctx.onInit();
                }

            });

        });

    }

Внешний код javascript похож на компоненты angular:

var ctx = {

// injected    
_httpService: {},
_emitterService: null,

// properies
model: {
    "title": "hello world!",
},


// events
onInit() {
    console.log('onInit');
},

onDestroy() {
    console.log('onDestroy');
},

onChanges(changes) {
    console.log('changes', changes);
},

customFunction1() {
    console.log('customFunction1');
},

childTemplateName: string = 'other-component'; 

};

И шаблоны компонентов похожи на angular templates:

<a (click)="customFunction1()">{{ ctx.model.title }}</a>
<input [(ngModel)]="ctx.model.title" type="text" />

И также может быть вложен:

<a (click)="customFunction1()">{{ ctx.model.title }}</a>
<my-template [name]="childTemplateName"></my-template>

Хотя это не идеально, разработчики пользовательских компонентов имеют аналогичную структуру, чем в angular2/4.

Ответ 5

Это можно сделать "вручную". Поскольку webpack ничего не знает о модуле внешних модулей (plug-ins), он не может включать их в пакеты (ы). Так что я сделал, это посмотреть на код, сгенерированный webpack, и я нашел эти пироги кода в main.bundle.js:

var map = {
"./dashboard/dashboard.module": ["../../../../../src/app/dashboard/dashboard.module.ts","dashboard.module"]}; 

Давайте рассмотрим, что содержит этот массив:

  • "./dashboard/dashboard.module" - это URL-адрес маршрутизации модуля, который мы хотим использовать для ленивой загрузки: {path: 'dashboard', loadChildren: './dashboard/dashboard.module # DashboardModule '}
  • "../../../../../src/app/dashboard/dashboard.module.ts" - это точка входа (contructor) берет из
  • "dashboard.module" - фактическое имя файла без chunk.js(например: dashboard.module.chunk.js)

Итак, теоретически, если вы добавите запись в свойство карты, настройте свою маршрутизацию и следуйте шаблону, вы можете иметь подключаемую систему. Теперь задача состоит в том, как добавлять или удалять записи из этого свойства карты. Очевидно, что это невозможно сделать из кода angular, это должно быть сделано для внешнего инструмента.

Ответ 6

Я попытался реализовать архитектуру плагина с использованием ABP, Angular и ASP.NET Core: https://github.com/chanjunweimy/abp_plugin_with_ui

В принципе, я разработал плагины Angular, используя другое приложение Angular, затем я динамически добавляю их вместе.

Дополнительная информация о том, как я ее достигаю:

У меня есть приложение 2 angular -cli, 1 является основным приложением Angular cli, а другое - плагином Angular cli. Проблема, с которой мы сталкиваемся в подходе архитектуры angular -cli, заключается в том, как мы их интегрируем.

Прямо сейчас, что я сделал, я запускал ng-build на обоих приложениях и помещал их в папку "wwwroot", которая затем размещалась на сервере ASP.NET core 2.0. Простейший репозиторий, который показывает эту идею, - это Angular Несколько приложений: https://github.com/chanjunweimy/angular-multiple-app

abp_plugin_with_ui - это репозиторий, который работает над созданием плагина, содержащего как бэкэнд, так и Angular cli. Для бэкэнд я использовал фреймворк aspnetboilerplate, интерфейс которого разработан с использованием нескольких приложений angular -cli.

Чтобы основное приложение было интегрировано с приложением plugin, мы должны запустить "ng-build" на обоих приложениях (обратите внимание, что мы также должны изменить на href приложения плагина), затем мы перемещаем построенный содержимое приложения plugin Angular cli, в основную папку "wwwroot" приложения. После достижения всего этого, мы можем запустить "прогон dotnet" для обслуживания веб-приложения ASP.NET Core 2.0 для размещения статических файлов, созданных "ng build".

Надеюсь, это поможет. Любые комментарии приветствуются! ^^