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

fix(core): Allow modification of lifecycle hooks any time before bootstrap #35464

Closed
wants to merge 2 commits into from

Conversation

mhevery
Copy link
Contributor

@mhevery mhevery commented Feb 15, 2020

Overview

Currently we read lifecycle hooks eagerly during ɵɵdefineComponent. The result is that it is not possible to do any sort of meta-programing such as mixins or adding lifecycle hooks using custom decorators since any such code executes after ɵɵdefineComponent has extracted the lifecycle hooks from the prototype. Additionally the behavior is inconsistent between AOT and JIT mode. In JIT mode overriding lifecycle hooks is possible because the whole ɵɵdefineComponent is placed in getter which is executed lazily. This is because JIT mode must compile a template which can be specified as templateURL and those we are waiting for its resolution.

Size tradeoffs

  • + ɵɵdefineComponent becomes smaller as it no longer needs to copy lifecycle hooks from prototype to ComponentDef
  • - ɵɵNgOnChangesFeature feature is now always included with the codebase as it is no longer tree shakable.

Perf tradeoffs

Previously we have read lifecycle hooks from prototype in the ɵɵdefineComponent so that lifecycle hook access would be monomorphic. This decision was made before we had T* data structures. By not reading the lifecycle hooks we are moving the megamorhic read form ɵɵdefineComponent to instructions. However, the reads happen on firstTemplatePass only and are subsequently cached in the T* data structures. The result is that the overall performance should be same (or slightly better as the intermediate ComponentDef has been removed)

Next steps

  • Remove ɵɵNgOnChangesFeature from compiler. (It will no longer be a feature.)
  • Discuss the future of Features as they hinder meta-programing.

Fix #30497

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.io application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

@mhevery mhevery requested a review from kara February 18, 2020 23:30
@mhevery mhevery added the area: core Issues related to the framework runtime label Feb 22, 2020
@ngbot ngbot bot added this to the needsTriage milestone Feb 22, 2020
@mhevery mhevery added the action: review The PR is still awaiting reviews from at least one requested reviewer label Feb 25, 2020
@bryanrideshark
Copy link

Thank you so much for fixing this. Angular Ivy is awesome - Being able to upgrade our app, which heavily uses custom decorators, will be possible once this PR is merged.

@mhevery mhevery force-pushed the issue-30497 branch 2 times, most recently from 12cff19 to 3d53368 Compare March 11, 2020 20:30
@RolginRoman

This comment has been minimized.

@ef32

This comment has been minimized.

@qtis

This comment has been minimized.

@kumaresan-subramani
Copy link

Eagerly waiting for this MR to get merged. Once this get merged so many issue must get resolved i think.

@lurock
Copy link

lurock commented Apr 16, 2020

When using Angular 9.1.1 with Ivy now when I "ng serve" all of my custom class decorators are called and working the way they did with view engine but when I run "ng build --prod" and run the application only a few of my custom decorators are called. @mhevery will this pull request fix that? Meaning will all my decorators get called when the application is first loaded.

@hakimio

This comment has been minimized.

@bryanrideshark
Copy link

@hakimio it seems like different members of the team have different opinions about how important Metaprogramming is for users of Angular.

Thankfully @mhevery seems to realize just how important it is to us; but he might have a challenge convincing other members. Hopefully everyone on the Angular team will realize just how prevalent metaprogramming is among Angular users.

@Maximaximum

This comment has been minimized.

@maxime1992
Copy link

Without this MR, Ivy misses a little bit to be backward compatible :)

That'd really help us too at CloudNC to work on a new version of ngx-sub-form where we're trying to get rid of inheritance.

🤞 for this to get merged soon

@LayZeeDK
Copy link
Contributor

LayZeeDK commented May 20, 2020

image

⬆️ Please don't kill component features.

Please stop worrying about custom decorators. Custom decorators are experimental and should be treated as such.

The original ECMAScript decorators proposal has been abandoned. There's a new proposal in early stages, but it has different syntax and semantics.

@hakimio
Copy link

hakimio commented May 20, 2020

Please don't kill component features.

AFAIK it's Angular private API and they can do whatever they want with private APIs.

Custom decorators are experimental.

Yet they are one of the most widely used TypeScript features and many TypeScript libraries depend on them.

@mlc-mlapis
Copy link
Contributor

mlc-mlapis commented May 20, 2020

AFAIK it's Angular private API and they can do whatever they want with private APIs.

It's private now, but because of the phase for stabilization inner structures and finalize the public API. It was always mentioned as the public API at some point.

Yet they are one of the most widely used TypeScript features and many TypeScript libraries depend on them.

Yep, but it was meant from the official ECMAScript spec point of view.

@klemenoslaj
Copy link
Contributor

klemenoslaj commented May 20, 2020

Please stop worrying about custom decorators. Custom decorators are experimental and should be treated as such.

Why is everyone fixating on decorators only? The point is, that components are JS classes. Methods on classes are members of prototype. Overwriting a prototype method is an absolutely valid thing to do. Angular currently makes this impossible.

And yes, sure, decorators are one use case of it and I wouldn't make custom decorators for reasons you mentioned, but there are many more use cases.
One use case is a takeUntilDestroy which is basically a takeUntil that patches ngOnDestroy hook in Angular. Impossible right now.

@bryanrideshark
Copy link

bryanrideshark commented May 20, 2020

If we can't use custom decorators, you might as well get rid of them across the board in Angular. No @Input, @Output, @HostBinding. I'm not going to keep using a framework if the authors of the framework take a "good for me, but not for thee" approach to something that's a key language feature. Angular originally was going to write its own language just to make decorators possible (Remember AtScript?) and now, because we've got an optimized compiler and some pet private APIs, we're going to say decorators are off limits for end users?

It's not a good look when libraries are built around the idea that developers have to use a subset of a language.

@mhevery mhevery force-pushed the issue-30497 branch 2 times, most recently from 4ac5a60 to 269c093 Compare July 14, 2020 23:25
…strap

Currently we read lifecycle hooks eagerly during `ɵɵdefineComponent`.
The result is that it is not possible to do any sort of meta-programing
such as mixins or adding lifecycle hooks using custom decorators since
any such code executes after `ɵɵdefineComponent` has extracted the
lifecycle hooks from the prototype. Additionally the behavior is
inconsistent between AOT and JIT mode. In JIT mode overriding lifecycle
hooks is possible because the whole `ɵɵdefineComponent` is placed in
getter which is executed lazily. This is because JIT mode must compile a
template which can be specified as `templateURL` and those we are
waiting for its resolution.

- `+` `ɵɵdefineComponent` becomes smaller as it no longer needs to copy
  lifecycle hooks from prototype to `ComponentDef`
- `-` `ɵɵNgOnChangesFeature` feature is now always included with the
  codebase as it is no longer tree shakable.

Previously we have read lifecycle hooks from prototype in the
`ɵɵdefineComponent` so that lifecycle hook access would be monomorphic.
This decision was made before we had `T*` data structures. By not
reading the lifecycle hooks we are moving the megamorhic read form
`ɵɵdefineComponent` to instructions. However, the reads happen on
`firstTemplatePass` only and are subsequently cached in the `T*` data
structures. The result is that the overall performance should be same
(or slightly better as the intermediate `ComponentDef` has been
removed.)

- [ ] Remove `ɵɵNgOnChangesFeature` from compiler. (It will no longer
      be a feature.)
- [ ] Discuss the future of `Features` as they hinder meta-programing.

Fix angular#30497
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Reviewed-for: size-tracking

@mhevery mhevery added action: merge The PR is ready for merge by the caretaker and removed action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews labels Jul 15, 2020
@ngbot
Copy link

ngbot bot commented Jul 15, 2020

I see that you just added the PR action: merge label, but the following checks are still failing:
    failure status "pullapprove" is failing
    pending forbidden labels detected: PR action: review
    pending status "google3" is pending
    pending 3 pending code reviews

If you want your PR to be merged, it has to pass all the CI checks.

If you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help.

@pullapprove pullapprove bot requested a review from IgorMinar July 15, 2020 18:41
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, using global approvers because the public-api change here is a false positive

Reviewed-for: global-approvers

@mhevery mhevery added merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note and removed merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note labels Jul 15, 2020
@mhevery
Copy link
Contributor Author

mhevery commented Jul 15, 2020

presubmit

@mhevery mhevery removed the action: review The PR is still awaiting reviews from at least one requested reviewer label Jul 15, 2020
@mhevery mhevery removed the request for review from IgorMinar July 15, 2020 21:09
@mhevery mhevery removed the action: merge The PR is ready for merge by the caretaker label Jul 15, 2020
@mhevery mhevery added the action: merge The PR is ready for merge by the caretaker label Jul 15, 2020
@AndrewKushnir AndrewKushnir added target: major This PR is targeted for the next major release and removed target: patch This PR is targeted for the next patch release labels Jul 15, 2020
@AndrewKushnir
Copy link
Contributor

Hi @mhevery, this PR was merged to master only, since there was a conflict while merging into a patch branch. Could you please create a new PR that targets patch branch? Thank you.

@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 Aug 15, 2020
profanis pushed a commit to profanis/angular that referenced this pull request Sep 5, 2020
…strap (angular#35464)

Currently we read lifecycle hooks eagerly during `ɵɵdefineComponent`.
The result is that it is not possible to do any sort of meta-programing
such as mixins or adding lifecycle hooks using custom decorators since
any such code executes after `ɵɵdefineComponent` has extracted the
lifecycle hooks from the prototype. Additionally the behavior is
inconsistent between AOT and JIT mode. In JIT mode overriding lifecycle
hooks is possible because the whole `ɵɵdefineComponent` is placed in
getter which is executed lazily. This is because JIT mode must compile a
template which can be specified as `templateURL` and those we are
waiting for its resolution.

- `+` `ɵɵdefineComponent` becomes smaller as it no longer needs to copy
  lifecycle hooks from prototype to `ComponentDef`
- `-` `ɵɵNgOnChangesFeature` feature is now always included with the
  codebase as it is no longer tree shakable.

Previously we have read lifecycle hooks from prototype in the
`ɵɵdefineComponent` so that lifecycle hook access would be monomorphic.
This decision was made before we had `T*` data structures. By not
reading the lifecycle hooks we are moving the megamorhic read form
`ɵɵdefineComponent` to instructions. However, the reads happen on
`firstTemplatePass` only and are subsequently cached in the `T*` data
structures. The result is that the overall performance should be same
(or slightly better as the intermediate `ComponentDef` has been
removed.)

- [ ] Remove `ɵɵNgOnChangesFeature` from compiler. (It will no longer
      be a feature.)
- [ ] Discuss the future of `Features` as they hinder meta-programing.

Fix angular#30497

PR Close angular#35464
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: core Issues related to the framework runtime cla: yes target: major This PR is targeted for the next major release
Projects
None yet