tiempo de ejecución cargar componentes o módulos en un módulo en angular2

Tengo una aplicación angular que se construye con TypeScript y se incluye junto con el paquete web. Nada inusual aquí. Lo que quiero hacer es permitir complementos en tiempo de ejecución, lo que significa que los componentes y / o módulos fuera del paquete también deberían poder registrarse en la aplicación. Hasta ahora he intentado incluir otro paquete de paquete web en index.html y usar una matriz implícita para insertar dicho módulo / componente en ese, y en mi módulo importarlos.

Ver las importaciones están utilizando una variable implícita. Esto funciona para los módulos dentro del paquete, pero los módulos en el otro paquete no funcionarán.

@NgModule({
  imports: window["app"].modulesImport,
  declarations: [
      DYNAMIC_DIRECTIVES,
      PropertyFilterPipe,
      PropertyDataTypeFilterPipe,
      LanguageFilterPipe,      
      PropertyNameBlackListPipe      
  ],
  exports: [
      DYNAMIC_DIRECTIVES,
      CommonModule,
      FormsModule,
      HttpModule
  ]
})
export class PartsModule {

    static forRoot()
    {
        return {
            ngModule: PartsModule,
            providers: [ ], // not used here, but if singleton needed
        };
    }
}

También intenté crear un módulo y un componente usando el código es5, como a continuación, y empujar lo mismo a mi matriz de módulos:

var HelloWorldComponent = function () {

};

HelloWorldComponent.annotations = [
    new ng.core.Component({
        selector: 'hello-world',
        template: '<h1>Hello World!</h1>',
    })
];

window["app"].componentsLazyImport.push(HelloWorldComponent);

Ambos enfoques dan como resultado el siguiente error:

ncaught Error: Unexpected value 'ExtensionsModule' imported by the module 'PartsModule'. Please add a @NgModule annotation.
    at syntaxError (http://localhost:3002/dist/app.bundle.js:43864:34) [<root>]
    at http://localhost:3002/dist/app.bundle.js:56319:44 [<root>]
    at Array.forEach (native) [<root>]
    at CompileMetadataResolver.getNgModuleMetadata (http://localhost:3002/dist/app.bundle.js:56302:49) [<root>]
    at CompileMetadataResolver.getNgModuleSummary (http://localhost:3002/dist/app.bundle.js:56244:52) [<root>]
    at http://localhost:3002/dist/app.bundle.js:56317:72 [<root>]
    at Array.forEach (native) [<root>]
    at CompileMetadataResolver.getNgModuleMetadata (http://localhost:3002/dist/app.bundle.js:56302:49) [<root>]
    at CompileMetadataResolver.getNgModuleSummary (http://localhost:3002/dist/app.bundle.js:56244:52) [<root>]
    at http://localhost:3002/dist/app.bundle.js:56317:72 [<root>]
    at Array.forEach (native) [<root>]
    at CompileMetadataResolver.getNgModuleMetadata (http://localhost:3002/dist/app.bundle.js:56302:49) [<root>]
    at JitCompiler._loadModules (http://localhost:3002/dist/app.bundle.js:67404:64) [<root>]
    at JitCompiler._compileModuleAndComponents (http://localhost:3002/dist/app.bundle.js:67363:52) [<root>]

Tenga en cuenta que si intento con un componente en lugar de un módulo, los coloco en declaraciones, lo que da como resultado el error correspondiente para los componentes que dicen que necesito agregar una anotación @ pipe / @ componente en su lugar.

Siento que esto debería ser factible, pero no sé lo que me estoy perdiendo. Estoy usando [email protected]

actualizar 11/05/2017

Así que decidí dar un paso atrás y comenzar desde cero. En lugar de usarpaquete web Decidí probar conSystemJS en cambio, como encontré un componente central en Angular. Esta vez lo hice funcionar usando el siguiente componente y servicio para insertar componentes:

typebuilder.ts

import { Component, ComponentFactory, NgModule, Input, Injectable, CompilerFactory } from '@angular/core';
import { JitCompiler } from '@angular/compiler';
import {platformBrowserDynamic} from "@angular/platform-browser-dynamic";

export interface IHaveDynamicData { 
    model: any;
}

@Injectable()
export class DynamicTypeBuilder {

    protected _compiler : any;
         // wee need Dynamic component builder
    constructor() {
        const compilerFactory : CompilerFactory = platformBrowserDynamic().injector.get(CompilerFactory);
        this._compiler = compilerFactory.createCompiler([]);
    }

  // this object is singleton - so we can use this as a cache
    private _cacheOfFactories: {[templateKey: string]: ComponentFactory<IHaveDynamicData>} = {};

    public createComponentFactoryFromType(type: any) : Promise<ComponentFactory<any>> {
        let module = this.createComponentModule(type);
            return new Promise((resolve) => {
            this._compiler
                .compileModuleAndAllComponentsAsync(module)
                .then((moduleWithFactories : any) =>
                {
                    let _ = window["_"];
                    let factory = _.find(moduleWithFactories.componentFactories, { componentType: type });
                    resolve(factory);
                });
        });
    }

    protected createComponentModule (componentType: any) {
        @NgModule({
        imports: [
        ],
        declarations: [
            componentType
        ],
        })
        class RuntimeComponentModule
        {
        }
        // a module for just this Type
        return RuntimeComponentModule;
    }
}

Dynamic.component.ts

import { Component, Input, ViewChild, ViewContainerRef, SimpleChanges, AfterViewInit, OnChanges, OnDestroy, ComponentFactory, ComponentRef } from "@angular/core";
import { DynamicTypeBuilder } from "../services/type.builder";

@Component({
    "template": '<h1>hello dynamic component <div #dynamicContentPlaceHolder></div></h1>',
    "selector": 'dynamic-component'
})
export class DynamicComponent implements AfterViewInit, OnChanges, OnDestroy {

    @Input() pathToComponentImport : string;

    @ViewChild('dynamicContentPlaceHolder', {read: ViewContainerRef}) 
    protected dynamicComponentTarget: ViewContainerRef;
    protected componentRef: ComponentRef<any>;

    constructor(private typeBuilder: DynamicTypeBuilder) 
    {

    }  

    protected refreshContent() : void {
        if (this.pathToComponentImport != null && this.pathToComponentImport.indexOf('#') != -1) {
          let [moduleName, exportName] = this.pathToComponentImport.split("#");
          window["System"].import(moduleName)
            .then((module: any) => module[exportName])
            .then((type: any) => {
                this.typeBuilder.createComponentFactoryFromType(type)
                .then((factory: ComponentFactory<any>) =>
                {
                    // Target will instantiate and inject component (we'll keep reference to it)
                    this.componentRef = this
                        .dynamicComponentTarget
                        .createComponent(factory);

                    // let's inject @Inputs to component instance
                    let component = this.componentRef.instance;

                    component.model = { text: 'hello world' };

                    //...
                });
            });
      }
    }

    ngOnDestroy(): void {
    }

    ngOnChanges(changes: SimpleChanges): void {
    }

    ngAfterViewInit(): void {
        this.refreshContent();
    }

}

Ahora puedo vincular a cualquier componente dado como este:

<dynamic-component pathToComponentImport="/app/views/components/component1/extremely.dynamic.component.js#ExtremelyDynamicComponent"></dynamic-component>

Configuración de mecanografía:

 {
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "allowJs": true,
    "experimentalDecorators": true,
    "lib": [ "es2015", "dom" ],
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  },
    "exclude": [
      "node_modules",
      "systemjs-angular-loader.js",
      "systemjs.config.extras.js",
      "systemjs.config.js"
  ]
}

Y encima de mi configuración de mecanografiado. Esto funciona, sin embargo, no estoy seguro de que estoy contento con el uso de SystemJS. Siento que esto también debería ser posible con webpack y no estoy seguro si es la forma en que TC compila los archivos que webpack no comprende ... Todavía recibo la excepción de decorador faltante si intento ejecutar este código en un paquete de paquete web .

Saludos cordiales Morten

Respuestas a la pregunta(1)

Su respuesta a la pregunta