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

Router: AoT compilation fails when using a function with loadChildren #10789

Closed
brandonroberts opened this issue Aug 14, 2016 · 33 comments
Closed

Comments

@brandonroberts
Copy link
Contributor

I'm submitting a ... (check one with "x")

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

In order to enable lazy loading with Webpack 1, a custom NgModuleFactoryLoader must be implemented to lazy load routes with loadChildren. I've implemented an example loader here.

https://github.com/brandonroberts/router-cli-aot/blob/master/src/app/shared/async-ng-module-loader.ts

The custom load function is being used here: https://github.com/brandonroberts/router-cli-aot/blob/master/src/app/app.routing.ts#L12-L25

When running ngc over the provided repo, an error occurs:

Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function (position 23:24 in the original .ts file), resolving symbol crisisCenterRoutes in /router-cli-aot/src/app/app.routing.ts, resolving symbol appRoutes in /router-cli-aot/src/app/app.routing.ts, resolving symbol routing in /router-cli-aot/src/app/app.routing.ts, resolving symbol AppModule in /router-cli-aot/src/app/app.module.ts, resolving symbol AppModule in /router-cli-aot/src/app/app.module.ts

I can comment out the loadChildren line and ngc completes successfully. If I uncomment the line after running ngc and bundle with webpack, the app works as desired with lazy loading.

While #10705 adds support for using a callback function with loadChildren such as loadChildren: () => System.import('lazy.module#LazyModule'), this will cause AoT compilation to fail also with the same error.

Expected/desired behavior

Providing a callback function to loadChildren does not cause AoT compilation to fail when used
with vanilla webpack or some other bundling tool.

Reproduction of the problem
If the current behavior is a bug or you can illustrate your feature request better with an example, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5).

What is the expected behavior?

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

Webpack 1/2 use a callback function to provide lazy loading through returning a promise.

Please tell us about your environment:

  • Angular version: 2.0.0-rc.5
  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
  • Language: [all | TypeScript X.X | ES6/7 | ES5]
@marcalj
Copy link

marcalj commented Aug 17, 2016

I have the same error in an ngUpgrade app with RC5. Not sure what is causing the error since the stack trace is not pointing to my code.

./node_modules/.bin/ngc -p tsconfig.json 
Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol AppModule in /Users/foo/app/scripts/core/app.module.ts, resolving symbol AppModule in /Users/foo/app/scripts/core/app.module.ts
    at simplifyInContext (/Users/foo/node_modules/@angular/compiler-cli/src/static_reflector.js:463:23)
    at StaticReflector.simplify (/Users/foo/node_modules/@angular/compiler-cli/src/static_reflector.js:466:22)
    at StaticReflector.annotations (/Users/foo/node_modules/@angular/compiler-cli/src/static_reflector.js:52:36)
    at _loop_1 (/Users/foo/node_modules/@angular/compiler-cli/src/codegen.js:50:54)
    at CodeGenerator.readFileMetadata (/Users/foo/node_modules/@angular/compiler-cli/src/codegen.js:63:13)
    at /Users/foo/node_modules/@angular/compiler-cli/src/codegen.js:91:74
    at Array.map (native)
    at CodeGenerator.codegen (/Users/foo/node_modules/@angular/compiler-cli/src/codegen.js:91:35)
    at codegen (/Users/foo/node_modules/@angular/compiler-cli/src/main.js:7:69)
    at Object.main (/Users/foo/node_modules/@angular/tsc-wrapped/src/main.js:25:16)
Compilation failed

@Richard87
Copy link

Richard87 commented Aug 18, 2016

Hi guys, I'm not sure if it's related, but it's I get the same error message:

C:\Users\richa\Prosjekt\phono-frontend>node_modules\.bin\ngc -p .
Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function (position 37:24 in the original .ts file), resolving symbol AppModule in C:/Users/richa/Prosjekt/phono-frontend/src/app/app.module.ts
    at simplifyInContext (C:\Users\richa\Prosjekt\phono-frontend\node_modules\@angular\compiler-cli\src\static_reflector.js:463:23)
    at StaticReflector.simplify (C:\Users\richa\Prosjekt\phono-frontend\node_modules\@angular\compiler-cli\src\static_reflector.js:466:22)
    at StaticReflector.annotations (C:\Users\richa\Prosjekt\phono-frontend\node_modules\@angular\compiler-cli\src\static_reflector.js:52:36)
    at _loop_1 (C:\Users\richa\Prosjekt\phono-frontend\node_modules\@angular\compiler-cli\src\codegen.js:50:54)
    at CodeGenerator.readFileMetadata (C:\Users\richa\Prosjekt\phono-frontend\node_modules\@angular\compiler-cli\src\codegen.js:63:13)
    at C:\Users\richa\Prosjekt\phono-frontend\node_modules\@angular\compiler-cli\src\codegen.js:91:74
    at Array.map (native)
    at CodeGenerator.codegen (C:\Users\richa\Prosjekt\phono-frontend\node_modules\@angular\compiler-cli\src\codegen.js:91:35)
    at codegen (C:\Users\richa\Prosjekt\phono-frontend\node_modules\@angular\compiler-cli\src\main.js:7:69)
    at Object.main (C:\Users\richa\Prosjekt\phono-frontend\node_modules\@angular\tsc-wrapped\src\main.js:25:16)
Compilation failed

It complains about my AuthConfig factory in my AppModule:

import { NgModule }       from '@angular/core';
import { BrowserModule  } from '@angular/platform-browser';
import { AppComponent }   from './app.component';
import {appRoutes} from "./app.routes";
import {LoggedInGuard} from "./Security/logged-in.guard";
import {AUTH_PROVIDERS, AuthHttp, AuthConfig, JwtHelper} from "angular2-jwt/angular2-jwt";
import {HttpModule} from "@angular/http";
import { FormsModule} from "@angular/forms";
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
import {DashboardModule} from "./dashboard/dashboard.module";
import {LandingpageComponent} from "./landingpage/landingpage.component";
import {Routes, RouterModule} from "@angular/router";
import {AuthService} from "./Security/auth.service";
import {NgFor, NgIf} from "@angular/common";

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

@NgModule({
    declarations: [AppComponent],
    imports:      [
        BrowserModule,
        HttpModule,
        NgbModule,
        FormsModule,
        DashboardModule,
        RouterModule.forRoot(routes)
    ],
    bootstrap:    [AppComponent],
    providers:    [
        LoggedInGuard,
        AUTH_PROVIDERS,
        JwtHelper,
        {
            provide: AuthConfig,
            useFactory: () => {
                return new AuthConfig({
                    tokenName: "auth_token",
                    headerName: 'Authorization',
                    headerPrefix: 'Bearer',
                    globalHeaders: [{'Content-Type':'application/json'}],
                    noJwtError: true,
                    noTokenScheme: true
                })
            }
        },
        AuthHttp,
        AuthService,
    ],
    directives: [NgFor, NgIf]
})
export class AppModule {}

(Running on Win10 Angular2.0.0@RC5)

@lpenet
Copy link

lpenet commented Aug 23, 2016

Same issue for me. This «Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function» makes it impossible to configure a custom provider such as in the following snippet :

@NgModule({
    declarations: [AppComponent,DelaisSchedule],
    imports:      [BrowserModule,
                   routing,
                   FormsModule,
                   ReactiveFormsModule,
                   HttpModule,
                   ButtonModule, CalendarModule, DataTableModule, DialogModule, GrowlModule, InputTextModule, TabViewModule, MenuModule],
    providers:    [new Provider(AuthenticatedHttp, {
                        useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => new AuthenticatedHttp(backend, defaultOptions),
                        deps: [XHRBackend, RequestOptions]
                    }),
                    APP_ROUTER_PROVIDERS,
                    DelaisLimitesService,
                    DroitsAccesService,
                    SyncService],
    bootstrap:    [AppComponent]
})

Or please indicate a workaround !

@chuckjaz
Copy link
Contributor

chuckjaz commented Aug 24, 2016

Calling functions or calling new is not supported in metadata when using AoT. This includes things like all the examples of above.

The work-around is to introduce an exported function to call such as changing the first example to,

export function loadCrisisCenter() {
  return require('es6-promise!./crisis-center/crisis-center.module')('CrisisCenterModule'));
}

export const crisisCenterRoutes: Routes = [
  {
    path: '',
    redirectTo: '/heroes',
    pathMatch: 'full'
  },
  {
    path: 'crisis-center',
    loadChildren: loadCrisisCenter
  }
];

@Richard87's example can be transformed into:

export function jwtHelperFactory() {
  return new AuthConfig({
    tokenName: "auth_token",
    headerName: 'Authorization',
    headerPrefix: 'Bearer',
    globalHeaders: [{'Content-Type':'application/json'}],
    noJwtError: true,
    noTokenScheme: true
  });
}

@NgModule({
    declarations: [AppComponent],
    imports:      [
        BrowserModule,
        HttpModule,
        NgbModule,
        FormsModule,
        DashboardModule,
        RouterModule.forRoot(routes)
    ],
    bootstrap:    [AppComponent],
    providers:    [
        LoggedInGuard,
        AUTH_PROVIDERS,
        JwtHelper,
        {
            provide: AuthConfig,
            useFactory: jwtHelperFactory
        },
        AuthHttp,
        AuthService,
    ],
})
export class AppModule {}

@lpenet's example can be transformed into:

export function authenticationFactory(backend: XHRBackend, defaultOptions: RequestOptions) {
 return new AuthenticatedHttp(backend, defaultOptions);
}

@NgModule({
    declarations: [AppComponent,DelaisSchedule],
    imports:      [BrowserModule,
                   routing,
                   FormsModule,
                   ReactiveFormsModule,
                   HttpModule,
                   ButtonModule, CalendarModule, DataTableModule, DialogModule, GrowlModule, InputTextModule, TabViewModule, MenuModule],
    providers:    [{provider: AuthenticatedHttp, 
                        useFactory: authenticationFactor,
                        deps: [XHRBackend, RequestOptions]
                    },
                    APP_ROUTER_PROVIDERS,
                    DelaisLimitesService,
                    DroitsAccesService,
                    SyncService],
    bootstrap:    [AppComponent]
})

The reason for this limitation is that the AoT compiler needs to generate the code that calls the factory and there is no way to import a lambda from a module, you can only import an exported symbol.

@Richard87
Copy link

Richard87 commented Aug 24, 2016

Great! Looking forward to try it out! Tested, and solves that problem, no over to the next on :D

@marcalj
Copy link

marcalj commented Aug 25, 2016

@chuckjaz What about using forwardRef?

...
export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule));

@NgModule({...})
class AppModule {}

Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol AppModule ...

Thanks!

EDITED: I have problems putting upgradeAdapter.upgradeNg1Component('...') inside decorator.

@marcalj
Copy link

marcalj commented Aug 25, 2016

Ok, cannot use export const ng1Component = upgradeAdapter.upgradeNg1Component('ng1Component'); with ngc...

Any suggestions? Thanks!

@chuckjaz
Copy link
Contributor

Since it depends on how this is used can you send a more complete example.

@alwayrun
Copy link

AoT compilation fails when using a function with loadChildren

import { Routes } from '@angular/router';

import { HomeRoutes } from './+home/home.routes';

declare const System: any;
export const lazyload: Type = (a: Function) => a;

export const routes: Routes = [
  ...HomeRoutes,
  { 
    path: 'about', 
    loadChildren: lazyload( () => System.import('./+about/about.module').then((r: any) => r.AboutModule) ),
  }
];
ngc -p ./tsconfig.aot.json

Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function (position 12:28 in the original .ts file), resolving symbol routes in /Users/webioix/workspace/code/angular2-aot/src/app.routes.ts, resolving symbol MainModule in /Users/webioix/workspace/code/angular2-aot/src/main.ts, resolving symbol MainModule in /Users/webioix/workspace/code/angular2-aot/src/main.ts
    at simplifyInContext (/Users/webioix/workspace/code/angular2-aot/node_modules/@angular/compiler-cli/src/static_reflector.js:463:23)
    at StaticReflector.simplify (/Users/webioix/workspace/code/angular2-aot/node_modules/@angular/compiler-cli/src/static_reflector.js:466:22)
    at StaticReflector.annotations (/Users/webioix/workspace/code/angular2-aot/node_modules/@angular/compiler-cli/src/static_reflector.js:52:36)

@marcalj
Copy link

marcalj commented Aug 26, 2016

tsconfig.json

{
    "compilerOptions": {
        "module": "system",
        "target": "es5",
        "moduleResolution": "node",
        "sourceMap": true,
        "declaration": true,
        "removeComments": false,
        "noImplicitReturns": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
//        "noImplicitAny": true,
        "suppressImplicitAnyIndexErrors": true
    },
    "files": [
        "typings/index.d.ts",
        "app/scripts/app.help.ts"
    ],
    "exclude": [
        "node_modules",
        "node_modules-clipping1",
        "bower_components",
        "typings/main.d.ts",
        "typings/main"
    ],
    "angularCompilerOptions": {
        "genDir": ".tmp/scripts/",
        "debug": true
    }
}

Main file loaded by SystemJS
app.ts

import dashboardMain from './modules/dashboard.main'; // app Ng1 modules

// Angular 2
import { upgradeAdapter } from './core/websays-dashboard.module'; // main Ng2 app module

import { Conversation } from './services/conversation'; // Import Ng1 services and components

angular.module('dashboardApp')
    .factory('Conversation', upgradeAdapter.downgradeNg2Provider(Conversation))
    .directive('dashboardSectionClippings',
       <angular.IDirectiveFactory>upgradeAdapter.downgradeNg2Component(DashboardSectionClippingsComponent));

import './core/upgrade_config'; // Upgrade Ng1 services

angular.element(document).ready(function () {
    upgradeAdapter.bootstrap(document.body, [dashboardMain.name]);
});

upgrade_config.ts

import {upgradeAdapter} from './websays-dashboard.module';

upgradeAdapter.upgradeNg1Provider('$filter');
upgradeAdapter.upgradeNg1Provider('$http');
...

websays-dashboard.module.ts (main Ng2 app module)

import { NgModule, forwardRef, Type } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UpgradeAdapter } from '@angular/upgrade';
import { HttpModule } from '@angular/http';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TOOLTIP_DIRECTIVES, DROPDOWN_DIRECTIVES } from 'ng2-bootstrap';

import { Conversation } from '../services/conversation';
import { ContextualHelpKeyDirective } from './contextual-help-key.directive';
import { TranslateNG1Pipe } from './translate-ng1.pipe';
import { InfiniteScroll } from 'angular2-infinite-scroll';
import { ChartFacetAuthorComponent } from './chart-facet-author.component';

export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => WebsaysDashboardModule));

@NgModule({
    imports: [CommonModule/*, MdTooltipModule*/],
    declarations: [TOOLTIP_DIRECTIVES, DROPDOWN_DIRECTIVES],
    exports: [TOOLTIP_DIRECTIVES, DROPDOWN_DIRECTIVES]
})
export class WebsaysDashboardUIThirdPartyModule {
}

// NOTE AoT doesn't like functions executed inside decorators (OK, doesn't like this way neither...)
export const dashboardClippingDateEditable:Type = upgradeAdapter.upgradeNg1Component('dashboardClippingDateEditable');

@NgModule({
    imports: [CommonModule, HttpModule, BrowserModule, FormsModule, ReactiveFormsModule,
        WebsaysDashboardUIThirdPartyModule],
    declarations: [
       ContextualHelpKeyDirective, TranslateNG1Pipe, InfiniteScroll, ChartFacetAuthorComponent

        // upgradeAdapter.upgradeNg1Component('...')
        dashboardClippingDateEditable],
    providers: [Conversation]
})
export class WebsaysDashboardModule {
}

@chuckjaz
Copy link
Contributor

chuckjaz commented Aug 26, 2016

The information recorded in annotations is translated into code by the AoT compiler and any references made in the annotations must be to simple exported symbols so having inline lambda or call is not supported because there is no way to extract the code in a way we can generate it correctly in another context.

The error you received is trying to communicate that you ran into one of the unsupported scenario. The key part of the error is Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function (position 12:28 in the original .ts file).

Consider changing your code to something like:

export function loadAboutModule() {
  return System.import('./+about/about.module').then((r: any) => r.AboutModule);
}

export const routes: Routes = [
  HomeRoutes,
  { 
    path: 'about', 
    loadChildren: loadAboutModule
  }
];

@marcalj
Copy link

marcalj commented Aug 29, 2016

@chuckjaz I'm not using ng2 router (using old ng1 router) and I'm not executing any function on any annotation (as far as I know), as you can see in code example.

@guojenman
Copy link

guojenman commented Sep 2, 2016

@chuckjaz I've created a bare bone project that reproduces the problem @marcalj and mysef are having.

All this project contains are, 1 ng2 component, 1 ng1 (ngUpgraded) component, and 1 module. Nothing more.

npm run tsc (works)
npm run ngc (does not work)

ngc throws the error that @marcalj posted above

Attached sample project:
ng2bad-build.zip

The problem is as @marcalj indicated, including the return value from upgradeNg1Component in the module declarations prevents ngc from compiling.

Also, should this bug be re-opened or we need to start a new bug?

@chuckjaz
Copy link
Contributor

chuckjaz commented Sep 2, 2016

Please start another issue as this is the same error arrived at in a different scenario.

It is confusing to have an issue whose title and initial description is about using the router with AoT turn into an issue discussing using the UpgradeAdapter with AoT. If this gets resolved, which issue was resolved?

@arandehkharghani
Copy link

arandehkharghani commented Sep 21, 2016

re chuckjaz's suggestion I can say that the solution shouldn't be updating the source code to get it to work with AOT, because this defeats the statement made by Angular team in link
One of the benefits of the introduction of NgModules is that your code does not have to change based on whether you’re running in AoT or just in time (JiT) mode

do this:
npm install typescript@next --save
typescript@next===typescript 2.1.0
and then change your gulp file to this:
let tsProject = ts.createProject('tsconfig.json', { typescript: require('typescript')});
and then update/create your tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
"files": [
"app/app.module.ts",
"app/main.ts",
"./typings/index.d.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit": false
}
}
and try running your ngc -p "path to the tsconfig"

@chuckjaz
Copy link
Contributor

@arandehkharghani The statement was intended to imply that there is a large set of code that works in both without modification. It was not intended to imply that all code the works with JIT will work with AoT without modification. Once you have code that works in AoT you can use that same code in JIT without modification; the inverse is not true.

@sosnet
Copy link

sosnet commented Oct 3, 2016

Hi, I'm on Ionic2 and I'm getting the same error:

ngc error: Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol AppModule in ./.tmp/app/app.module.ts, resolving symbol AppModule in ./.tmp/app/app.module.ts

My code looks like this:

...
import { InMemoryWebApiModule } from 'angular2-in-memory-web-api';
import { InMemoryDataService }  from '../in-memory-data.service';
...
@NgModule({
    imports: [
        IonicModule.forRoot(MyApp),
        InMemoryWebApiModule.forRoot(InMemoryDataService) <--- this line throws the error
    ]
...

Any ideas? Thank you

@chuckjaz
Copy link
Contributor

chuckjaz commented Oct 3, 2016

Most likely it is because forRoot is too complicated to evaluate statically. What is the implementation of forRoot?

@brandonroberts
Copy link
Contributor Author

@sosnet you need the latest version of the angular-in-memory-web-api (the name has changed) that supports AoT.

https://github.com/angular/in-memory-web-api

@sosnet
Copy link

sosnet commented Oct 4, 2016

@brandonroberts hm, that could be the solution, unluckily the newest version throws a really strange error for me when I use it with ionic2: angular/in-memory-web-api#42

@chuckjaz I have no idea, It's from the angular2-tutorial..

@simetin
Copy link

simetin commented Oct 25, 2016

@sosnet Did you found a solution ? I have a similar problem.

@sosnet
Copy link

sosnet commented Nov 3, 2016

Sorry @tchinou1, haven't seen your question.
There is a workaround here: angular/in-memory-web-api#42 (comment)

@samiheikki
Copy link

Hi, I'm using angular2-polymer module and I'm getting the same error:

Error: Error encountered resolving symbol values statically. Calling function 'PolymerElement', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function

My code looks like this:

...
import { PolymerElement } from '@vaadin/angular2-polymer';
...
@NgModule({
  imports: [
    BrowserModule,
    routing
  ],
  declarations: [
    AppComponent,
    HeroesComponent,
    HeroDetailComponent,
    PolymerElement('app-header-layout') // fails
  ],
  providers: [
    HeroService,
    appRoutingProviders
  ],
  bootstrap: [ AppComponent ],
  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class AppModule { }

Any ideas? Thank you

@DzmitryShylovich
Copy link
Contributor

@samiheikki you cannot call functions in metadata. your code should be statically analizable

@Majorhe
Copy link

Majorhe commented Nov 24, 2016

@chuckjaz export a function then reference this function name is ok in providers, routes, and decarations but not ok in @component metadata, Do you have any good solution? thanks

My code as follow:
...
import { CustomAnimationsService } from '../shared/services/custom-animations.service';
...
export function customAnimations() {
let animations = new CustomAnimationsService();
return animations.getAnimations();
}
@component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css'],
animations: customAnimations()
})
export class TestComponent implements OnInit {
...
}

@chuckjaz
Copy link
Contributor

chuckjaz commented Jan 10, 2017

@jaonhe We support very limited the source evaluation to statically produce metadata, we only support what I call macro functions are pretty simplistic in what they support, they can only be a simple return statement and only contain expressions we otherwise support. I am working on improving the documentation around this as well as improving the error messages.

The first step is to change your function to be able be evaluated by the metadata collector,

export function customAnimations() {
  return new CustomAnimationsService().getAnimations();
}

This, unfortunately, will not help because CustomAnimationService is not one of the types known by the static reflector and it will complain that CustomAnimationService is a call it cannot resolve.

This style of specifying animations will only work in JIT and will need to be re-organized to work with AOT.

@robert-cahoon
Copy link

Hi,

I'm very new to Angular 2 development and I have been working through the Angular 2 Tour of Heroes tutorial replacing the angular2-in-memory-web-api with the Angular 2 MockBackend working in Visual Studio Code.

Once completed I found that running "ng serve" in the VS Code terminal resulted in the error noted above, i.e. "Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function..." webpack: failed to compile.

After reviewing your comments above I realised the problem was a lambda function used in the useFactory metadata for MocBackend. I was able to export the function and the error disappeared.

The odd thing was that when the problem first appeared, before I fixed it by exporting the function, I noticed something odd that I don't understand. Once I ran "ng serve" in the VS code terminal and it failed, if I then opened and saved any .ts file, it kicked off an automatic build which then ran without error. Each successive automatic build after that ran without error. I understand that the typescript file watcher probably kicked off the build but why would those automatic builds succeed and a manual "ng serve" fail?

Cheers,

Rob C.

@rayer4u
Copy link

rayer4u commented Feb 27, 2017

Hi,
@chuckjaz .How to deal with 'new Class' situation in AOT. as 273

import { StoreModule } from '@ngrx/store';

imports: [StoreModule.provideStore(reducer, { user: new User() }), ...]

relate key code

    StoreModule.provideStore = function (_reducer, _initialState) {
        return {
            ngModule: StoreModule,
            providers: provideStore(_reducer, _initialState)
        };
    };

export function provideStore(_reducer, _initialState) {
    return [
        Dispatcher,
        { provide: Store, useFactory: _storeFactory, deps: [Dispatcher, Reducer, State] },
        { provide: Reducer, useFactory: _reducerFactory, deps: [Dispatcher, INITIAL_REDUCER] },
        { provide: State, useFactory: _stateFactory, deps: [INITIAL_STATE, Dispatcher, Reducer] },
        { provide: INITIAL_REDUCER, useFactory: _initialReducerFactory, deps: [_INITIAL_REDUCER] },
        { provide: INITIAL_STATE, useFactory: _initialStateFactory, deps: [_INITIAL_STATE, INITIAL_REDUCER] },
        { provide: _INITIAL_STATE, useValue: _initialState },
        { provide: _INITIAL_REDUCER, useValue: _reducer }
    ];
}

export interface ValueProvider {
    /**
     * An injection token. (Typically an instance of `Type` or `OpaqueToken`, but can be `any`).
     */
    provide: any;
    /**
     * The value to inject.
     */
    useValue: any;
    /**
     * If true, then injector returns an array of instances. This is useful to allow multiple
     * providers spread across many files to provide configuration information to a common token.
     *
     * ### Example
     *
     * {@example core/di/ts/provider_spec.ts region='MultiProviderAspect'}
     */
    multi?: boolean;
}

@chuckjaz
Copy link
Contributor

You need to use useFactory and provide a function that returns the value you wish to use instead of using useValue.

@larssn
Copy link

larssn commented Jul 25, 2017

The odd thing was that when the problem first appeared, before I fixed it by exporting the function, I noticed something odd that I don't understand. Once I ran "ng serve" in the VS code terminal and it failed, if I then opened and saved any .ts file, it kicked off an automatic build which then ran without error.

@robert-cahoon I've noticed the same thing (Angular 4.3.1). Wondering if it is a bug.

@tatsujb
Copy link

tatsujb commented Feb 15, 2018

@chuckjaz Hi

what about when you create a browser animation :

import {sequence, trigger, animate, style, group, query as q, transition, animateChild} from '@angular/animations';
const query = (s,a,o={optional:true})=>q(s,a,o);

export const slideLeft = trigger('slideLeft', [
  transition('* => *', [
    query(':enter, :leave', style({ position: 'fixed', width:'100%' })),
    query(':enter', style({ transform: 'translateX(100%)' })),
    sequence([
      query(':leave', animateChild()),
      group([
        query(':leave', [
          style({ transform: 'translateX(0%)' }),
          animate('1s cubic-bezier(.86,.01,.27,1)',
            style({ transform: 'translateX(-100%)' }))
        ]),
        query(':enter', [
          style({ transform: 'translateX(100%)' }),
          animate('1s cubic-bezier(.86,.01,.27,1)',
            style({ transform: 'translateX(0%)' })),
        ]),
      ]),
      query(':enter', animateChild()),
    ])
  ])
]);

the component that loads it :

import {Component, OnInit} from '@angular/core';
import {slideLeft} from '../../../../assets/animations/router.animations';
import {Router} from '@angular/router';

@Component({
  selector: 'app-routing',
  templateUrl: './routing.component.html',
  styleUrls: ['./routing.component.scss'],
  animations: [slideLeft]
})
export class RoutingComponent implements OnInit {

  router:Router;

  constructor() {}

  ngOnInit() {}

  getState(outlet) {
    return outlet.activatedRouteData.state;
  }

}

on ng b -prod I get :

 ERROR in app\logged-in\content\routing\routing.component.ts(9,16): Error during template compile of 'RoutingComponent'
[ERROR]   Function expressions are not supported in decorators in 'slideLeft'
[ERROR]     'slideLeft' references 'ɵ0'
[ERROR]       'ɵ0' contains the error at assets\animations\router.animations.ts(2,15)
[ERROR]         Consider changing the function expression into an exported function.

I don't see a case above that applies to me.

@ngolforoushan
Copy link

@chuckjaz thanks for your greate post. your post fixed my problem.
I don't know why should be that much difference between dev and production (AOT). ( I know why but should be margin limited to minimum).

@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 Sep 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests