[angular] Angular 2, 4, 5, 6에서 플러그인 아키텍처 / 플러그인 시스템 / 플러그 가능 프레임 워크 구현

2018 년 5 월 24 일 업데이트 : 우리는 이제 원래 게시물에서 +3 버전의 Angular를 사용하고 있으며 최종적으로 실행 가능한 솔루션이 없습니다. Lars Meijdam (@LarsMeijdam)은 확실히 볼만한 가치가있는 흥미로운 접근법을 고안했습니다. 독점 문제로 인해 원래 샘플을 게시 한 GitHub 리포지토리를 일시적으로 제거해야했습니다. 그러나 사본을 원하면 직접 메시지를 보낼 수 있습니다. 자세한 내용은 아래 주석을 참조하십시오.

Angular 6의 최근 아키텍처 변경으로 인해 솔루션에 더 가깝습니다. 또한 Angular Elements ( https://angular.io/guide/elements )는 몇 가지 구성 요소 기능을 제공하지만 원래이 게시물에서 설명한 것과는 다릅니다.

놀라운 Angular 팀의 누군가 가이 문제를 겪게되면이 기능에도 관심이 많은 다른 사람들이있는 것처럼 보입니다. 백 로그를 고려할 가치가 있습니다.


나는의 플러그 (플러그인) 프레임 워크 구현하고 싶은 Angular 2, Angular 4, Angular 5, 또는 Angular 6응용 프로그램을.

(플러그 가능한 프레임 워크를 개발하기위한 특정 사용 사례는 소형 컨텐츠 관리 시스템을 개발해야한다는 것입니다. 여기에서 자세히 설명 할 필요는없는 여러 가지 이유로 Angular 2/4/5/6해당 시스템의 대부분의 요구에 거의 완벽하게 맞습니다.)

플러그 가능한 프레임 워크 (또는 플러그인 아키텍처) 란 특히 타사 개발자가 기본 응용 프로그램의 소스 코드에 직접 액세스하거나 지식없이 플러그 가능 구성 요소 사용하여 기본 응용 프로그램의 기능을 만들거나 확장 할 수있는 시스템을 의미 합니다. 또는 내부 작업 .

( ” 응용 프로그램의 소스 코드 나 내부 작업에 직접 액세스하거나 지식을 얻지 않고 “라는 문구 는 핵심 목표입니다.)

플러그 프레임 워크의 예는 같은 일반적인 콘텐츠 관리 시스템 포함 WordPress또는 Drupal.

Drupal과 같은 이상적인 상황은 이러한 플러그 가능 구성 요소 (또는 플러그인)를 폴더에 간단하게 배치하고 응용 프로그램이 자동으로 감지하거나 발견하게하고 마술처럼 “작동”하도록하는 것입니다. 앱이 실행되는 동안 핫 플러그 ​​가능한 방식으로 발생하는 것이 가장 좋습니다.

나는 현재 (답변 결정하기 위해 노력하고 여러분의 도움으로 다음과 같은 다섯 개 가지 질문을).

  1. 실용성 :Angular 2/4/5/6 애플리케이션을 위한 플러그인 프레임 워크는 실용적입니까? (지금까지는를 사용하여 진정한 플러그 가능한 프레임 워크를 만드는 실용적인 방법을 찾지 못했습니다 Angular2/4/5/6.)
  2. 예상되는 과제 :Angular 2/4/5/6 애플리케이션 의 플러그인 프레임 워크를 구현할 때 어떤 문제가 발생할 수 있습니까?
  3. 구현 전략 :Angular 2/4/5/6 애플리케이션 의 플러그인 프레임 워크를 구현하기 위해 어떤 특정 기술 또는 전략을 사용할 수 있습니까?
  4. 모범 사례 :Angular 2/4/5/6 애플리케이션 용 플러그인 시스템을 구현하기위한 모범 사례는 무엇입니까 ?
  5. 대체 기술 : 경우 플러그인 프레임 워크가 되지 에 실제 Angular 2/4/5/6응용 프로그램, 무엇을 상대적으로 동등한 기술 (예를 들어 React)이 적합 할 수있는 현대적인 반응성이 매우 높은 웹 응용 프로그램 ?

일반적으로 다음을 사용하는 Angular 2/4/5/6것이 매우 바람직합니다.

  • 당연히 엄청나게 빠릅니다.
  • (초기로드 후) 매우 적은 대역폭을 소비합니다.
  • 발자국이 비교적 작고 (후 AOTtree shaking) 발자국이 계속 줄어 듭니다.
  • 고도로 기능적이며 Angular 팀과 커뮤니티는 생태계의 빠른 성장을 계속하고 있습니다.
  • 이 같은 최고와 최신 웹 기술의 많은 잘 재생 TypeScriptObservables
  • 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/6현재 프로젝트 에 사용 하고 싶습니다. 내가 사용 할 수 있어요 경우 Angular 2/4/5/6, 나는 또한 사용하는 것 Angular-CLI아마와 Angular Universal(서버 측 렌더링.)

위의 질문에 대한 지금까지 나의 생각은 다음과 같습니다. 피드백과 깨달음을 검토하고 제공하십시오.

  • Angular 2/4/5/6앱은 패키지를 사용하지만 이는 애플리케이션 내에서 플러그인을 허용하는 것과 반드시 ​​같을 필요는 없습니다. 다른 시스템 (예 Drupal:)의 플러그인은 플러그인 폴더를 공통 모듈 디렉토리에 드롭하여 시스템에 의해 자동으로 “픽업”되는 본질적으로 추가 될 수 있습니다. 에서 Angular 2/4/5/6(플러그인과 같은) 패키지는 일반적으로를 통해 설치 npm하고에 추가 package.json한 다음에 수동으로 앱으로 가져옵니다 app.module. Drupal폴더를 삭제하고 시스템에서 패키지를 자동으로 감지하는 방법 보다 훨씬 더 복잡 합니다. 플러그인을 설치하는 것이 복잡할수록 사람들이 플러그인을 사용할 가능성이 줄어 듭니다. 방법이 있다면 훨씬 좋을 것입니다Angular 2/4/5/6플러그인을 자동으로 감지하고 설치합니다. 개발자가 아닌 개발자가 Angular 2/4/5/6응용 프로그램의 모든 아키텍처를 이해하지 않고도 응용 프로그램을 설치하고 선택한 플러그인 을 설치할 수있는 방법을 찾고 싶습니다 .

  • 일반적으로 플러그 가능한 아키텍처를 제공함으로써 얻을 수있는 이점 중 하나는 타사 개발자가 시스템 기능을 확장하는 것이 매우 쉽다는 것입니다. 분명히, 이러한 개발자들은 그들이 연결하고있는 응용 프로그램에 대한 코드의 모든 복잡한 부분에 익숙하지 않을 것입니다. 일단 플러그인이 개발되면 기술을 덜 사용하는 다른 사용자도 단순히 애플리케이션과 선택한 플러그인을 설치할 수 있습니다. 그러나 Angular 2/4/5/6비교적 복잡하고 학습 시간이 매우 길다. 더 복잡한 일에, 대부분의 생산 Angular 2/4/5/6응용 프로그램도 활용 Angular-CLI, Angular UniversalWebPack. 플러그인을 구현하는 사람은 아마도 강력한 작업 지식과 함께 이들 모두가 어떻게 결합되는지에 대한 최소한의 기본 지식을 가지고 있어야 할 것입니다.TypeScript에 대한 합리적인 친숙 함 NodeJS. 지식 요구 사항이 너무 높아서 타사가 플러그인을 개발하기를 원하지 않습니까?

  • 대부분의 플러그인에는 일부 서버 측 구성 요소 (예 : 플러그인 관련 데이터 저장 / 검색)와 일부 클라이언트 측 출력이있을 수 있습니다. Angular 2/4/5특히 개발자는 런타임에 자체 템플릿을 주입하지 않아야합니다. 이는 심각한 보안 위험을 초래할 수 있습니다. 플러그인이 수용 할 수있는 많은 유형의 출력을 처리하려면 (예 : 그래프 표시) 사용자가 응답 스트림에 주입 된 콘텐츠를 다른 형식으로 만들 수 있도록 허용하는 것이 필요할 수 있습니다. 필자 Angular 2/4/5/6의 보안 메커니즘 을 비판적으로 파쇄하지 않고 어떻게 이러한 요구를 수용 할 수 있을지 궁금하다 .

  • 대부분의 프로덕션 Angular 2/4/5/6응용 프로그램은 Ahead of Time( AOT) 컴파일을 사용하여 사전 컴파일됩니다. (아마도 모두가 있어야합니다.) 플러그인이 사전 컴파일 된 응용 프로그램에 추가되거나 통합 될 수 있는지 확실하지 않습니다. 가장 좋은 시나리오는 기본 애플리케이션과 별도로 플러그인을 컴파일하는 것입니다. 그러나이 작업을 수행하는 방법을 잘 모르겠습니다. 폴백은 포함 된 플러그인을 사용하여 전체 애플리케이션을 다시 컴파일하는 것일 수 있지만 선택한 플러그인과 함께 애플리케이션을 자신의 서버에 설치하려는 관리 사용자에게는 약간 복잡합니다.

  • 에서 Angular 2/4/5/6응용 프로그램, 특히 미리 컴파일 된 하나, 잘못된의 한 조각 또는 충돌 코드 전체 응용 프로그램을 중단 할 수 있습니다. Angular 2/4/5/6응용 프로그램이 항상 디버그하기 가장 쉬운 것은 아닙니다. 잘못 작동하는 플러그인을 적용하면 매우 불쾌한 경험이 발생할 수 있습니다. 현재 동작하지 않는 플러그인을 정상적으로 처리하는 메커니즘을 알지 못합니다.



답변

도움이 될만한 솔루션으로 github에 리포지토리를 만들었습니다. UMD 번들 라이브러리를 느리게로드하는 Angular 6 라이브러리와 1 개의 기본 애플리케이션을 사용합니다. https://github.com/lmeijdam/angular-umd-dynamic-example

제안이 있으시면 언제든지 추가하십시오!


답변

Github 데모 앵귤러 플러그인 아키텍처

아이비는 무언가를 바꿀 수 있지만 당분간 Angular CLI Custom Builder를 사용하고 다음 요구 사항을 충족시키는 솔루션을 사용합니다.

  • AOT
  • 중복 코드를 피하십시오 (@ angular / core {common, forms, router}, rxjs, tslib와 같은 패키지)
  • 모든 플러그인에서 공유 라이브러리를 사용하지만 각 플러그인의 해당 공유 라이브러리에서 생성 된 팩토리를 출하하지 말고 라이브러리 코드 및 팩토리를 재사용하십시오.
  • Angular CLI가 제공하는 것과 동일한 수준의 최적화
  • 외부 모듈을 가져 오려면 번들 파일 경로 만 알아야합니다.
  • 코드는 모듈을 인식하고 플러그인을 페이지에 배치해야합니다.
  • 서버 측 렌더링 지원
  • 필요할 때만 모듈로드

사용법은 다음과 같이 간단합니다.

ng build --project plugins --prod --modulePath=./plugin1/plugin1.module#Plugin1Module
         --pluginName=plugin1 --sharedLibs=shared --outputPath=./src/assets/plugins

내 기사에서 이에 대한 자세한 내용 :


답변

방금 책 ” 앵귤러로 개발하기 “에 대한 새로운 장을 출판했습니다 Angular 2+의 플러그인 주제를 다루는 외부 플러그인을 구축하려는 사람들에게 큰 관심을 가져야합니다.

키 포인트:

  • 플러그인
  • 문자열 이름을 기반으로 구성 요소 작성
  • 외부 소스에서 구성로드
  • 동적으로 변화하는 응용 프로그램 경로
  • 외부 플러그인
  • 플러그인 라이브러리 생성
  • 애플리케이션에 플러그인로드
  • 플러그인 콘텐츠가 포함 된 동적 경로

이 책은 무료로 제공되며 “원하는 금액을 지불”모델이 있습니다. 사본을 들고 도움이되기를 바랍니다.


답변

작업 플러그인 시스템 예제 응용 프로그램합니다 (github에의 REPO를 설립하기위한 헤이스에 감사합니다!) https://github.com/PacktPublishing/Mastering-Angular-2-Components/tree/master/angular-2-components-chapter-10을 기반으로 eBook 마스터 링 Angular 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;
    }
  }
}

최고 … 톰


답변

부트 스트랩 시간에로드를 해킹하고 다른 모듈을 컴파일하지만 순환 종속성 문제를 해결하지 못했습니다.

 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
},


답변

나는 직장에서 엔터프라이즈 응용 프로그램을위한 RAD 환경을 개발하기 위해 각도 2/4의 플러그인 시스템을 찾고있었습니다. 몇 가지 연구를 한 후 데이터베이스 저장 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();
                }

            });

        });

    }

외부 자바 스크립트 코드는 각도 구성 요소와 유사합니다.

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';

};

그리고 컴포넌트의 템플릿은 각도 템플릿과 같습니다.

<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와 유사한 프레임 워크를 갖습니다.