【问题标题】:Share lazy-loaded (not in App.module) service (DI context) between other multiple lazy loaded modules?在其他多个延迟加载模块之间共享延迟加载(不在 App.module 中)服务(DI 上下文)?
【发布时间】:2020-01-03 02:42:49
【问题描述】:

让我们来看看场景:

App.module
   |__Lazy1.module
   |    \__LazyService1.module
   |__Lazy2.module
   |    \__LazyService1.module
   \__(many more)

目标是让LazyService1.moduleLazy1/2.module 提供单例实例,但仅在获取 Lazy1/Lazy2 时才需要加载。

Angular 只创建和解析根 DI 上下文一次。任何后续上下文(对于惰性模块)都是子上下文。我的问题是我不想在App.module 中提供服务(LazyService1.module)(这是一个大模块,并且只被 2 个延迟加载的模块使用),所以逻辑上我的LazyService1.module 不会在根 DI 中解决上下文。

我需要以某种方式在 2 个延迟加载的模块之间共享 DI 上下文,而不必使其成为根依赖项(在 App.module 中)。

有没有办法定义共享 DI?一个模块可以访问其他模块的 DI 上下文吗?

是否可以在根目录下提供延迟加载服务供其他延迟加载模块使用,而不需要从根目录App.module 提供?

至于堆栈 - 我不认为我可以提供堆栈,因为我不知道它的外观。我可以实现一个热切在根目录下提供服务,但这不是这里的问题。

编辑 2:

App.module:

@NgModule({
    declarations: [
        AppComponent,
    ],
    imports: [
        // Used by all:
        BrowserModule,
        BrowserAnimationsModule,
        CommonModule,
        HttpClientModule,
        // App router:
        AppRoutingModule
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

延迟加载路由模块:

const routes: Routes = [
    { path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) },
    { path: 'main', loadChildren: () => import('./main/main.module').then(m => m.MainModule) },
    ... many others, lazy or not
];

服务模块:

@NgModule({
    providers: [
        AuthenticationService
    ],
    declarations: [...],
    exports: [...],
    imports: [
        CommonModule,
    ]
})
export class SecurityModule { }

服务:

@Injectable()
export class AuthenticationService { ... }

然后我们有两个懒惰的:adminmain

如果我要像这样导入SecurityModule

@NgModule({
    imports: [
        SecurityModule
    ]
})
export class MainModule { }

我最终会为 Main 和 Admin 提供单独的 AuthenticationService。 如果我在App.module 中导入它,确定它可以工作,但我必须加载巨大的SecurityModule,它只需要在可能永远无法访问的 Main/Admin 中。

【问题讨论】:

  • 我认为你不需要在AppModule 中导入ServiceModule,如果它只会被Lazy1Module 使用。您可以在 stackbliktz.com 上创建一个示例吗?
  • @ShashankVivek 重写了整个问题,以在惰性场景中更多地指向 DI 上下文。

标签: angular typescript lazy-loading angular8


【解决方案1】:

您不能在模块之间共享服务,这将扼杀制作模块的全部目的。 但是对于这个场景你可以试试这个方法

App.module
   |__Lazy1.module  
   |                (import)<= SharedModule -> LazyService1.module
   |__Lazy2.module  
   |
   \__(many more)

以上说明创建一个新模块作为共享模块,并创建您想要在服务之间共享的服务,并将该模块导入您需要该服务的其他模块。

更新:

您需要创建一个名为forRoot 的静态方法,将服务与模块本身一起导出。这将为您提供共享模块的所有导入的单个实例。

查看此链接,我 100% 确定它回答了您的问题。快乐编码:)

Shared Dependency Tree

希望对你有帮助,如有疑问请告知

【讨论】:

  • 我之前已经尝试过了,结果每个 Lazy1/2.module 都有 2 个不同的实例。我是不是做错了什么,应该重新审视(你确定一个实例可以在两者之间共享吗?)
  • 在原始问题中添加了一些代码 - 您的想法是否涵盖了我的问题?我什至想不出解决这个问题的方法——我可能遗漏了一些关键的设计事实,所以请解释一下。 :)
  • 更新了我的答案,如果可行,请检查并投票:)
【解决方案2】:

到目前为止,所有答案都非常棒(即使在发布问题之前我实际上已经阅读了大量答案)。

forRoot 的问题(我认为所有建议的链接)是(对我而言)它不是真正的 DI,因为它强烈地将App.module 与注入的模块/服务结合在一起——这是我遇到的全部问题一直在问题中描述。

由于我是一名头脑清醒的 Java 编码员(而且我们确实喜欢依赖注入),所以我无法动摇必须有办法让它成为真正的 DI 的想法。

所以我很确定 Shashank Vivek 在这里至少有部分错误:

因为这是让它在 Angular 中工作的唯一方法

之所以很难找到一个好的解决方案,是因为 Angular 是一个该死的快速开发框架,而且你发现的几乎 90% 的框架都在 2-4 版本左右。

无论如何 - 从 Angular 6 开始,我们在装饰器中 providedIn,虽然我已经知道了几个月(因为与 forRoot 相比,它被认为是“真正的 DI”),但它让我感到惊讶:它实际上是可摇树的

总而言之 - 您可以从字面上获取一项服务,用 providedIn 对其进行标记,并且在您实际使用它之外的任何地方(实际上没有声明或导入)都不要触摸它。

原来服务是它们自己的生物,而 Angular 足够聪明,可以将它们与任何使用它们的东西一起加载和打包。

所以我的问题的答案是:

  1. 删除对惰性服务的所有引用。
  2. @Injectable({ providedIn: 'root' })标记它们
  3. 只需将它们注入到您需要它们的构造函数中(在延迟加载的模块中)。

Angular 将制作部分惰性模块,其中包含在许多惰性模块之间共享的服务(和其他东西)(就像在我的示例中一样),并在它们加载时加载它们。该实例将在根目录中提供(在我的情况下)并在所有应用程序(惰性模块)之间共享。

为了走得更远(因为 DI 是爱),这里有一本很好的读物,介绍了如何走得更远(我说的是 Spring 级别的更远)。 :)

https://angular.io/guide/dependency-injection-providers#tree-shakable-providers

https://www.softwarearchitekt.at/aktuelles/the-new-treeshakable-providers-api-in-angular/

我很惊讶这太难找到了:O ...深埋在 Angular 文档中。

Here is a demo code to play around with it !

【讨论】:

  • 好一个。也将其标记为答案。
猜你喜欢
  • 2018-04-10
  • 1970-01-01
  • 2020-09-06
  • 1970-01-01
  • 2018-05-22
  • 1970-01-01
  • 2017-08-22
  • 2018-04-17
  • 2017-02-22
相关资源
最近更新 更多