Skip to content

Conversation

@crisbeto
Copy link
Member

Adds the new ng generate @angular/core:inject-migration schematic that will convert existing code from constructor-based injection to injection using the inject function. The migration also has a few options that should help reduce compilation errors.

This migration is slightly different than our usual ones in that it may have to update entire class or constructor declarations. We don't go through the ts.factory.update* APIs for this, because it can cause the entire declaration to be re-formatted. Instead, this migration tries to insert strings in a way that won't affect the user's formatting.

@crisbeto crisbeto added action: review The PR is still awaiting reviews from at least one requested reviewer area: core Issues related to the framework runtime area: migrations Issues related to `ng update`/`ng generate` migrations target: minor This PR is targeted for the next minor release labels Jul 19, 2024
@ngbot ngbot bot added this to the Backlog milestone Jul 19, 2024
@angular-robot angular-robot bot added the detected: feature PR contains a feature commit label Jul 19, 2024
@crisbeto crisbeto requested a review from devversion July 19, 2024 12:06
@crisbeto crisbeto marked this pull request as ready for review July 19, 2024 12:06
Copy link
Contributor

@eneajaho eneajaho left a comment

Choose a reason for hiding this comment

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

Hi @crisbeto
I saw that generics case is not supported, for example: ElementRef<HTMLDivElement>

Because inject() doesn't infer the type correctly (check this issue: #53894) I guess, we also need to pass the whole type as a generic to inject.

el = inject<ElementRef<HTMLDivElement>>(ElementRef<HTMLDivElement>)

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
import { Component, Inject, Optional, inject } from '@angular/core';
import { Component, inject } from '@angular/core';

Copy link
Member Author

Choose a reason for hiding this comment

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

Right now it's not removing the unused imports. I can look into it for a follow-up since it would involve the code we use to manage imports across all the schematics.

Copy link
Member

Choose a reason for hiding this comment

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

@crisbeto when you look into this, feel free to consider adding this to the ngtsc import manager as we likely should use that at some point.

Copy link
Member

@devversion devversion left a comment

Choose a reason for hiding this comment

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

LGTM overall. Just some minor comments

Copy link
Member

Choose a reason for hiding this comment

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

You can also use the type checker to check if it's nullable— but maybe this is intended to be just AST based

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll double check it, but my assumption was that it might not work if it can't resolve types coming from other files.

Copy link
Member

Choose a reason for hiding this comment

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

Hmm. It might end up being the same, if the type is defined outside of the file. Although inside files, it would be more correct. Seems minor to not bother if that's the case

Copy link
Member

Choose a reason for hiding this comment

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

why can't we use the raw text of TypeNode here already?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because it's a bit of a mix of string manipulation and creating an AST.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure I 100% follow, but it doesn't matter much, so LGTM

Copy link
Member Author

Choose a reason for hiding this comment

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

Re-reading your comment now and I think I understand the question. If I remember correctly, TS does some sanitization of identifiers. I was a bit afraid that it might mangle a TypeNode that looks something like Foo<Bar<Baz>>.

Copy link
Member

Choose a reason for hiding this comment

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

IIRC it only does this when using a "generated identifier" via e.g. ts.createUniqueIdentifier

Adds the new `ng generate @angular/core:inject-migration` schematic that will convert existing code from constructor-based injection to injection using the `inject` function. The migration also has a few options that should help reduce compilation errors.

This migration is slightly different than our usual ones in that it may have to update entire class or constructor declarations. We don't go through the `ts.factory.update*` APIs for this, because it can cause the entire declaration to be re-formatted. Instead, this migration tries to insert strings in a way that won't affect the user's formatting.
@crisbeto
Copy link
Member Author

Good point @eneajaho, I've added it.

Thank you for the quick review @devversion 🎉

Copy link
Contributor

@eneajaho eneajaho left a comment

Choose a reason for hiding this comment

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

All license links in the top comment point to: https://angular.io/license
Should we move them to: https://angular.dev/license

@crisbeto
Copy link
Member Author

I looked into changing the licenses a few weeks ago, but it turned out to be kinda huge so I decided to leave it for later: #56379

@rainerhahnekamp
Copy link

Apologies for the question, but could you clarify why we are getting a migrator?

Did I miss a discussion or statement indicating that inject is now the preferred approach?

The last information I saw suggested that we could use any method we preferred, and that there would be a wait for the outcome of the standardization process of the parameter decorators.

Since the inject vs. constructor topic is quite polarizing, it might be helpful to release a statement before this change is merged.

@crisbeto
Copy link
Member Author

@rainerhahnekamp both constructor-based injection and inject are supported right now and will continue being supported in the foreseeable future. We're getting this migrator, because:

  1. We've seen that there's similar things popping up both internally and externally so there's a clear need for it.
  2. We had some requests for it internally so it made sense to just open-source this so that all Angular users can use it.
  3. Given that standard decorators don't support function parameters, there may be projects out there that want to switch to inject so that they can turn off experimental decorators.

@crisbeto crisbeto added action: merge The PR is ready for merge by the caretaker and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Jul 22, 2024
@rainerhahnekamp
Copy link

Thanks @crisbeto, that was the answer I was looking for!

@atscott
Copy link
Contributor

atscott commented Jul 22, 2024

This PR was merged into the repository by commit fab673a.

The changes were merged into the following branches: main

@atscott atscott closed this in fab673a Jul 22, 2024
vladboisa pushed a commit to vladboisa/angular that referenced this pull request Jul 29, 2024
…7056)

Adds the new `ng generate @angular/core:inject-migration` schematic that will convert existing code from constructor-based injection to injection using the `inject` function. The migration also has a few options that should help reduce compilation errors.

This migration is slightly different than our usual ones in that it may have to update entire class or constructor declarations. We don't go through the `ts.factory.update*` APIs for this, because it can cause the entire declaration to be re-formatted. Instead, this migration tries to insert strings in a way that won't affect the user's formatting.

PR Close angular#57056
@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 22, 2024
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 area: migrations Issues related to `ng update`/`ng generate` migrations detected: feature PR contains a feature commit target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants