angularangular-ivyangular-compiler

Angular: library upgrate to Angular9 with ngcc build error for the demo-app


I'm maintaining an Angular library, which is generated by Angular Cli. Inside the workspace there is a library and a demo-app, which is a standard architecture for all of Angular libray created from angular-cli.

Currently I'm upgrading my library to new release of Angular 9.

I use the automatic upgrade soultion with ng update. After fixing some migration issues(some API are deprecated). The library can be build successfully.

But I am blocked by the build of the demo-app which has the library as dependency. I got ngcc error. After some research online I know the background: https://angular.io/guide/ivy#maintaining-library-compatibility; Library build fails with Angular 9

Even though I understand what's ngcc and why we need it for now, I can't still fix the build error.

In my library I have too modules as following:

// the first module

@NgModule({
   ...
})
export class FirstModule {
  public static forRoot(
    FirstConfig: Config
  ): ModuleWithProviders<FirstModule> {
    return DIYModuleWithProviders(FirstModule, FirstConfig);
  }
  ...
 }

// the second module

@NgModule({
   ...
})
export class SecondModule {
  public static forRoot(
    SecondConfig: Config
  ): ModuleWithProviders<SecondModule> {
    return DIYModuleWithProviders(SecondModule, SecondConfig);
  }
  ...
 }

These two modules both call a function imported from other module in the fotRoot method as following:

export function DIYModuleWithProviders(
  module: any,
  config: Config
): ModuleWithProviders {
  return {
    ngModule: module,
    providers: [
      {
        ...
      },
      {
        ...
      }
    ]
  };
}

This function just return a ModuleWithProviders for the forRoot method. I abstract the function here, because these two module has the same logic for this part.

As I mentioned, the library iteself is build successfully (based on the google Angular team's documents, Library is still using old View Eigine instead of Ivy compiler). But the demo-app failed to build with following error:

Compiling my-library : module as esm5
Error: Error on worker #1: Error: No typings declaration can be found for the referenced NgModule class in function DIYModuleWithProviders(module, config) {
    return {
        ngModule: module,
        providers: [
            {
                ...
            },
            {
                ...
            }
        ]
    };
}.

based on the google Angular team's document: demo-app use Ivy compiler, that's the reason why ngcc comes here.

I tuned the type of DIYModuleWithProviders for a while but can't work it out. Based on the link https://angular.io/guide/migration-module-with-providers, in Angualr 9, ModuleWithProviders must have generic type. So change it to ModuleWithProviders<any>, but it doesn't work.

https://github.com/500tech/angular-tree-component/issues/721. Is there any ideas?


Solution

  • You have to give your ModuleWithProviders a type reference.

    ModuleWithProviders<YourType>

    See there: https://angular.io/guide/migration-module-with-providers

    Edit: To be more precice, your DIYModuleWithProviders function also have to return a typed module.

    Edit: Try it like that:

    export function DIYModuleWithProviders<T>(
      module: T,
      config: Config
    ): ModuleWithProviders<T> {
      return {
        ngModule: module,
        providers: [
          {
            ...
          },
          {
            ...
          }
        ]
      };
    }
    

    or just remove the function and hook it into your Module like that:

    export class YourModule {
    
      public static withOptions(options: YourModuleOptions ): ModuleWithProviders<YourModule> {
        return {
          ngModule: YourModule ,
          providers: [...]
      }
    }