代码之家  ›  专栏  ›  技术社区  ›  bradd

加载动态组件时角度4 AOT编译错误:未加载运行时编译器

  •  1
  • bradd  · 技术社区  · 7 年前

    我的Angular应用程序必须处理加载动态组件的问题。有了准时制 ng serve or, ng build 编译,一切正常。即使使用AOT ng serve --prod or, ng build --prod ,我仍然可以成功进行构建。此外,应用程序中的所有延迟加载模块都按预期工作。但一旦我 initiate an event to load a dynamic component 从登录页,我得到以下错误:

    vendor.fbd3ddffb0a9e35bbf55.bundle.js:1 ERROR Error: Uncaught (in promise): 
    Error: Runtime compiler is not loaded
    Error: Runtime compiler is not loaded
    at Z (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at t.compileModuleAndAllComponentsAsync 
    (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at dynamic.module.3b05550d9afcedd58855.chunk.js:1
    at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
    at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
    at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
    at polyfills.a58272fc2ef255219061.bundle.js:1
    at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
    at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at Z (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at t.compileModuleAndAllComponentsAsync 
    (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at dynamic.module.3b05550d9afcedd58855.chunk.js:1
    at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
    at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
    at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
    at polyfills.a58272fc2ef255219061.bundle.js:1
    at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
    at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at c (polyfills.a58272fc2ef255219061.bundle.js:1)
    at polyfills.a58272fc2ef255219061.bundle.js:1
    at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
    at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
    at r.runTask (polyfills.a58272fc2ef255219061.bundle.js:1)
    at o (polyfills.a58272fc2ef255219061.bundle.js:1)
    at <anonymous>`
    

    我通过在动态组件中应用喷油器消除了上述错误,如下所示:

    export class DynamicComponent {
    private injector: Injector;
    private compiler: Compiler;
    constructor(injector: Injector) {
        this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS,
            injector);
        this.compiler = this.injector.get(Compiler);
    }
    }
    

    一旦上述错误消失,我现在得到以下错误:

    vendor.fbd3ddffb0a9e35bbf55.bundle.js:1 ERROR Error: Uncaught (in promise): 
    Error: No NgModule metadata found for 'l'.
    Error: No NgModule metadata found for 'l'.
    at t.FDXN.t.resolve (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at t.FDXN.t.getNgModuleMetadata (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at t.FDXN.t._loadModules (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at t.FDXN.t._compileModuleAndAllComponents (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at t.FDXN.t.compileModuleAndAllComponentsAsync (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at dynamic.module.c493eec4648091b2c9b3.chunk.js:1
    at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
    at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
    at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
    at t.FDXN.t.resolve (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at t.FDXN.t.getNgModuleMetadata (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at t.FDXN.t._loadModules (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at t.FDXN.t._compileModuleAndAllComponents (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at t.FDXN.t.compileModuleAndAllComponentsAsync (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
    at dynamic.module.c493eec4648091b2c9b3.chunk.js:1
    at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
    at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
    at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
    at c (polyfills.a58272fc2ef255219061.bundle.js:1)
    at polyfills.a58272fc2ef255219061.bundle.js:1
    at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
    at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
    at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
    at r.runTask (polyfills.a58272fc2ef255219061.bundle.js:1)
    at o (polyfills.a58272fc2ef255219061.bundle.js:1)
    at <anonymous>
    

    我在互联网上找到了很多与这个问题相关的帖子,包括栈内溢出,但没有一篇适合我。

    我的动态组件如下所示:

    import { Component, Input, Output, ViewContainerRef, Compiler, ComponentFactory, ComponentFactoryResolver, ModuleWithComponentFactories, ComponentRef, ReflectiveInjector, SystemJsNgModuleLoader, OnInit, OnDestroy, ViewChild, Injector } from '@angular/core';
    import { Http } from '@angular/http';
    import { Observable, Subscription } from 'rxjs/Rx';
    import { JitCompiler } from '@angular/compiler';
    import { COMPILER_PROVIDERS } from '@angular/compiler';
    import * as _ from 'lodash';
    import { Page } from './interfaces/page';
    import { PageService } from './services/page.service';
    import { ActivePageService } from './services/active-page.service';
    
    export class ModuleNode { modulePath: string; componentName: string; }
    @Component({
    selector: 'app-dynamic-viewer',
    host: { 'class': 'template-wrapper dynamicviewer' },
    templateUrl: './dynamic.component.html',
    styleUrls: ['./dynamic.component.less'],
    providers: [PageService, ActivePageService]
    })
    export class DynamicComponent implements OnInit, OnDestroy {
    module: ModuleNode;
    componentRef: ComponentRef<any>;
    @ViewChild('pageContainer', { read: ViewContainerRef }) public pageHost;
    public activePagesData: string[];
    public pageData: Page[];
    public currentPage: Page;
    private injector: Injector;
    private compiler: Compiler;
    
    constructor(
        injector: Injector,
        private activePageService: activePageService,
        private pageService: pageService,
        private viewContainerRef: ViewContainerRef,
        private componentFactoryResolver: ComponentFactoryResolver,
        private systemJsNgModuleLoader: SystemJsNgModuleLoader
    ) {
        this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS, 
    injector);
        this.compiler = this.injector.get(Compiler);
    }
    
    ngOnInit() {
        this.getActivePageData();
    }
    
    openWebApp(currentModule: any) {
        this.destoryComponent();
        this.systemJsNgModuleLoader.load(currentModule.modulePath)  
            .then((moduleFactory) => {
                this.compiler.compileModuleAndAllComponentsAsync<any>(moduleFactory.moduleType)
                    .then((factory: ModuleWithComponentFactories<any>) => {
                        return factory.componentFactories.find(x => x.componentType.name === currentModule.componentName);
                    })
                    .then(componentFactory => {
                        const moduleRef = moduleFactory.create(this.pageHost.parentInjector);
                        this.componentRef = this.pageHost.createComponent(componentFactory, 0, moduleRef.injector);
                    });
            });
    }
    
    destoryComponent() {
        if (this.componentRef) {
            this.componentRef.destroy();
        }
    }
    
    ngOnDestroy() {
        this.destoryComponent();
    }
    
    getPageData() {
        this.pageService.getPageData().subscribe(res => {
            for (const page of res) {
                page.active = (this.activePagesData.indexOf(page.name) !== -1)
            }
            this.pageData = res;
    
        });
    }
    
    
    getActivePageData() {
        this.activePageService.getActivePageData().subscribe(res => {
            this.activePagesData = res;
            this.getPageData();
        });
    }
    
    selectPage(page: Page) {
        if (page.active) {
            this.currentPage = page;
            if (this.componentRef) {
                this.componentRef.destroy();
            }
            this.module = new ModuleNode();
            this.module.modulePath = this.currentPage.modulePath;
            this.module.componentName = this.currentPage.componentName;
            this.openWebApp(this.module);
        }
    }
    }
    

    应用环境:

    @angular/cli: 1.3.0-beta.1
    node: 6.9.4
    os: win32 x64
    @angular version: 4.3.6
    

    1 回复  |  直到 7 年前
        1
  •  2
  •   Community CDub    4 年前

    我也经历过同样的问题。我就是这样做的。比如说, UserComponent needs to be loaded dynamically 使用登录页上的AOT编译。

    使用者单元输电系统

    @NgModule({
      ...
      entryComponents: [UserComponent]
    })
    export class UserModule {
      static entry = UserComponent
    }
    

    您的基本登录页可以是:

    动态组成部分htlm公司

    <div>
        <ng-template #pageContainer></ng-template>
    </div>    
    <div *ngFor="let page of pageData">
        <div (click)="selectPage(page)">
            <div>{{page.title}}</div>
        </div>
    </div>
    

    当您从登录页选择页面(即尝试动态加载组件)时,请提供相应模块的绝对路径。因此 currentPage.modulePath 对于用户页面,可能类似于 app/modules/pages/user/user.module#UserModule . 最后,您可以这样加载条目组件:

    openWebApp(path: string) {
            this.systemJsNgModuleLoader.load(path)
                .then((moduleFactory: NgModuleFactory<any>) => {
                    const entryComponent = (<any>moduleFactory.moduleType).entry;
                    const moduleRef = moduleFactory.create(this.injector);    
                    const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
                    this.componentRef = this.pageHost.createComponent(compFactory);
                });
        }
    

    因此,您的动态组件如下所示:

    动态组成部分输电系统

    import { Component, Input, Output,   NgModuleFactory, ViewContainerRef, Compiler, ComponentFactory, ComponentFactoryResolver, ModuleWithComponentFactories, ComponentRef, ReflectiveInjector, SystemJsNgModuleLoader, OnInit, OnDestroy, ViewChild, Injector } from '@angular/core';
    import { Http } from '@angular/http';
    import { Observable, Subscription } from 'rxjs/Rx';    
    import { COMPILER_PROVIDERS } from '@angular/compiler';
    import * as _ from 'lodash';    
    import { Page } from './interfaces/page';
    import { PageService } from './services/page.service';
    import { ActivePageService } from './services/active-page.service';
    
    @Component({
        selector: 'app-dynamic-viewer',
        host: { 'class': 'template-wrapper dynamicviewer' },
        templateUrl: './dynamic.component.html',
        styleUrls: ['./dynamic.component.less'],
        providers: [PageService, ActivePageService]
    })
    export class DynamicComponent implements OnInit, OnDestroy {
        componentRef: ComponentRef<any>;
        @ViewChild('pageContainer', { read: ViewContainerRef }) public pageHost;
        public activePagesData: string[];
        public pageData: Page[];
        public currentPage: Page;
        private injector: Injector;
        private compiler: Compiler;
    
        constructor(
            injector: Injector,
            private activePageService: ActivePageService,
            private pageService: PageService,
            private viewContainerRef: ViewContainerRef,
            private componentFactoryResolver: ComponentFactoryResolver,
            private systemJsNgModuleLoader: SystemJsNgModuleLoader
        ) {
            this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS, injector);
            this.compiler = this.injector.get(Compiler);
        }
    
        ngOnInit() {
            this.getActivePageData();
        }
    
        selectPage(page: Page) {
            if (page.active) {
                this.currentPage = page;
                if (this.componentRef) {
                    this.componentRef.destroy();
                }    
                this.openWebApp(this.currentPage.modulePath);
            }
        }
    
        openWebApp(path: string) {
            this.destoryComponent();
            this.systemJsNgModuleLoader.load(path)
                .then((moduleFactory: NgModuleFactory<any>) => {
                    const entryComponent = (<any>moduleFactory.moduleType).entry;
                    const moduleRef = moduleFactory.create(this.injector);    
                    const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
                    this.componentRef = this.pageHost.createComponent(compFactory);
                });
        }
    
        destoryComponent() {
            if (this.componentRef) {
                this.componentRef.destroy();
            }
        }
    
        ngOnDestroy() {
            this.destoryComponent();
        }
    
        getPageData() {
            this.pageService.getPageData().subscribe(res => {
                for (const page of res) {
                    page.active = (this.activePagesData.indexOf(page.name) !== -1)
                }    
                this.pageData = res;
            });
        }
    
    
        getActivePageData() {
            this.activePageService.getActivePageData().subscribe(res => {
                this.activePagesData = res;
                this.getPageData();
            });
        }
    }