Angular-cli: Custom decorators are stripped when using the AoT build flag

Created on 20 Oct 2016  路  39Comments  路  Source: angular/angular-cli

OS?

Mac OSX Sierra

Versions.

angular-cli: 1.0.0-beta.17
node: 6.2.1
os: darwin x64

Repro steps.

  1. Clone @ngrx/example-app
  2. Compile the project using the --aot flag
  3. Check the compiled copy of either effect service
  4. Note that the @Effect() decorator from @ngrx/effects has been stripped from the classes

    The log given by the failure.

No errors are thrown

2 (required)

Most helpful comment

This issue should be top priority as it makes larger apps (which usually have some custom decorators in place) impossible to compile ahead of time. And the larger the app is (the more components it has), the longer time the JIT takes. This results in terrible performance and makes angular2 quite problematic to be used in production. I would really appreciate any short-term fix. While tree shaking is nice (and I understand the reasons for decorator stripping), I would gladly accept not having it for some time if that means I am able to do AoT at the moment.

All 39 comments

I'd like to see this resolved. AoT is great, but custom decorators will be important in the future as more and more third party modules take advantage of the stable API, unlike the current crop out there which tend to be developed on the RCs.

The problem is this needs to be fixed over in Angular 2, not here. @clydin pointed out this issue specifically is in the webpack loader, however there are also issues with decorators in the compiler.
The compiler itself takes a static list of decorators and those are the only decorators that can be AoT compiled.

The custom webpack loader is what is doing the actual decorator removal: https://github.com/angular/angular-cli/blob/master/packages/webpack/src/loader.ts#L18

@MikeRyan52 thanks for raising this (and all the hard work on ngrx + effects to begin with).

I agree that is critical to be resolved. I guess the main reason, I have not hit it directly, yet, is that beta.17 with aot and lazy-loading was the initial constraint hitting.

I know, everyone on the angular-cli team is working hard, but the resolution of this issue should be most welcome.

We have the same thing with @select in the ng2-redux world. If you need more info or help let me know.

I think I saw this same failure mode in an example program that made use of a simple custom decorator. Unfortunately that code is long gone, I ascribed it to programmer error at the time - but once this issue is fixed I will certainly try again.

I see the exact same behavior in my application. I have a class with some method decorators:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

import { AuthService, AttributesResponse} from 'api-services';
import { ObservableAction } from 'andux';

@Injectable()
export class UserActions {
  constructor(
    private service: AuthService
  ) {}

  @ObservableAction()
  loadAttributes(): Observable<AttributesResponse> {
    return this.service.loadAttributes();
  }
  @ObservableAction()
  loadPermissions(): Observable<any> {
    return this.service.loadPermissions();
  }
}

When building the application with the AOT option, the decorator is being stripped out by the CLI but the build is a success. Then i run into runtime issues because of the decorator not being applied. The decorators are then also dropped because they are unused.

Dropping unused function ObservableAction [../~/andux/src/actions/observable-action.ts:3,0]
Dropping unused function PaginatableActions [../~/andux/src/actions/paginatable-actions.ts:1,0]
Dropping unused function SortableActions [../~/andux/src/actions/sortable-actions.ts:1,0]
Dropping unused function CrudReducer [../~/andux/src/reducers/crud-reducer.ts:5,0]
Dropping unused function PaginatableReducer [../~/andux/src/reducers/paginatable-reducer.ts:4,0]
Dropping unused function SortableReducer [../~/andux/src/reducers/sortable-reducer.ts:6,0]

We will have to wait for a proper fix as described here: https://github.com/angular/angular-cli/pull/2881

So I understand the tradeoff between tree shaking and allowing custom decorators. However my feeling is that if I have to choose between an optimization (tree shaking) vs. correctness in the code output (not stripping all decorators) I would be inclined to choose correctness first, while I work on re-enabling the optimization afterwards.

This is putting a few people in a fairly awkward position...

Sorry, I haven't commented on this issue and should have.

We will support custom decorators, this is a real issue, but the solution isn't as easy as it seems. There are a lot of performance implications, and build time is an important factor.

The current solution we're considering: dev build will not remove any decorators and as such will not tree shake properly. That's okay, it's dev. Prod builds will only remove decorators that are marked as annotations using tsickle. The prod builds will be slower (as slow as today), while the dev builds (where RTT is much more important) will be larger.

Again, this is what's being considered. The final solution might not be the same. For the time being I'll keep the code as is, but switching to tsickle will happen real soon.

ok thanks @hansl

This issue should be top priority as it makes larger apps (which usually have some custom decorators in place) impossible to compile ahead of time. And the larger the app is (the more components it has), the longer time the JIT takes. This results in terrible performance and makes angular2 quite problematic to be used in production. I would really appreciate any short-term fix. While tree shaking is nice (and I understand the reasons for decorator stripping), I would gladly accept not having it for some time if that means I am able to do AoT at the moment.

I couldn't agree more with @xaralis. We have a large application that actually uses a lot of custom decorators. We also have terrible performance using the JIT and are in the real need of AoT but since the decorators are stripped away we cannot use it... I don't get how this issue only can have priority 2, it should definitely have higher priority.

While we're waiting for fix, I've added temporary version of @ngtools/webpack that doesn't touch decorators: https://github.com/Polvista/ngtools-webpack-keep-decorators.

Usage is pretty easy:
npm install --save ngtools-webpack-keep-decorators
require('@ngtools/webpack') => require('ngtools-webpack-keep-decorators')
loaders: ['@ngtools/webpack'] => loaders: ['ngtools-webpack-keep-decorators']

How do I change because there is no webpack config in cli?
Pls help!

@sithwin it won't help if you use angular-cli to perform AOT compilation. However, decorators will work if you compile with webpack + ngtools-webpack-keep-decorators. It's just drop in replacement for @ngtools/webpack.

Since angular-cli beta-21, we can combine AOT and lazy loaded modules ! It took me some hours to improve my routes so they can be lazy loaded + being able to compile with aot flag.

Now, as I'm using ngrx/effects and it has @Effects decorator, I'm not able to use AOT (nothing happens).

Would it be possible with angular-cli to have a temporary flag like --keep-decorators so people who choose to build with AOT can (knowing that the build is probably going to be bigger) ? Just the time to figure out how to improve all of that ? It seems to be a much needed improvement according to this issue and the :+1:.

I had to deploy my app to production without AOT since I am using ngrx/effects. Eagerly waiting to resolve this issue.

@metanav I've made a fork of angular-cli thanks to @Polvista :
https://github.com/maxime1992/angular-cli.

This fork is not super clean and I'll not make a PR but it's something until the official release.

I tried it on my project and it works well ! =)

EDIT 1 :
How to use it :

cd some-folder-of-your-choice
npm uninstall -g angular-cli
git clone https://github.com/maxime1992/angular-cli.git
cd angular-cli
npm link

Then in your project

npm link angular-cli
ng serve --prod --aot

EDIT 2 :
Just for information :

  • main.bundle.js (build with --prod --aot) is now 250KB instead of 243KB
  • chunk.js (build with --prod --aot) is now 17.9 KB instead of 18.1 KB (it's even smaller, WTH !)

any news on this @hansl ?

Do you have any ETA for that functionality? as I have experienced the same problem and it would great to have that done.

Any updates on this would be very much appreciated, I'll try @maxime1992 fork in the meantime and/or try ngc to do my AoT builds instead. Thanks

@petercn I did try to rebase from the original repo and things got broken.
If you have some trouble to use it too, you should git checkout the (only) commit I've made.

There is an update tho :
image

@hansl is working on it and we'll probably have a fix in next release ! :)

Nice, thanks for the update @maxime1992

There is a new version of the cli (beta.23), anyone knows if the fix for this is in there?

@nirgn975 yes, a temporary fix via PR https://github.com/angular/angular-cli/pull/3583 is in while they implement a better permanent solution.

@Splaktar Great, thanks!
Do you know why beta.23 is not publish to npm yet?

Just tried again with beta.24 and this appears to be fixed?

Temporary fix. All decorators are kept but file sizes are now larger

ok cool, thanks.

Decorators are no longer being stripped.

Aren't they stripped again? I'm using custom decorator and it's being stripped on latest version of @ngtools/webpack
Can anyone confirm what's the current approach for custom decorators?
cc @Brocco

@KKrisu this is weird. Which version of cli / angular are you using ?

I don't have that problem (and I'm using ngrx/effects, custom decorators were stripped before but not anymore).

@KKrisu I suggest using https://github.com/shlomiassaf/ngc-webpack instead of @ngtools/webpack, it seems way much more mature/stable (at least in present).

Hey, @maxime1992 I'm on @ngtools/[email protected]
I have totally custom decorator built on our own. So the decorator body looks like this:

export function Embeddable(key: string) {
  return function(componentClass: Function) {
    // our custom code
  }
}

then in components

import { Embeddable } from '...';
@Embeddable('link')
@Component({
...

@xaralis thank you, I will consider this alternative if we have more problems, currently, this is the only one with the decorator.

Angular cli removes standart decorators. That does't worked at same times AOT and Jit.
How to disable deletion standart decorators?

@Brocco Just wonder when you say decorators are not striped, do you have fix number? It seems it stills removes them.
The standard angular ones. , I just need to keep @Input(), @Output(), nothing else.

I see in the code (ngtools):

 if (!plugin.skipCodeGeneration) {
                return Promise.resolve()
                    .then(() => _removeDecorators(refactor))
                    .then(() => _replaceBootstrap(plugin, refactor));
            }

Is this is the solution ?

Thank you,
Frank

Any news about this? As soon as i compile it with --prod my decorators are removed.

Can i keep them?

Even standard decorators are removed.
ng build --prod
Please remove the deletion

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._

Was this page helpful?
0 / 5 - 0 ratings