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

@select + AoT + Angular CLI === sadness #236

Closed
SethDavenport opened this issue Oct 24, 2016 · 29 comments
Closed

@select + AoT + Angular CLI === sadness #236

SethDavenport opened this issue Oct 24, 2016 · 29 comments

Comments

@SethDavenport
Copy link
Member

SethDavenport commented Oct 24, 2016

When you run in JIT mode, it works fine. When you run code using @select in AoT mode, it just turns into a no-op.

Looking at the output suggests that the decorator code is simply missing after transpilation.

@SethDavenport
Copy link
Member Author

SethDavenport commented Oct 24, 2016

@clbond did some experiments with angular-cli's AoT integration and found this: https://github.com/angular/angular-cli/blob/master/packages/webpack/src/loader.ts#L19

This code appears to be stripping all decorators out of the AST (!)

@SethDavenport
Copy link
Member Author

Apparently commenting out those lines in the cli's loader causes ng2-redux's @select to work just fine again.

@SethDavenport
Copy link
Member Author

Once #234 is fixed I'll put together a sample repo and file a bug with the CLI team asking for more context about this code.

Meanwhile, we're checking to see if it works with raw ngc.

@SethDavenport
Copy link
Member Author

With some hacks to workaround #234 and #235 we were able to get @select working with a raw ngc (non CLI) compile. So it looks like this is specific to the angular CLI's webpack loader.

@SethDavenport
Copy link
Member Author

SethDavenport commented Oct 24, 2016

angular/angular-cli#2799

@SethDavenport SethDavenport changed the title @select + AoT === sadness @select + AoT + Angular CLI === sadness Oct 24, 2016
@NeoLSN
Copy link

NeoLSN commented Nov 8, 2016

When I tried to use @select(state => state.value) private property, I got
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

Is this issue investigating that kind of error?

@SethDavenport
Copy link
Member Author

SethDavenport commented Nov 8, 2016

Nope - that's an AoT limitation with anonymous functions. You'll need to do either:

// Baby-sit AoT's limitations with anonymous functions and needing things to be
// exported.
export function selectValue(s) { return s.value; }; 

// ...

@select(selectValue) value

or

// Looks for a property on state called 'value'
@select('value') property;

or even

// Infers state.value from the property name
@select() value;

@SethDavenport
Copy link
Member Author

In general, AoT has a lot of non-obvious limitations with what TypeScript constructs can be used at the boundary of NgModules. Documentation has also been lacking. The best resource I know of right now is some experiments being conducted by my work colleagues as they migrate some larger codebases to AoT.

https://github.com/rangle/angular-2-aot-sandbox

@fiznool
Copy link

fiznool commented Nov 17, 2016

@SethDavenport would you mind sharing how you managed to get your custom decorator @select to work with an AOT build?

I'm trying to use ngrx/effects in my Ionic 2 app. Ionic 2 does not use the angular-cli, instead it uses ngc directly when it builds an app for production. Therefore, it shouldn't be prone to the issue in the angular-cli webpack loader, which strips out all custom decorators.

Instead, I think we're coming up against this section in the angular compiler codebase which appears to only allow a whitelist of decorators.

Did you find a way of getting around this?

@SethDavenport
Copy link
Member Author

Hi @fiznool - I can't speak for that piece of code you linked: I'm aware of it but I'm not clear of when during AoT it gets invoked.

That said, my colleagues have put together a set of test repos in an attempt to flush out AoT's "hidden gems" :)

@SethDavenport
Copy link
Member Author

Their tests seem to indicate that both ngrx's @Effect and our @select can be made to work with raw ngc.

@SethDavenport
Copy link
Member Author

@SethDavenport
Copy link
Member Author

Take a look, hopefully that will shed some light on it?

@fiznool
Copy link

fiznool commented Nov 21, 2016

@SethDavenport thanks! Looks like a great resource. I'll try to add an explicit test for ngrx/effects soon, just to confirm that it will indeed work - but as you've indicated it certainly should do, therefore I need to try and figure out how to get this working with Ionic 😄

@SethDavenport
Copy link
Member Author

@select appears to work now with Angular CLI beta.24.

@belafarinrod91
Copy link

Hey @SethDavenport,

I am getting the same issue as @NeoLSN mentioned: ERROR in 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 15:11 in the original .ts file), resolving symbol when trying to build my project with AoT.

I am using angular-cli 1.0.0 and Angular 4.0.2 - are you aware of this already ?

Thanks !

@SethDavenport
Copy link
Member Author

Can you share the line of code that's triggering the error?

@belafarinrod91
Copy link

belafarinrod91 commented Apr 27, 2017

Hi @SethDavenport,

thanks for your response. This is the line, which is triggering the error @select(appStore => appStore.base.id) routeId$: Observable<number>;. I am triggering the build with ng build --aot and I am using the latest version of angular-redux/store (6.2.0).

(If I remove the line, the select decorators from the other components are triggering the same error).

@wmarques
Copy link

wmarques commented May 3, 2017

@SethDavenport
Hi, I'm facing the same error with angular cli 1.0 and Angular 4.
If I disable the aot by doing --aot=false everything works fine.

@SethDavenport
Copy link
Member Author

SethDavenport commented May 4, 2017

This is a known limitation of the AoT compiler. It's not very good with inline arrow functions in certain cases.

Instead, try this:

export function selectBaseId(appstore) {
  return appStore.base.id;
}

class YourClass {
  // ...
  @select(selectBaseId) routeId$: Observable<number>;
}

@SethDavenport
Copy link
Member Author

SethDavenport commented May 4, 2017

Alternately, for a simple selector like this you can do:

export function selectBaseId(appstore) {
  return appStore.base.id;
}

class YourClass {
  // ...
  @select(['base', 'id']) routeId$: Observable<number>;
}

Apart from being more succinct, it will also not explode if base is undefined or null.

@belafarinrod91
Copy link

Thanks, @SethDavenport ! It's now working when using @select(['base', 'id']) routeId$: Observable<number>; !

@rightisleft
Copy link

rightisleft commented Jun 12, 2017

The need to declare an entire secondary function just to use DI is is a pretty heavy work around ...

@SethDavenport
Copy link
Member Author

This is not related to DI. This is a limitation of angular's AoT compiler.

@rightisleft
Copy link

@SethDavenport is there anything on the angular-cli roadmap? The syntax is pretty gnarly.

@SethDavenport
Copy link
Member Author

I can't comment on the Angular team's plans unfortunately. However there are a few things you can already do with @select that might help. For example, if your selector function is simply of the form state => state.propName, you can pass a string to @select:

// shorthand for @select(state => state.propName), but AoT-safe
@select('propName') propName$;

Alternately, if your selector is a property path (e.g. state => state.foo.bar) you can specify a PathSelector:

// shorthand for @select(state => state.foo.bar), but AoT-safe
@select(['foo', 'bar']) fooBar$;

If you're doing anything much more complex than this, it's likely to be something that should be separated out and unit tested anyway.

@rightisleft
Copy link

I feel ya, but both of those use string properties which is not typesafe and wont play nicely with either VSCode or WebStorm tooling.

@SethDavenport
Copy link
Member Author

I use vscode all the time without issues. If you're wanting to enforce that those paths conform to the store, then use a function selector. Again, most people keep their function selectors in a separate file for a number of reasons:

  • AoT support
  • Unit testability
  • The ability to enhance them with things like reselect (memoization) etc.

There are lots of different programming styles, and lots of levels to which typing is enforced. That's why we support a few different syntaxes. Some people want everything to be typesafe to the nth degree. They tend to use exported function selectors or ngRedux.select().

There are people who are comfortable with property or path selectors because they are super declarative, and that matters more to them than enforcing types 100% of the time.

Would I prefer that Angular's AoT compiler get comfortable with lambdas? Yes I would. But it's not my call.

@rightisleft
Copy link

Well said @SethDavenport - i moved the ticket over to the Angular-CLI team. I'll probably end up using ngRedux.select() as a stop gap. There are other projects that suffer from this same compilation issue ( TypeORM )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants