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(@ngtools/webpack): downlevel constructor parameter type information #14473

Merged
merged 3 commits into from
May 23, 2019

Conversation

clydin
Copy link
Member

@clydin clydin commented May 19, 2019

The Angular JIT compiler uses the output of TypeScript's emitDecoratorMetadata to support dependency injection at runtime. This option stores type and DI token information so that the runtime JIT compiler can inject the proper provider. This option is not needed for AOT compilation and the metadata is indirectly stripped from the output due to all Angular decorators being removed during the compilation process.

Unfortunately, the emitDecoratorMetadata option does not support forward references (or more generally circular dependencies) within ES2015+ output due to the TypeScript compiler transforming the metadata into a direct reference of the yet to be defined class. This results in a runtime TDZ error. This is a known limitation of the emitDecoratorMetadata option (reference). This situation is not unique to Angular and can occur in any TypeScript code. As it is marked as a design limitation, it is considered that it cannot be fixed within the current architecture of TypeScript.

As a result, the change in this PR removes the need for the use of the option by storing the DI information in a static property function via the use of the tsickle ctorParameters transformation. By leveraging the existing functionality, no changes to the framework code is necessary. Also, minimal new code is required within the CLI, as the relevant tsickle code can be extracted and used with several local modifications.

For forward references to function in ES2015+, the emitDecoratorMetadata option must be disabled based on the current implementation. To support both the option and forward references, the metadata generated by TypeScript would need to be altered to remove the type information that would trigger a TDZ error. However, by doing so the metadata information is no longer useful to Angular and technically incorrect as it will not contain the information from the source code as described by the option.

Closes: #14424

Copy link
Contributor

@IgorMinar IgorMinar left a comment

Choose a reason for hiding this comment

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

I really like this solution and especially the fact that we are reusing code from tsickle rather than writing stuff from scratch - this will align the external and google3 build stacks to work more alike.

notes from internal discussion:

  • we considered also writing a migration to remove reflect metadata from dev polyfills in all projects, because at this point, there is no need for reflect-metadata in CLI projects unless the app code or other 3rd party libraries need it. This is however too risky during the RC so we'll defer this cleanup until v9
  • we'll however document that reflect-metadata is no longer needed and will be removed from projects in v9 (in the meantime there is no prod impact because the code is never included in prod bundles).
  • we will also update the polyfills docs and removed reflect-metadata from the list of required polyfills. the relevant doc is here: https://angular.io/guide/browser-support#core-es7-reflect
  • lastly, we should update the new app/lib schematics to no longer bring reflect-metadata into new projects. we should tried to do this before 8.0 still since it's a low risk change with significant impact on new projects.

@clydin clydin added the target: patch This PR is targeted for the next patch release label May 21, 2019
The TypeScript `emitDecoratorMetadata` option does not support forward references of ES2015 classes due to the TypeScript compiler transforming the metadata into a direct reference of the yet to be defined class.  This results in a runtime TDZ error.  This is a known limitation of the `emitDecoratorMetadata` option.
The change in the PR removes the need for the option by storing the information in a static property function via the use of the tsickle `ctorParameters` transformation.  By leveraging the existing functionality, no changes to the framework code is necessary.  Also, minimal new code is required within the CLI, as the relevant tsickle code can be extracted and used with several local modifications.
@clydin clydin marked this pull request as ready for review May 21, 2019 14:07
This is required to support forward references in ES2015 target code.  tsickle provides the constructor parameter downlevel logic that removes the runtime TDZ error that would otherwise be encountered.
@@ -103,6 +103,11 @@ function addDependenciesToPackageJson() {
name: 'ng-packagr',
version: '^5.1.0',
},
Copy link
Collaborator

@alan-agius4 alan-agius4 May 21, 2019

Choose a reason for hiding this comment

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

//cc @alexeagle kindly note this change!

Copy link
Collaborator

@alan-agius4 alan-agius4 left a comment

Choose a reason for hiding this comment

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

From library/tsickle perspective this looks good to me.

@Splaktar
Copy link
Member

This seems to be at least partially related to angular/angular#30586.

@trotyl
Copy link
Contributor

trotyl commented May 22, 2019

@IgorMinar I believe angular/angular#25039 would be a better approach, which eliminate the need for emitDecoratorMetadata at semantic level, and will not result any inconsistency with or without using Angular CLI.

@IgorMinar IgorMinar added this to the 8.0 milestone May 22, 2019
@IgorMinar
Copy link
Contributor

IgorMinar commented May 22, 2019

EDIT: oops.. I copy pasted the wrong link, instead of angular/angular#25039 I meant angular/angular#30586. I updated the links below.

I agree that angular/angular#25039 angular/angular#30586 is better but it's not a change we can implement in 8.0. It's too late for that, we are in an RC and in risk-averse mode. We can however implement it in 8.1.

Keep in mind that while that solution is better, this PR is sufficient to prevent regressions in 8.0 - to ensure that things that worked prior to 8.0 still work with 8.0 and all the new defaults (e.g. differential loading). The proposal described by Paul enables something that never worked before - bazel+ssr. We should do this but again, not in 8.0.

So the least risky solution is to

@IgorMinar
Copy link
Contributor

With regards to angular/angular#25039 - it's solving a very different problem and while it could potentially also solve this one, it would only work for new code and not for any of the existing application/library code which would need to be migrated.

@mgechev mgechev merged commit 635de55 into angular:master May 23, 2019
@clydin clydin deleted the forwardref-metadata branch May 23, 2019 17:15
@evmar
Copy link

evmar commented May 28, 2019

Does this mean we can remove the decorator downlevelling code from tsickle? When? (I think it is great that Angular owns this particular code because I never understood it well.)

@alexeagle
Copy link
Contributor

@evmar I think that could happen already, tsickle is already an optional dependency from Angular ecosystem. It's really hard for us to be sure about the consequences without trying it though - there might be users like Lucidchart who still depend on that behavior

@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
target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fix forwardRef in ES2015 via a pass
9 participants