-
Notifications
You must be signed in to change notification settings - Fork 26.5k
feat(compiler): allow selector-less directives as base classes #31379
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
Conversation
54c01b1
to
f3e64f1
Compare
f3e64f1
to
8ff47db
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, one nit
directives.push(symbol); | ||
} else { | ||
abstractDirectives.push(symbol); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Can we flip the ternary so it's not "if-not/else" ?
if (metadataResolver.isAbstractDirective(symbol)) {
abstractDirectives.push(symbol);
} else {
directives.push(symbol);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The general rule I try to use in the compiler is that for simple if-else
blocks, the common case is the first branch. So in this case, most directives are plain directives and flow through the if
section, and the else
section handles the occasional abstract directive. That does make the conditional a little trickier to parse, though.
I added some extra comments to clarify the two bodies here :)
8ff47db
to
8fcb1fa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm for api changes
Caretaker: reviews in place |
angular#31379)" This reverts commit f90c7a9 due to breakages in G3.
Following angular#31379, this adds support for directives without a selector to Ivy.
…ar#31379) In Angular today, the following pattern works: ```typescript export class BaseDir { constructor(@Inject(ViewContainerRef) protected vcr: ViewContainerRef) {} } @directive({ selector: '[child]', }) export class ChildDir extends BaseDir { // constructor inherited from BaseDir } ``` A decorated child class can inherit a constructor from an undecorated base class, so long as the base class has metadata of its own (for JIT mode). This pattern works regardless of metadata in AOT. In Angular Ivy, this pattern does not work: without the @directive annotation identifying the base class as a directive, information about its constructor parameters will not be captured by the Ivy compiler. This is a result of Ivy's locality principle, which is the basis behind a number of compilation optimizations. As a solution, @directive() without a selector will be interpreted as a "directive base class" annotation. Such a directive cannot be declared in an NgModule, but can be inherited from. To implement this, a few changes are made to the ngc compiler: * the error for a selector-less directive is now generated when an NgModule declaring it is processed, not when the directive itself is processed. * selector-less directives are not tracked along with other directives in the compiler, preventing other errors (like their absence in an NgModule) from being generated from them. PR Close angular#31379
angular#31379)" (angular#32089) This reverts commit f90c7a9 due to breakages in G3. PR Close angular#32089
…ar#31379) In Angular today, the following pattern works: ```typescript export class BaseDir { constructor(@Inject(ViewContainerRef) protected vcr: ViewContainerRef) {} } @directive({ selector: '[child]', }) export class ChildDir extends BaseDir { // constructor inherited from BaseDir } ``` A decorated child class can inherit a constructor from an undecorated base class, so long as the base class has metadata of its own (for JIT mode). This pattern works regardless of metadata in AOT. In Angular Ivy, this pattern does not work: without the @directive annotation identifying the base class as a directive, information about its constructor parameters will not be captured by the Ivy compiler. This is a result of Ivy's locality principle, which is the basis behind a number of compilation optimizations. As a solution, @directive() without a selector will be interpreted as a "directive base class" annotation. Such a directive cannot be declared in an NgModule, but can be inherited from. To implement this, a few changes are made to the ngc compiler: * the error for a selector-less directive is now generated when an NgModule declaring it is processed, not when the directive itself is processed. * selector-less directives are not tracked along with other directives in the compiler, preventing other errors (like their absence in an NgModule) from being generated from them. PR Close angular#31379
) Following angular#31379, this adds support for directives without a selector to Ivy. PR Close angular#32125
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
In Angular today, the following pattern works:
A decorated child class can inherit a constructor from an undecorated base
class, so long as the base class has metadata of its own (for JIT mode).
This pattern works regardless of metadata in AOT.
In Angular Ivy, this pattern does not work: without the @directive
annotation identifying the base class as a directive, information about its
constructor parameters will not be captured by the Ivy compiler. This is a
result of Ivy's locality principle, which is the basis behind a number of
compilation optimizations.
As a solution, @directive() without a selector will be interpreted as a
"directive base class" annotation. Such a directive cannot be declared in an
NgModule, but can be inherited from.