Angular shared module breaks console.log()

49 Views Asked by At

I have an Angular app in which my app-routing.module.ts uses lazy loading for different modules(pages in my case). Now I have a generic shared.module.ts in which I have some common components which I use in all of my lazy loaded modules. However in one particular case I managed to reutilize several components for 2 of my lazy loaded modules, hence I needed another shared module - other-shared.module.ts. Everything seemed to work fine, data is loaded, HTML looks fine, directives are working, however console.log() statements do not work any longer, they are simply not displayed in the console anymore. Which is strange because in all of the other places in my app (including components from shared.module.ts console.log() works fine). If somebody encountered this how did you manage to solve it? I will provide the chain of modules here for clarity:

app-routing.module.ts

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  {
    path: 'home',
    loadChildren: () =>
      import('./pages/home/home.module').then(
        (m) => m.HomeModule,
      ),
  },
...

shared.module.ts

@NgModule({
  declarations: [
    HeaderComponent,
    FooterComponent,
    ToastsContainer,
    LangSwitchComponent,
    ValidationMessagesComponent,
    ConfirmModalComponent,
    ErrorIconComponent,
    ValidationMessagesComponent,
  ],
  imports: [
    CommonModule,
    NgbModule,
    NgbTooltipModule,
    HttpClientModule,
    ReactiveFormsModule,
    FormsModule,
    RouterModule,
    TranslateModule,
  ],
  exports: [
    HeaderComponent,
    FooterComponent,
    ToastsContainer,
    LangSwitchComponent,
    ValidationMessagesComponent,
    ConfirmModalComponent,
    ErrorIconComponent,
    ValidationMessagesComponent,
    CommonModule,
    NgbModule,
    NgbTooltipModule,
    HttpClientModule,
    ReactiveFormsModule,
    FormsModule,
    TranslateModule,
  ],
})
export class SharedModule {}

other-shared.module.ts

@NgModule({
  declarations: [
    Component1,
    Component2,
    ...
  ],
  imports: [SharedModule, DragDropModule],
  exports: [
    SharedModule,
    Component1,
    Component2,
    ...
  ],
})
export class OtherSharedModule {}

some-lazy-loaded-page-module.ts

const routes: Routes = [{ path: '', component: Page1MainComponent }];
@NgModule({
  declarations: [Page1MainComponent],
  imports: [SharedModule, RouterModule.forChild(routes)],
})
export class LazyLoadedPageModule {}

lazy-loaded-page-where-I-use-my-other-shared-module.ts

const routes: Routes = [{ path: '', component: MainComponent }];

@NgModule({
  declarations: [
    MainComponent,
    SubComponent1,
    SubComponent2,
    ...
  ],
  imports: [
    OtherSharedModule,
    RouterModule.forChild(routes),
  ],
})
export class LazyLoadedPageWithIssueModule {}

Initially I had no idea why the console.log was not working, but in the end I managed to pinpoint the issue to modules. At first I moved the components to a single page module and disabled the second page - everything worked. Then I moved the components back to the other-shared.module.ts and imported it in pages, but I kept only 1 page and commented the other - and it still worked fine. Then I enabled the second page again. As soon as the app is initialized with both lazy loaded modules containing the other-shared.module.ts the console log stops working, which hints to the fact that somehow when the module is used in both pages the console crashes in some way, however again, in all other parts of the app it works, and the most important is the fact that in works in components which are registered under the initial shared.module.ts. So I really do not understand why it does not work in that case. In the end I just commented out the other-shared.module.ts and moved the components to the generic shared.module.ts and console.log() again starting working. I would still like to solve the issue because now I import those components in all of my lazy loaded modules, but I need it only for 2 in terms of optimization.

EDIT: I have a base.component.ts which I use for generic functions/services I use trough my app, from which most of my components are extended. I noticed that the components in my shared.module.ts do not extend from it, while the ones in other-shared.module.ts actually do.

base.component.ts

export class BaseComponent {
  protected toastService: ToastService;
  protected translateService: TranslateService;
  protected loggerService: LoggerService;
  protected validatorService: ValidatorService;

  constructor() {
    this.toastService = AppInjector.injector.get(ToastService);
    this.translateService = AppInjector.injector.get(TranslateService);
    this.loggerService = AppInjector.injector.get(LoggerService);
    this.validatorService = AppInjector.injector.get(ValidatorService); // Initialize here instead of each component
  }
...

The thing here is that I did not what to import the services in each component every single time and call super() with 4 arguments, but rather use AppInjector and then I have access to those services in each component right away.

logger.service.ts

@Injectable({
  providedIn: 'root',
})
export class LoggerService {
  level: LogLevel = LogLevel.Info;
  logWithDate: boolean = true;

  constructor() {
    this.level = environment.logLevel;
  }

  public get debug(): LogFunction {
    if (!this.shouldLog(LogLevel.Debug)) return () => null;
    const now = new Date();
    const time = `[${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}]`;
    const type = `Type: ${LogLevel[LogLevel.Debug]};`;
    const style =
      'color:' +
      LogColor.Default +
      ';font-weight:bold; background-color: ' +
      LogColor.Debug +
      ';';

    return console.log.bind(
      window.console,
      `%c ${time} ${type} Message: %s`,
      style,
    );
  }
...

The logger.service.ts is a service used to have console.log() with different colors for various log levels for better readability by binding the console.

1

There are 1 best solutions below

3
SaschaA1982 On

You should not override console.log. Especially not multiple times if debug function is called more than once. Also keep in mind that console and window.console are the same object.

Instead use the LoggerService for printing the log messages to the console.

For example:

@Injectable({
  providedIn: 'root',
})
export class LoggerService {
  level: LogLevel = environment.logLevel;
  logWithDate = true;

  public debug(message: string): void {
    if (!this.shouldLog(LogLevel.Debug)) return;

    const now = new Date();
    const time = `[${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}]`;
    const type = `Type: ${LogLevel[LogLevel.Debug]};`;
    const style = `color: ${LogColor.Default}; font-weight: bold; background-color: ${LogColor.Debug};`;

    console.log(`%c ${time} ${type} Message: ${message}`, style);
  }
  ...
}