单例服务不适用于延迟加载的模块

Singleton services are not available to lazy loaded modules

我最近将我的单个 AppModule 拆分为多个模块,现在我正在尝试延迟加载一个模块并使其使用来自共享模块的单例服务。

我按照提到的步骤 in the docs (as well as in this tutorial) 创建了一个共享 CoreModule 来提供单例服务。但是,当其中一个共享模块的服务试图注入任何单例服务时,将抛出以下异常:

EXCEPTION: Uncaught (in promise): Error: No provider for HttpClientService!
Error: No provider for HttpClientService!
    at NoProviderError.BaseError [as constructor] (http://localhost:5000/lib/angular/@angular/core/bundles/core.umd.js:1105:38)

app.module.ts

@NgModule({
    imports: [
        BrowserModule,
        CoreModule.forRoot(),
        AppRoutingModule
    ]
})
export class AppModule { }

app-routing.module.ts

export const routes: Routes = [
    {
        path: "mailgroups",
        loadChildren: "app/mailgroup/mailgroup.module#MailGroupModule"  // <-- lazy loading the module
    }
];

@NgModule({
    imports: [ RouterModule.forRoot(routes) ],
    exports: [ RouterModule ],
})
export class AppRoutingModule { }

core.module.ts(共享模块)

export class CoreModule {
    constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
        if (parentModule) {
            throw new Error("CoreModule is already loaded. Import it in the AppModule only!");
        }
    }

    static forRoot(): ModuleWithProviders {
        return {
            ngModule: CoreModule,
            providers: [
                HttpClientService,  // <-- singleton service 1
                UserService         // <-- singleton service 2
            ]
        };
    }
}

mailgroup.module.ts(延迟加载模块)

@NgModule({
    imports: [
        MailGroupRoutingModule
    ]
})
export class MailGroupModule { }

有趣的是,当我将共享模块 CoreModule 导入延迟加载模块 MailGroupModule 时,我没有得到任何异常(尽管 throw new Error(...) 在构造函数),因为 parentModule 参数总是 null.

我是不是遗漏了什么明显的东西? (省略了我认为不必要的声明)

经过几个小时的编程 "at random",我的努力得到了回报。问题出在配置错误的 system.config.js 中。

将 SystemJS 配置与 the systemjs.config.web.js used in the docs 进行比较时,我注意到在我的文件中配置应用程序文件夹和引导应用程序的文件路径的方式存在细微差别。

✘ 之前(错误配置的 SystemJS)

System.config({
    paths: { ... },
    map: {
        app: '/app',                // <-- This line (incorrect)
        ...
    },
    packages: {
        app: {
            main: '/main.js'        // <-- And this line (incorrect)
            defaultExtension: 'js'
        }
    }
})

注意 app: '/app' 中的前导斜杠和 main: '/main.js' 中的相对路径。

✔ 之后(正确的 SystemJS 配置)
(更改为 app: 'app'main: './main.js'

System.config({
    paths: { ... },
    map: {
        app: 'app',                 // <-- This line (correct)
        ...
    },
    packages: {
        app: {
            main: './main.js'       // <-- And this line (correct)
            defaultExtension: 'js'
        }
    }
})

所以,这两个细微的修复让世界大不相同!

现在,同样,尝试将共享模块 CoreModule 导入除 AppModule 以外的任何其他地方时,也会如预期的那样引发异常。

根据最佳实践,CoreModule 是 AppModule 的扩展。它不应该是一个共享模块。它应该只被 AppModule 导入和使用 一个共享模块,应该叫做..... SharedModule