【问题标题】:Angular Circular dependency detected检测到 Angular 循环依赖项
【发布时间】:2021-04-07 05:54:52
【问题描述】:

在我的 Angular 应用程序中,我有三个模块,核心模块和共享模块以及主题模块。核心模块包含所有单例服务、拦截器和所有。主题模块包含所有第三方包。共享模块具有所有共享组件、管道、方向。结构看起来像这样 -

Core ->
  --- /Services
      --- title.service.ts
      --- analytics.service.ts
      --- logger.service.ts
      --- confirm-dialog.service.ts
      --- index.ts
core.module.ts
theme.module.ts


Shared ->
  --- /components
      --- direction-map
      --- confirm-dialog
      --- index.ts
shared.module.ts

当我尝试将核心模块中的任何服务添加到收到此警告的任何共享组件时 -

应用模块

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

import { CoreModule } from '@core/core.module';
import { ThemeModule } from '@core/theme.module';

@NgModule({
    declarations: [AppComponent],
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        CoreModule,
        ThemeModule.forRoot()
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule {}

核心模块

import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { NgModule, Optional, SkipSelf } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { EnsureModuleLoadedOnceGuard } from './ensureModuleLoadedOnceGuard';
import { AjaxService } from './http';
import { AuthenticationService } from './authentication';
import { HTTPInterceptorProvider } from './interceptors';
import { AuthGuard } from './guards';
import {
    TitleService,
    LoggerService,
    AnalyticsService,
    ConfirmationDialogService
} from './services';

const PROVIDERS = [
    AuthGuard,
    AjaxService,
    TitleService,
    LoggerService,
    AnalyticsService,
    AuthenticationService,
    ConfirmationDialogService
];

@NgModule({
    imports: [
        CommonModule,
        FormsModule,
        RouterModule,
        HttpClientModule,
        ReactiveFormsModule
    ],
    exports: [RouterModule, HttpClientModule, FormsModule, ReactiveFormsModule],
    providers: [...PROVIDERS, HTTPInterceptorProvider]
})
export class CoreModule extends EnsureModuleLoadedOnceGuard {
    /**
     * !Ensuring that CoreModule is only loaded into AppModule
     * *Looks for the module in the parent injector to see if it's already been loaded (only load once)
     *
     * @param module as parameter
     * @date: 10 Feb 2021
     * @developer: Rahul Kundu <r.kundu5@gmail.com>
     */
    constructor(
        @Optional() @SkipSelf() parentModule: CoreModule,
        _titleService: TitleService
    ) {
        super(parentModule);
        _titleService.init();
    }
}

主题模块

import { CommonModule } from '@angular/common';
import {
    NgModule,
    Optional,
    SkipSelf,
    ModuleWithProviders
} from '@angular/core';
import { throwIfAlreadyLoaded } from './ensureModuleLoadedOnceGuard';

// Configs imports
import { appToaster } from '@app/configs';

// Third party packages
import { ToastrModule } from 'ngx-toastr';
import { CookieService } from 'ngx-cookie-service';
import { NgSelectModule } from '@ng-select/ng-select';
import { OverlayscrollbarsModule } from 'overlayscrollbars-ngx';
import { NgxTippyModule, NgxTippyService } from 'ngx-tippy-wrapper';
import { LoadingBarModule, LoadingBarService } from '@ngx-loading-bar/core';

// NGX bootstrap Packages
import { TabsModule } from 'ngx-bootstrap/tabs';
import { ModalModule } from 'ngx-bootstrap/modal';
import { RatingModule } from 'ngx-bootstrap/rating';
import { SortableModule } from 'ngx-bootstrap/sortable';
import { CollapseModule } from 'ngx-bootstrap/collapse';
import { AccordionModule } from 'ngx-bootstrap/accordion';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';

const BASE_MODULES = [CommonModule];

const THEME_PROVIDERS = [CookieService, NgxTippyService, LoadingBarService];

const PLUGINS_I = [
    NgSelectModule,
    NgxTippyModule,
    LoadingBarModule,
    OverlayscrollbarsModule,
    ToastrModule.forRoot(appToaster)
];

const PLUGINS_E = [
    ToastrModule,
    NgSelectModule,
    NgxTippyModule,
    LoadingBarModule,
    OverlayscrollbarsModule
];

const NGB_MODULES_I = [
    TabsModule.forRoot(),
    ModalModule.forRoot(),
    BsDatepickerModule.forRoot()
];

const NGB_MODULES_E = [
    TabsModule,
    ModalModule,
    BsDatepickerModule
];

@NgModule({
    imports: [...BASE_MODULES, ...PLUGINS_I, ...NGB_MODULES_I],
    exports: [...BASE_MODULES, ...PLUGINS_E, ...NGB_MODULES_E],
    declarations: []
})
export class ThemeModule {
    static forRoot(): ModuleWithProviders<ThemeModule> {
        return {
            ngModule: ThemeModule,
            providers: [...THEME_PROVIDERS]
        };
    }
}

共享模块

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

// Shared Components
import {
    DirectionMapComponent,
    ConfirmDialogComponent
} from '@shared/components';

// Custom pipes
import {
    SummaryPipe,
    TimeAgoPipe,
    OrdinalPipe,
    FileSizePipe,
    ShortNumberPipe,
    SafeSanitizePipe
} from '@shared/pipes';

// Custom Directives
import {
    DigitOnlyDirective,
    ImgFallbackDirective,
    ClickOutsideDirective,
    InputTransformDirective,
    AutocompleteOffDirective,
    OverlayScrollbarDirective
} from '@shared/directives';

const MODULES = [CommonModule];

const CUSTOM_PIPES = [
    SummaryPipe,
    TimeAgoPipe,
    OrdinalPipe,
    FileSizePipe,
    ShortNumberPipe,
    SafeSanitizePipe
];

const DIRECTIVES = [
    DigitOnlyDirective,
    ImgFallbackDirective,
    ClickOutsideDirective,
    InputTransformDirective,
    AutocompleteOffDirective,
    OverlayScrollbarDirective
];

const SHARED_COMPONENTS = [DirectionMapComponent];

const ENTRY_COMPONENTS = [ConfirmDialogComponent];

@NgModule({
    imports: [...MODULES],
    declarations: [
        ...ENTRY_COMPONENTS,
        ...SHARED_COMPONENTS,
        ...CUSTOM_PIPES,
        ...DIRECTIVES
    ],
    exports: [...SHARED_COMPONENTS, ...MODULES, ...CUSTOM_PIPES, ...DIRECTIVES],
    entryComponents: [...ENTRY_COMPONENTS]
})
export class SharedModule {}

direction-map.component

import { LoggerService } from '@core/services';
export class ConfirmDialogComponent implements OnInit {
    constructor(private _logger: LoggerService) {}

    ngOnInit(): void {
        this._logger.log('test');
    }
}

【问题讨论】:

  • 您的实际问题是什么? Angular 已经准确地告诉你每个循环依赖中涉及哪些文件——你需要做的就是解决这些问题。
  • @Roddy of the Frozen Peas,我怎样才能删除警告。我只是在共享组件中导入了一项服务。我不知道如何解决这个问题。
  • 抱怨你是从桶中导入而不是直接从文件中导入,导致循环。
  • oho 好的,我现在明白了,在我的组件中我已经做到了 - import { LoggerService } from '@core/services/logger.service';。蚂蚁警告消失了。
  • @Roddy of the Frozen Peas 我有一个来自除共享之外的任何其他组件的问题我可以做到这一点import { LoggerService } from '@core/services'; 但是在共享中为什么完全导入有任何具体原因?

标签: angular typescript


【解决方案1】:

这可能是因为您可能会在某些组件中导入某些服务,反之亦然。组件应该依赖于服务,但服务不应该依赖于组件。服务应该只负责数据提供者,而组件应该是 UI 的控制器。因此,相应地按顺序导入事物,因此您可以避免此处创建的循环依赖。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 2018-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多