angular / angular

Deliver web apps with confidence 🚀
https://angular.dev
MIT License
96.19k stars 25.46k forks source link

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

Closed alan-agius4 closed 3 years ago

alan-agius4 commented 6 years ago

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: https://github.com/dherges/ng-packagr/issues/822 https://github.com/dherges/ng-packagr/issues/778 https://github.com/dherges/ng-packagr/issues/727 https://github.com/dherges/ng-packagr/issues/765 https://github.com/dherges/ng-packagr/issues/767 https://github.com/dherges/ng-packagr/issues/885

alan-agius4 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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.

iamimbohacker commented 6 years ago

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 commented 6 years ago

Are you using the latest angular cli, with a library tsconfig? If not I suggest to either update to that or update to ng-packagr v3.0.0-rc.3

On Wed, 09 May 2018 at 15:47, iamimbohacker notifications@github.com wrote:

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

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/angular/angular/issues/23609#issuecomment-387743732, or mute the thread https://github.com/notifications/unsubscribe-auth/AQv-WtOWkvdrrvf6luk2S0wYaFWeLaejks5twvNugaJpZM4TsqoI .

iamimbohacker commented 6 years ago

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

MurhafSousli commented 6 years ago

@dherges I have these image

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

JoostK commented 6 years ago

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

victornoel commented 6 years ago

For the record, I have this problem with latest angular and ng-packagr (3.0.0) and the three aforementioned parameters are set to true (this is the default when generating a library with angular-cl). So I'm not sure the PR you made @JoostK actually fixes this problem… or something new appeared with latest versions. This is really a pain in the ass because there is no way to understand why something works or not (at one point I made it work, but I am unable to know why or how I can go back to this working state), I second @dherges request to have better error output…

EDIT: I found the source of my problem, it was a wrong paths declaration in tsconfig preventing metadata to be found. Neverttheless, we are really missing something to diagnose those problems…

ReToCode commented 6 years ago

I think I had the same issue. In my case the metadata of the used library was not generated correctly:

"metadata": {}

Then I changed the public_api.ts in the library project:

# from
export * from './lib/auth';
# to
export * from './lib/auth/index';

Now it works fine. Maybe this helps to resolve the issue?

snarun commented 6 years ago

Why the function calls are not supported in decorators? What impacts it may cause? Its not clear of the thought process behind it.. The available docs doesn't provide much details.. For e.g. The compiler throws error for the below code.


@NgModule({})

export class MyStoreModule { static forRoot(): ModuleWithProviders { return StoreModule.forRoot(reducers); } constructor(private store: Store) { console.log("initialized application store ---> ", this.store); } }


@NgModule({ imports: [ StateProviderModule.forRoot(), ], providers: [ ] })

export class ABCModule { }


Error during template compile of 'ABCModule' Function calls are not supported in decorators but 'StoreModule' was called in 'MyStoreModule' 'MyStoreModule' calls 'StoreModule'.

A direct referencing of these classes in ABCModule resolves the issues.. But will be against the standard of 'separation of concerns'. Any thoughts??

probert94 commented 6 years ago

I am also facing this issue, however, I have a slightly different case: I am defining my Routes as a tree, to show them in a hierarchical structure in a sidenav. For the RouterModule instead, I need to provide a flattened version of this tree.

Example:

export const ROUTE_TREE: RouteTree  = [
    {
        path: PATH_PARENT,
        component: ParentComponent,
        treeChildren: [
            {
                path: PATH_CHILD_1,
                component: ChildComponent,
                data: {
                    num: 1
                },
            },
                path: PATH_CHILD_2,
                component: ChildComponent,
                data: {
                    num: 2
                },
            }
        ]
    }
];

should become:

export const ROUTE_TREE: RouteTree  = [
    {
        path: PATH_PARENT,
        component: ParentComponent
    },
    {
        path: PATH_CHILD_1,
        component: ChildComponent,
        data: {
            num: 1
        },
    },
        path: PATH_CHILD_2,
        component: ChildComponent,
        data: {
            num: 2
        },
    }
];

for the RouterModule. As I don't want to change the Routes twice, if I change, add or remove something, I wrote a "flattening" function for my tree and use it in the RouterModuleforRoot-Method.

JIT works fine, but AOT gives me an error, saying Function calls are not supported in decorators.

I will probably try to go the other way and define the Routes flat and try to convert it to a tree programatically.

alan-agius4 commented 6 years ago

@Springrbua I think in your case an error is actually the correct behaviour. If you are using a flattening function inside a decorator.

probert94 commented 6 years ago

@alan-agius4 I was expecting that, but I don't really understand why. Also, I can't find a simple workaround for my case...

alan-agius4 commented 6 years ago

That is because metadata needs to be resolved at compile time, not runtime.

probert94 commented 6 years ago

@alan-agius4 thanks for the information, now that I know it, it seems obvious...

danielmhair commented 6 years ago

Any update on this? I'm having quite a few errors here: https://github.com/formly-js/ngx-formly/issues/996.

maurei commented 6 years ago

Would luuuuv to see this fixed :-)

danielmhair commented 6 years ago

I wanted to comment again, because I have came into this error for the 5th time while updating all my demo apps, main app and libraries (3 demos, 1 main app, and 3 libraries). I receive these errors in various modules. One was referenced above (formly-js/ngx-formly#996) and then another that I just receive from @ngrx/core, where it says the same error:

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

The other 3 are from forRoot methods in my own modules. The common theme with all these, is that they all use InjectionTokens. I'm quite convinced that this is only related to modules that use forRoot methods providing a value for an InjectionToken.

This is forcing me to copy all that is in those forRoot methods and paste them into the module I need them in. This is becoming very taxing, especially when those InjectionTokens are from libraries I don't maintain.

Anyway, I really appreciate all the effort that has gone into resolving this error. If there is anything I can do to help with this, I'm open to help. I'm not really sure what to do, to help with this one. Seems like its pinned down on what is happening. Hopefully it can get resolved soon.

danielmhair commented 6 years ago

After moving the providers from forRoot for StoreModule, the same happened to EffectsModule.forRoot (@ngrx/effects) and StoreDevtoolsModule.instrument() (@ngrx/store-devtools).

Looks like EffectsModule and StoreDevtoolsModule have InjectionTokens as well.

This error turned a clean module file:

@NgModule({
  imports: [
    StoreModule.forRoot(prmCoreActionReducers, { initialState: initialPrmCoreState }),
    EffectsModule.forRoot([ApiEffects, GridEffects]),
    StoreDevtoolsModule.instrument(),
  ],
})
export class PrmCoreStoreModule { }

Into a mess:

@NgModule({
  providers: [
    // STORE DEV TOOLS MODULE instrument() Temporary Fix
    DevtoolsExtension,
    DevtoolsDispatcher,
    StoreDevtools,
    {
      provide: INITIAL_OPTIONS,
      useValue: {},
    },
    {
      deps: [REDUX_DEVTOOLS_EXTENSION, STORE_DEVTOOLS_CONFIG],
      provide: IS_EXTENSION_OR_MONITOR_PRESENT,
      useFactory: createIsExtensionOrMonitorPresent,
    },
    {
      provide: REDUX_DEVTOOLS_EXTENSION,
      useFactory: createReduxDevtoolsExtension,
    },
    {
      deps: [INITIAL_OPTIONS],
      provide: STORE_DEVTOOLS_CONFIG,
      useFactory: createConfig,
    },
    {
      deps: [StoreDevtools],
      provide: StateObservable,
      useFactory: createStateObservable,
    },
    {
      provide: ReducerManagerDispatcher,
      useExisting: DevtoolsDispatcher,
    },

    // EFFECTS MODULE forRoot Temporary Fix
    EffectsRunner,
    EffectSources,
    Actions,
    ApiEffects,
    GridEffects,
    {
      deps: [ApiEffects, GridEffects],
      provide: ROOT_EFFECTS,
      useFactory: createSourceInstances,
    },

    // STORE MODULE forRoot Temporary Fix
    { provide: _INITIAL_STATE, useValue: initialPrmCoreState },
    {
      deps: [_INITIAL_STATE],
      provide: INITIAL_STATE,
      useFactory: _initialStateFactory,
    },
    { provide: _INITIAL_REDUCERS, useValue: prmCoreActionReducers },
    {
      provide: _STORE_REDUCERS,
      useExisting: prmCoreActionReducers instanceof InjectionToken ? prmCoreActionReducers : _INITIAL_REDUCERS,
    },
    {
      deps: [Injector, _INITIAL_REDUCERS, [new Inject(_STORE_REDUCERS)]],
      provide: INITIAL_REDUCERS,
      useFactory: _createStoreReducers,
    },
    {
      provide: META_REDUCERS,
      useValue: [],
    },
    {
      provide: _REDUCER_FACTORY,
      useValue: combineReducers,
    },
    {
      deps: [_REDUCER_FACTORY, META_REDUCERS],
      provide: REDUCER_FACTORY,
      useFactory: createReducerFactory,
    },
    ACTIONS_SUBJECT_PROVIDERS,
    REDUCER_MANAGER_PROVIDERS,
    SCANNED_ACTIONS_SUBJECT_PROVIDERS,
    STATE_PROVIDERS,
    STORE_PROVIDERS,
  ],
})
export class PrmCoreStoreModule { }

As a note, I am now hitting another module with a forRoot that uses Angular's APP_INITIALIZER InjectionToken from ConfigModule from the package @ngx-config/core and have had to do the same thing like the above modules.

guilhermewaess commented 6 years ago

+1 For now, it's fine to leave provide configuration inside the module which is using my lib, but in the future would be great if someone could come and say the status of this fix.

jfpicard1 commented 6 years ago

Any update ? It's blocking our migration from angular 5 to 6. Our libraries contains 3 forRoot. I don't like the solution to copy the forRoot code of the external libraries to our project.

danielmhair commented 6 years ago

Agreed. We have a task to revert once this is fixed.

alan-agius4 commented 6 years ago

@jfpicard1, that flag is not related to angular compiler and this error.

shairez commented 6 years ago

I had a similar error which only happened using yarn link. I fixed it by installing from the source.

lechu1985 commented 6 years ago

+1 Any update on this issue?

danielmhair commented 6 years ago

@shairez I wonder if it is that issue. My problem is, due to my mono-repo, I need to link my libraries to my application via npm link. Hopefully there is another solution.

danielmhair commented 6 years ago

From the reference to ngx-api-utils, perhaps these are related to only tokens that are not using the options in the InjectionToken providedIn and factory?

See https://github.com/ngx-api-utils/ngx-api-utils/commit/276f50afb7d2d6884047adc78b5888026080574e

smoke commented 6 years ago

@danielmhair I have followed your comment above https://github.com/angular/angular/issues/23609#issuecomment-401456878 and refactor the code to avoid having forRoot that provides InjectionToken and it worked, of course loosing the convenience of the forRoot that I really miss!

I wanted to say that I didn't get the chance to dig deeper and confirm is it the InjectionToken alone or there is something else e.g. there is a RegExp passed through those https://github.com/ngx-api-utils/ngx-api-utils/commit/276f50afb7d2d6884047adc78b5888026080574e#diff-c70648b85de41ca753b77ffeb09409a0L38

I really hope this issue gets fixed as soon as possible or reasonable amount of light on the topic gets to us!

danielmhair commented 6 years ago

Yeah, I do miss the forRoot for sure. I really hate this bypass. Everything has worked with this solution, except for one. I'm still tracking it down, but it's with ngrx, it doesn't seem to work.

In fact, it's erroring out from what I posted here: https://github.com/angular/angular/issues/23609#issuecomment-401460241. Perhaps I didn't copy everything over from the forRoots of the following:

    StoreModule.forRoot(prmCoreActionReducers, { initialState: initialPrmCoreState }),
    EffectsModule.forRoot([ApiEffects, GridEffects]),
    StoreDevtoolsModule.instrument(),

Basically, the redux devtools chrome extension is showing that there is no redux active, meaning StoreDevtoolsModule.instrument is not working properly. And the others I use in order to do GETs for my grid and my grids are not displaying any information. So I'm assuming, currently, that it stems from not using the forRoot. We shall see.

dherges commented 6 years ago

I recommend to not use symlinks (and npm link and yarn link). I prefer to copy folders to node_modules - it is the same was npm install does when it unpacks the tarballs.

danielmhair commented 6 years ago

You said not to use yarn link. I assume that is the same as yarn add @my/lib@link:../dist/my-lib is the same, right? This adds to package.json "@my/lib": "link:../dist/my-lib". That is why I said I use npm link in my previous comment. It seems like it results in the same thing. It's just convenient this way so when I run yarn, it will add those links.

So you just have an automation process to copy the folders over, @dherges?

Also, what about when your build process updates dist, it will have to copy over dist every time, which is why I preferred linking because you didn't have to copy anything. And what about ensuring dependencies of other libraries?

For example, I have: Lib 1 Lib 2 depends on lib 1 Lib 3 depends on lib 1 One demo for each lib My main app depends on lib 1, lib 2, and lib 3.

I suppose I will just have a mapping to their dependencies. And then when I publish, just manually add those to the package.json.

And have a post install script to copy those over. Or postbuild script.

danielmhair commented 6 years ago

@dherges what about installing the dependencies of my library in my app?

It will work well to copy the library from dist/my-lib to my-app/node_modules/@my/lib, but what about installing the dependencies of my-lib in my-app/node_modules?

danielmhair commented 6 years ago

Okay, @dherges I found out the best way to do this. In dist/my-lib, I run npm pack, then run yarn add @my/lib@file:../dist/my-lib/my-lib-3.0.0.tgz on my-app, which copies over the dist folder (just like copying over the files), but I'm still getting this error, so in my case, yarn link is not the issue.

mkdropbox commented 6 years ago

Any update on this issue? This seems to be a core angular idiom and has been broken for almost 3 months now. Why hasn't this been marked as a blocking bug and prioritized before new feature implementations? Projects are implementing rather ugly work arounds for this and this has been a blocker for migration to Angular 6 for many,

victornoel commented 6 years ago

The problem with index.ts files not being followed should be fixed in 6.0.8 release (see https://github.com/angular/angular/pull/22856).

I don't know if some other things creates the symptoms described it here though, it would be interesting that people test.

danielmhair commented 6 years ago

I found another workaround that isn't as ugly as my prior workaround. You can see where I found this, here: https://github.com/dschnelldavis/angular2-json-schema-form/issues/273#issuecomment-407184242. So, here is my workaround for the example I gave above with ngrx.


export const storeModuleForRoot: ModuleWithProviders = StoreModule.forRoot(prmCoreActionReducers, { initialState: initialPrmCoreState })
export const effectsModuleForRoot: ModuleWithProviders = EffectsModule.forRoot([ApiEffects, GridEffects])
export const storeDevToolsModuleForRoot: ModuleWithProviders = StoreDevtoolsModule.instrument()

@NgModule({
  imports: [
    effectsModuleForRoot,
    storeModuleForRoot,
    storeDevToolsModuleForRoot,
  ],
})
export class PrmCoreStoreModule { }

Please note that you must declare ModuleWithProviders, otherwise, another error occurs.

smoke commented 6 years ago

I see angular@6.1.0 is released have someone checked if this problem is fixed?

smoke commented 6 years ago

I have placed an easy to reproduce branch here https://github.com/ngx-api-utils/ngx-api-utils/pull/14 using newly released Angular 6.1.0

leonardochaia commented 6 years ago

After some struggle it seems that forRoot must be a function with a return statement and nothing more.

This menas that, variables and functions can not be used inside the method.

WORKS

 public static forRoot(config: ITimoneerTab[]): ModuleWithProviders {
  return {
    ngModule: TabsModule,
    providers: [
      [...]
      {
        provide: APPLICATION_TABS,
        useValue: config
      }
    ]
  };
}

DOESNT WORK Storing the object in a variable, or using any function breaks the build.

public static forRoot(config: ITimoneerTab[]): ModuleWithProviders {
  const output = {
    ngModule: TabsModule,
    providers: [
     [...]
      {
        provide: APPLICATION_TABS,
        useValue: config
      }
    ]
  };

  return output;
}

Commit fixing this in Timoneer

ng build --prod
ERROR in Error during template compile of 'AppTabsModule'
  Function calls are not supported in decorators but 'TabsModule' was called.

A good example is the RouterModule

danielmhair commented 6 years ago

@leonardochaia that is correct, because it must be a completely static function, including what it returns, which is why it cannot have a const in there.

superduck35 commented 6 years ago

After reading @leonardochaia 's answer I just fixed this error on my lib import.. by removing a console.log() statement from the forRoot method declaration

kiranjholla commented 6 years ago

How should shared modules that use data passed in from the Application context for initialization be handled? I am trying the solution suggested in https://github.com/angular/angular-cli/issues/9358#issuecomment-373053053, but unsuccessfully.

My scenario is as below:

> ng --version
Angular CLI: 6.1.4
Node: 10.4.1
OS: win32 x64
Angular: 6.1.4
... animations, cli, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.7.4
@angular-devkit/build-angular      0.7.4
@angular-devkit/build-ng-packagr   0.7.5
@angular-devkit/build-optimizer    0.7.4
@angular-devkit/build-webpack      0.7.4
@angular-devkit/core               0.7.4
@angular-devkit/schematics         0.7.4
@angular/cdk                       6.4.6
@angular/flex-layout               6.0.0-beta.17
@angular/material                  6.4.6
@ngtools/json-schema               1.1.0
@ngtools/webpack                   6.1.4
@schematics/angular                0.7.4
@schematics/update                 0.7.4
ng-packagr                         3.0.6
rxjs                               6.2.2
typescript                         2.7.2
webpack                            4.9.2

My Code:

import { NgModule, ModuleWithProviders, InjectionToken } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AppSettingsService } from './services/app-settings.service';

export const AppSettingsObject = new InjectionToken('AppSettingsObject');

export function createAppSettingsService(settings) {
  return new AppSettingsService(settings);
}

@NgModule({
  imports: [
    CommonModule
  ]
})
export class AppSettingsModule {
  static forRoot(config: Object): ModuleWithProviders {
    return {
      ngModule: AppSettingsModule,
      providers: [
        { provide: AppSettingsObject, useValue: config },
        {
          provide: AppSettingsService,
          useFactory: (createAppSettingsService),
          deps: [AppSettingsObject]
        }
      ]
    };
  }
}

Error:

> ng build my-app --prod

Date: 2018-08-29T
Hash: saghsh4ty463f34r4fef
Time: 8585ms
chunk {0} runtime.xxx.js (runtime) 1.05 kB [entry] [rendered]
chunk {1} styles.xxx.css (styles) 102 kB [initial] [rendered]
chunk {2} polyfills.xxx.js (polyfills) 130 bytes [initial] [rendered]
chunk {3} main.xxx.js (main) 128 bytes [initial] [rendered]

ERROR in Error during template compile of 'MyAppModule'
  Function calls are not supported in decorators but 'AppSettingsModule' was called.

Any help?

danielmhair commented 6 years ago

I would suggest my fix. Its temporary, but not overbearing in how bad it looks. Not sure if it will help, but it helped me in about 5 scenarios quite like this.

In MyAppModule, when you call forRoot, have it be exported into a const variable such as:

export const appSettingsModuleForRoot: ModuleWithProviders = AppSettingsModule.forRoot(yourConfig)

...
imports: [
  ...,
  appSettingsModuleForRoot,
],
...

Make sure you import ModuleWithProviders from @angular/core and that you put it as a typing. It might not work if you do not type the appSettingsModuleForRoot variable.

kiranjholla commented 6 years ago

@danielmhair Thanks! I actually had tried your fix too and that too had not worked for me.

However, I have now discovered that the problem wasn't in this piece of code or the fixes that had been suggested here, but rather in a different piece of my code. It was in the way I was deriving the config object that was being passed into this forRoot method when importing the AppSettingsModule.

The Problem

/**
 * main.module.ts
 *
// Angular & Lodash
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { assign } from 'lodash';

// Application Modules
import { coreConfig } from '../modules/core';
import { userConfig } from '../modules/user';

// Components
import { MainComponent } from './components/main.component';

const appConfig = assign({}, coreConfig, userConfig);     // <--- This is where the problem came from!!

@NgModule({
  declarations: [
    MainComponent
  ],
  imports: [
    BrowserModule,
    // Application-specific modules
    AppSettingsModule.forRoot(appConfig)
  ],
  providers: [],
  bootstrap: [MainComponent]
})
export class MainModule { }

The Fix

To fix this, I replaced this with

/**
 * main.module.ts
 *
@NgModule({
  declarations: [
    MainComponent
  ],
  imports: [
    BrowserModule,
    // Application-specific modules
    AppSettingsModule.forRoot(coreConfig, userConfig)
  ],
  providers: [],
  bootstrap: [MainComponent]
})
export class MainModule { }

/**
 * app.settings.module.ts
 *
export const CoreSettingsObject = new InjectionToken('CoreSettingsObject');
export const UserSettingsObject = new InjectionToken('UserSettingsObject');

export function createAppSettingsService(core, user) {
  return new AppSettingsService(assign({}, core, user));
}

@NgModule({
  imports: [
    CommonModule
  ]
})
export class AppSettingsModule {
  static forRoot(core: Object, user: Object): ModuleWithProviders {
    return {
      ngModule: AppSettingsModule,
      providers: [
        { provide: CoreSettingsObject, useValue: core },
        { provide: UserSettingsObject, useValue: user },
        {
          provide: AppSettingsService,
          useFactory: (createAppSettingsService),
          deps: [CoreSettingsObject, UserSettingsObject]
        }
      ]
    };
  }
}

The trick seems to be to ensure that there is absolutely no code-execution necessary before the forRoot is invoked. All executable code should be only within the factory. The forRoot method can only deal with completely static values.

kiranjholla commented 6 years ago

OK, I spoke too soon.; this is like peeling an onion! This issue is still not completely fixed.

Context

The AppSettingsModule that I keep referring to in my previous posts in the thread above are actually part of a different Library application within the same Angular CLI workspace.

As I was working on this project, to investigate another issue, I had temporarily updated my tsconfig.json to point to the Library application directly instead of via the dist folder.

Original tsconfig.json settings
{
    ...
    "paths": {
      "my-lib": [
        "dist/my-lib"
      ],
      "my-lib/*": [
        "dist/my-lib/*"
      ]
    }
}
Modified tsconfig.json settings
{
    ...
    "paths": {
      "my-lib": [
        "projects/my-lib"
      ],
      "my-lib/*": [
        "projects/my-lib/*"
      ]
    }
}

With the above modified settings, the build works just fine.

However, if I revert the tsconfig.json to the original settings, the build fails.

I have now created a github repo to illustrate this problem. If you clone that repo and run npm run repro, you will see the error I am referring to.

kiranjholla commented 6 years ago

Thanks to help from @samherrmann, I have been able to get my code working.

It appears that the AOT-enabled compilation process has problems dealing with import statements that rely on index.ts files inside directories.

Firstly, an explicit export statement for the Angular Modules was necessary within the library public_api.ts file to get rid of the error Function calls are not supported in decorators but 'Module' was called..

But even after that, all directory-based import statements within the library code, which rely on index.ts files within those directories to export the other modules, had to be changed to import directly from the module files themselves.

i.e. change:

import { TestService } from './services';

to

import { TestService } from './services/test.service';

Look at https://github.com/kiranjholla/ng-issue-23609-repro/issues/1#issuecomment-417449088 for details.

albanx commented 6 years ago

Any update on this issue?

albanx commented 6 years ago

I solved by moving all function calls to normal functions (ex. function x() {}, and not const x = () =>{}