angular-redux/store

Beta 6, AoT possible issue?

spock123 opened this issue · 24 comments

Hi there,
I'm playing with Beta6 and AoT compilation.

I'm not sure what the problem is, but AoT throws an error as soon as I add the NgReduxModule.forRoot() method.

Only code I have in my app is that line.. and the AoE throws the following 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

Any ideas, guys?

I'm not doing anything other than importing the module - I*m not even configuring it.. doing step by step to make sure which line creates the error.

I also found this issue.

Can confirm, same problem here.
Coming from a working AOT build with 4.0.0-aotbeta.3

If you are not using an @select decorator - you should be able to. Currently the decorators don't play well with AoT, and still looking for a solution, but may just be a limitation of the compiler.

If you have a component / app that is throwing an error that is't using @select can you point me to an example?

The potential bug ist visible in our company starter project:

https://bitbucket.org/DcsMarcRemolt/dcs-angular2-starter/branch/ng2-redux-issue-234

The master ist still on aotbeta.3 and works, the branch I linked above is on beta.6 and there I get the error. The only difference is the package version and the necessary code changes (.forRoot()).

The project does not yet use a select decorator, as this is our empty starting point for coding a2 apps.

Tested with:

  • node 6.9.1
  • npm 3.10.8
  • package versions are hardcoded (no ^ or ~)

Steps to reproduce:

  • git checkout master
  • npm install
  • npm run ngc

Works

  • git checkout ng2-redux-issue-234
  • npm install
  • npm run ngc

Breaks with mentioned error

As @DcsMarcRemolt says, it doesn't take much to replicate it.
You don't have to create a store, you don't have to configure a store.

It's enough to import the Ng2ReduxModule and call the .forRoot() method.

Thanks for providing a test repo. Let me take a look.

@e-schultz I can reproduce the issue with @DcsMarcRemolt's repo. The NgReduxModule.forRoot() is indeed what's triggering it; commenting out that line makes the error go away.

I think the forRoot function itself needs to be explicitly exported?

Anyway all, we have a few issues related to AoT right now. AoT brings a lot of (presently undocumented) limitations to what TypeScript constructs you can use as exports from your NgModules and this has blindsided us a bit.

Rest assured this is high on the priority list. For now I suggest working in JIT mode instead until we get things sorted out.

Think I found the source of the issue, and I'll try and get a fix out tonight. Basically

  • index.metadata.json was not being generated

This is because I was doing

@NgModule({})
class MyModule { }

export {
MyModule,
OtherStuff }

when exporting like that, the metadata doesn't seem to get generated.

Changing it to:

@NgModule({})
export class MyModule { }
export {
OtherStuff 
}

then the metadata gets generated properly.

I will try and get a fix/publish out for this later today

@spock123 just published 4.0.0-beta.7 and tried running your starter repo with it (build:prod / serve:prod) - and was able to get it running w/o spitting up errors.

Let me know if it's working for you - thanks for your patience.

@e-schultz Thank you so much for your effort, it's super appreciated.

So a bit of progress:

  • the compiler now runs without throwing any errors.
  • however, when webpack tries to build, it does build but throws this error:
ERROR in [default] /Users/spock/projects/angular2-webpack2-typescript2/compiled/src/frontend/app/app.module.ngfactory.ts:175:14 
Generic type 'NgRedux<RootState>' requires 1 type argument(s).

Is it something I did wrong?

Btw I updated my starter repo. Replication:

// Install dependencies
npm install

// Compile 
npm run aot

// Compile and build
npm run build-aot

@DcsMarcRemolt I verified ng2-redux@4.0.0-beta.7 with your repo and it appears to be working now. Btw, you should also update to rxjs@5.0.0-beta.12 to resolve some npm peer dependency warnings.

@spock123 I'm assuming you're talking about a different starter repo? Is it something you can share so I can take a look?

One thing I have noticed when using generics in a constructor - first run of ngc is fine, but if you leave the .ngfactory.ts artifacts around and run ngc again - then it complains with that error.

try removing the ngfactory files and running the build - and does it work?
then try running it again - that is when the error happens (at least for me)

Unfortunately that didn't change anything for me, sorry.

@e-schultz so I now managed to get it to work by providing the workaround @NeoLSN used, by extending NgRedux, and "provide" that new class instead of NgRedux (see @#228)

@spock123 when injecting NgRedux into your components/services, does

export class SomeClass {
    constructor(ngRedux: NgRedux <any> ) {}
}

work? might be simpler than needing to create a wrapper-work around that accomplishes the same.

I have a feeling this might be a limitation of AoT, but has me wondering if you could then do ... (thinking out loud, will try and experiment tonight)

export class SomeClass {
    private _store: NgRedux <AppState> ;
    constructor(ngRedux: NgRedux <any> ) {
        this._store = ngRedux as NgRedux<AppState>
    }

    ngOnInit() {
        this.stuff = this._store.select( /* back to getting a strongly typed store */ )
    }
}

Not ideal, but if AoT is having issues with injecting generics as parameters - might be a limitation we need to deal with until the compiler is updated to accommodate it.

There is issue #12262 on the angular issue tracker talking a bit about this.

@e-schultz
I just tested and it works! Both @select and injecting the store and using store.select()

My setup:

Webpack: 2.1.0-beta.22
Node: 6.3.0
Angular: 2.1.1
Ng2Redux: 4.0.0-beta.7

Repo:
https://github.com/spock123/angular2-webpack2-typescript2

Extend NgRedux:

import { Injectable } from '@angular/core';
import { NgRedux } from 'ng2-redux';

@Injectable()
export class _NgRedux extends NgRedux<any> {
    constructor(){
        super();
    }
}

Import this extended class in the app module:

import { _NgRedux }    from './store/extended-class';
import { NgRedux } from 'ng2-redux';

In the app module, use provide() so all references to NgRedux will now get this extended class instead:

let providers = [
{ provide: NgRedux, useClass: _NgRedux },
 ... other providers in your app
];

....

@NgModule({

     imports: [
        NgReduxModule.forRoot(),
        other modules....
    ],

    declarations: [
        bla bla bal
    ],

    providers: providers,
    bootstrap:    [ AppComponent ]
})

export class AppModule{
   // Initialize redux store in the constructor

}

Compile, build and serve the app: (localhost: 8080)

npm install && npm run build-aot && npm run serve:dist

PS: the build generates Serviceworker also, so make sure to remove it in chrome devtools (under application) after...

@e-schultz

I just import the store as usual in my components:

import { NgRedux, IAppState, select } from 'my-store-bundle';
import { Observable } from 'rxjs/Observable';

export class SomeClass {

   @select('whatever') whatever$: Observable<any>;

constructor(ngRedux: NgRedux <IAppState> ) {}

    ngOnInit() {
        // Nothing to see here.. 
       //  Not using the injected store, but we could use this.ngRedux.select() here
    }
}

@spock123
Do you mean my work around also can let the @select() work?

@NeoLSN the @select thing is actually specific to angular-CLI's implementation of AoT. They're working on it, see #236

If you're not using angular-cli, but instead using ngc directly, then the decorator works fine.

@SethDavenport
Oh, I see.

I think this issue can be closed now