Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function calls are not supported in decorators when fullTemplateTypeCheck is not specified and @dynamic has no effect #23609

Closed
alan-agius4 opened this issue Apr 30, 2018 · 117 comments
Labels
area: compiler Issues related to `ngc`, Angular's template compiler freq3: high P5 The team acknowledges the request but does not plan to address it, it remains open for discussion state: confirmed type: bug/fix
Milestone

Comments

@alan-agius4
Copy link
Contributor

alan-agius4 commented Apr 30, 2018

I'm submitting a...


[X] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:

Current behavior

When building a library and specifying both skipTemplateCodegen and strictMetadataEmit to true, and you try to call a method inside the ngModule decorate example RouterModule.forChild([]) this will cause a compilation error Function calls are not supported in decorators but 'RouterModule' was called.

When adding fullTemplateTypeCheck to true the error is not emitted.

Also, @dynamic seems not to have any effect in this particular case.

Expected behavior

No error emitted, or at least that it can be suppressed with the @dynamic.

I also expect that setting fullTemplateTypeCheck doesn't have any effect here as this flag relates more to binding in templates.

Minimal reproduction of the problem with instructions

Create a file example

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

@NgModule({
  imports: [
    RouterModule.forChild([])
  ]
})
export class LibModule { }

Have tsconfig set with the following options;

  "angularCompilerOptions": {
    "skipTemplateCodegen": true,
    "strictMetadataEmit": true
  }

When transpiling this will emit an error;

Error during template compile of 'LibModule' Function calls are not supported in decorators but 'RouterModule' was called.

Note when adding "fullTemplateTypeCheck": true no error is emitted. (Though this is kinda weird as I don't think this shouldn't have any effect)

Reproduction repo: https://github.com/alan-agius4/angular-issue-23609

What is the motivation / use case for changing the behavior?

No error was emitted in NG 5

Environment


Angular version: 6.0.0-rc-6

Related issues:
ng-packagr/ng-packagr#822
ng-packagr/ng-packagr#778
ng-packagr/ng-packagr#727
ng-packagr/ng-packagr#765
ng-packagr/ng-packagr#767
ng-packagr/ng-packagr#885

@alan-agius4 alan-agius4 changed the title Function calls are not supported in decorators when fullTemplateTypeCheck is not specified Function calls are not supported in decorators when fullTemplateTypeCheck is not specified and @dynamic has no effect Apr 30, 2018
@alan-agius4
Copy link
Contributor Author

alan-agius4 commented Apr 30, 2018

Added a small repo reproducing this.

From my quick debug, It looks like the static_reflector is not resolving members / statics properly. As for instance the RouterModule should have a forChild member.

image

@wardbell
Copy link
Contributor

wardbell commented May 5, 2018

I have this problem too. I tried fullTemplateTypeCheck in lib/tsconfig.json and it made no difference.

My repro:

git clone https://github.com/johnpapa/angular-ngrx-data.git ngrx-data-FAIL
cd ngrx-data-FAIL
git checkout ng-v6-FAIL
npm install

Now attempt to build the ngrx-data library

npm run build-lib

The build fails. The console says

BUILD ERROR
Error during template compile of 'NgrxDataModule'
  Function calls are not supported in decorators but 'StoreModule' was called.
  ...

Comment out the two ngrx imports in NgrxDataModule (leaving the FooModule) and try building again.
This time the build succeeds and generates a package in dist.

Note that FooModule is just fine.

@dherges
Copy link
Contributor

dherges commented May 6, 2018

Regarding Ward's repro: @wardbell

The build will succeed / fail depending on the combination of angularCompilerOptions. Added one example in this repro

Build success

    "skipTemplateCodegen": true,
    "strictMetadataEmit": true,
    "fullTemplateTypeCheck": true
    "skipTemplateCodegen": false,
    "strictMetadataEmit": false
    "skipTemplateCodegen": false,
    "strictMetadataEmit": true,
    // fullTemplateTypeCheck omitted (= default value)

Build failures

    "skipTemplateCodegen": true,
    "strictMetadataEmit": true,
    // fullTemplateTypeCheck omitted (= default value)
    "skipTemplateCodegen": true,
    "strictMetadataEmit": false
    // fullTemplateTypeCheck omitted (= default value)

Observation

In Ward's example, setting "skipTemplateCodegen": true requires that "fullTemplateTypeCheck": true is also enabled to get a success build from ngc.

Side notes / other thoughts

My experience is that the issue goes down to "everything statically analyzable for AoT" (see "need for static value resoltion" in the compiler docs). Imo, something is broken around the strictMetadataEmit option or my understanding of the option is horribly broken 😆

From my experience I can tell that the issue is often produced in static forRoot(): ModuleWithProviders, sometimes depending on one line of code that becomes or becomes not "statically analyzable". Of course, I don't have reliable repros and I also don't want to speculate on some vague memories of code that I've seen working / non-working.

Can ngc improve the error message?

What will help that ngc prints out the line number in the source code that triggers the error.

@wardbell
Copy link
Contributor

wardbell commented May 7, 2018

Thanks, @dherges, for figuring out a combination that succeeds. I'm clearly flailing with no clue what these flags are doing to help or hurt.

This issue should remain open until Angular makes these choices intelligible and documents appropriately.

wardbell added a commit to johnpapa/angular-ngrx-data that referenced this issue May 7, 2018
* Inspired by inability to build because of issue
angular/angular#23609

* other refactors to satisfy RxJS v6 and lint checks
wardbell added a commit to johnpapa/angular-ngrx-data that referenced this issue May 8, 2018
* tweak collection reducer methods

* refactor: NgrxDataModule no longer calls store/effects .forFeature,
Inspired by inability to build because of issue
angular/angular#23609

* other refactors to satisfy RxJS v6, fix and add tests, and clear many lint errors.

* feat: add optional label to EntityAction and EntityActionFactory
@iamimbohacker
Copy link

iamimbohacker commented May 9, 2018

Can anyone tell a nub what should I do for now to workaround this issue?
ng build --prod
I'm using ngx-progressbar
and i get : "Function calls are not supported in decorators but 'NgProgressModule' was called."

@alan-agius4
Copy link
Contributor Author

alan-agius4 commented May 9, 2018 via email

@iamimbohacker
Copy link

I'm using Angular CLI 6.0.0 only. I do not use ng-packagr

@MurhafSousli
Copy link

@dherges I have these
image

but I still get the error when I use the module in AOT

@JoostK
Copy link
Member

JoostK commented May 10, 2018

For more information on why the metadata is elided, as shown in @alan-agius4's screenshot I have a detailed description over at ng-packagr/ng-packagr#860.

@kroeder
Copy link
Contributor

kroeder commented Aug 5, 2020

I fixed the error by following #23609 (comment)

  • you can not have any source code inside the function. It can only contain a return statement that yields a ModuleWithProviders object.

I had to remove this

@NgModule({
    imports: [
        // [...]
    ]
})
export class CoreModule implements OnDestroy {

    private static showUserInfo = true;

    static forRoot(options: CoreOptions = {}): ModuleWithProviders<NextCoreModule> {
        // this line caused the error
        // NextCoreModule.showUserInfo = options.showUserInfo ?? true;

        return {
            ngModule: NextCoreModule,
            providers: [
                {
                    provide: APP_INITIALIZER,
                    useFactory: initialize,
                    deps: [
                        ConfigBuilderService, AppKeyService, TranslateService, Title, coreOptionsToken
                    ],
                    multi: true
                },
                { provide: coreOptionsToken, useValue: options || {} }
            ]
        };
    }

    // [...]
}

@JustDoItSascha
Copy link

@kroeder You, sir, made my day! Thanks!

Does anyone know whether this is documented? And why this happens?

@mlc-mlapis
Copy link
Contributor

mlc-mlapis commented Aug 5, 2020

@JustDoItSascha

Read #36415 and #37126 for details in the implementation. The reason is the Angular compiler has to exactly understand (by only static analysis) what the code means.

@Adrian1907
Copy link

I fixed that by replacing import of RouterModule.forChild(routes) with the previously defined constant:
export const routerModule = RouterModule.forChild(routes);

@jelbourn jelbourn added P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent P5 The team acknowledges the request but does not plan to address it, it remains open for discussion and removed P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent severity3: broken labels Oct 1, 2020
@aescobar-icc
Copy link

this works for me:

"angularCompilerOptions": {
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"enableResourceInlining": true
},

@MickL
Copy link

MickL commented Jan 20, 2021

So that's really our fix for this issue - Ivy will eventually make confusing and inconsistent metadata errors like this a thing of the past. With libraries the situation is a little complicated since for backwards compatibility, they still have to publish in View Engine format and thus deal with strictMetadataEmit for a little longer, but that's going to change sooner rather than later, hopefully.

@alxhub I created a Library which is not allowed to be published to npm built with Ivy. Therefor I have to use ng build --prod which uses View Engine. But when I do so, I cant built:

@NgModule({
  imports:      [
    LoggerModule.forRoot({
      level: NgxLoggerLevel.DEBUG
    }),
  ],
})
export class MyLibModule {}

Error:

Function calls are not supported in decorators but 'LoggerModule' was called.

This issue is 2,5 years old and has >130 comments. A lot of suggestions from where I dont understand most of them. @alxhub would you mind write down a clear workaround? I wonder what this compiler options do and what downsides they have. And will there be ever a fix for View Engine? If not, and View Engine is required for libraries, then the issue and workaround should be documented in the documentation.

Also @SergeyVolynkin @hitallow @bh3605 @antontemchenko would you mind write down why you downvoted @Adrian1907 solution? Sounded like a quick and easy fix, but why isnt it?

@SergeyVolynkin
Copy link
Contributor

Hey, there; Didn't downvote 😃 ; you probably mistyped me instead @SergeyMell

@TheRealOha
Copy link

TheRealOha commented Mar 31, 2021

I'm having the same issue as @MickL but with NgxWebstorageModule.forRoot().
I have the PrimeNg 11 Table as part of my library, which throws a very strange error when it's not compiled with Ivy.
To circumvent this I set "fullTemplateTypeCheck": false", which seemed to remove the need to build with Ivy, but now I'm stuck with the same thing as Mick.
Anyone's got a solution?
I found that people were advising to build Libs that are only publisehd to internal NPM repos with Ivy by removing prebublishOnly from package.json, but I don't even have this set anywhere in my package.json, therefore I don't know how to remove it.
However, this also is only a workaround and doesn't really fix the whole problem, that libs are not supposed to be built with Ivy but if you try to omit Ivy, you're stuck with problems like the one described here.

Help, anyone?

@NiklasPor
Copy link

Always make sure that when you're providing a module (inside an npm library / ngc / enableIvy: false) that you're keeping the withConfig forRoot methods as simple one liners. For example I had to remove the simple assignment at the start and move it into a parameter, instead of creating a variable:

Classic "Function calls are not supported.." 👿 :

@NgModule({})
class MyModule {
  static withConfig(
    config: Partial<Config> = {}
  ): ModuleWithProviders<MyModule> {
    const mergedConfig: Config = {
      ...defaultConfig,
      ...config,
    };

    return {
      ngModule: MyModule,
      providers: [
        {
            provide: MY_VALUE_1,
            useValue: mergedConfig.myValue1,
          },
          {
            provide: MY_VALUE_2,
            useValue: mergedConfig.myValue2,
          },
      ],
    };
  }
}

Actually working 🤯 :

@NgModule({})
class MyModule {
  private static withMergedConfig(config: MyConfig) {
    return {
      ngModule: MyModule,
      providers: [
        {
          provide: MY_VALUE_1,
          useValue: config.myValue1,
        },
        {
          provide: MY_VALUE_2,
          useValue: config.myValue2,
        },
      ],
    };
  }

  static withConfig(
    config: Partial<MyConfig> = {}
  ): ModuleWithProviders<MyModule> {
    return MyModule.withMergedConfig({
      ...defaultConfig,
      ...config,
    });
  }
}

tsconfig.json (like already suggested above):

"angularCompilerOptions": {
  "skipTemplateCodegen": true,
  "strictMetadataEmit": true,
  "enableResourceInlining": true,
  "fullTemplateTypeCheck": true,
}

@JoostK
Copy link
Member

JoostK commented May 14, 2021

This has arguably been the most annoying error that libraries have had to deal with, and I'm glad that this class of issues has been resolved with the Ivy compiler.

With v12 now allowing libraries to be compiled with the Ivy compiler, I am closing this issue as resolved.

@SuperITMan
Copy link

Hey @JoostK

Could you share your configuration to publish libraries with Ivy?

Locally, with angular v12 and ng-packagr 12, I'm still not allowed to publish libraries with ivy enabled 😞
Angular compiler-cli is still adding the following script in "package.json":

"scripts": {
  "prepublishOnly": "node --eval \"console.error('ERROR: Trying to publish a package that has been compiled by Ivy in full compilation mode. This is not allowed.\\nPlease delete and rebuild the package with Ivy partial compilation mode, before attempting to publish.\\n')\" && exit 1"
}

According to official doc, Ivy is still not recommended for libraries:

enableIvy
Enables the Ivy compilation and rendering pipeline. Default is true, as of version 9. In version 9, you can opt out of Ivy to continue using the previous compiler, View Engine.

For library projects generated with the CLI, the production configuration default is false in version 9.

Thanks in advance for your help 👍

@NiklasPor
Copy link

NiklasPor commented Jun 9, 2021

@SuperITMan what you're reading is valid for version 9 - 11.

Starting with version 12 it's recommended to set enableIvy: true and compilationMode: 'partial'.

...Please delete and rebuild the package with Ivy partial compilation inside your error message refers to this compilation mode.


compilationMode

Specifies the compilation mode to use. The following modes are available:

  • 'full': generates fully AOT-compiled code according to the version of Angular that is currently being used.
  • 'partial': generates code in a stable, but intermediate form suitable for a published library.

The default value is 'full'.

@JoostK
Copy link
Member

JoostK commented Jun 9, 2021

According to official doc, Ivy is still not recommended for libraries:

That is something we should fix in the docs, then, as it's not the case anymore since v12.

Other than that I think I got beaten by @NiklasPor, who has just given the correct answer :)

@SuperITMan
Copy link

@NiklasPor @JoostK

Thanks for your quick answers! 😃

You're right, I missed the "compilationMode": "partial" part for libraries. With this option, the "prepublishOnly" is no longer present 👍

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jul 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: compiler Issues related to `ngc`, Angular's template compiler freq3: high P5 The team acknowledges the request but does not plan to address it, it remains open for discussion state: confirmed type: bug/fix
Projects
None yet
Development

No branches or pull requests