Repository navigation
fix(ivy): take components into account when discovering directives - #26113
pkozlowski-opensource wants to merge 1 commit into
Conversation
83e6567 to
5be12f8
Compare
|
You can preview 23a9b33 at https://pr26113-23a9b33.ngbuilds.io/. |
|
You can preview 83e6567 at https://pr26113-83e6567.ngbuilds.io/. |
|
You can preview 5be12f8 at https://pr26113-5be12f8.ngbuilds.io/. |
There was a problem hiding this comment.
Now that we know the component is stored first, I'm not sure this loop is necessary anymore. I think to get the directives list in discoverDirectives, we can just copy the existing directives array using the start/end indices:
function discoverDirectives(nodeIndex: number, lViewData: LViewData, includeComponents: boolean = false) {
const directiveInstances = lViewData[DIRECTIVES];
if (directiveInstances != null) {
const tNode = lViewData[TVIEW].data[nodeIndex] as TNode;
const startIndex =
includeComponents ? getDirectiveStartIndex(tNode) : getDirectiveStartIndex(tNode) + 1;
const endIndex = getDirectiveEndIndex(tNode, startIndex);
return directiveInstances.slice(startIndex, endIndex);
}
return null;
}There was a problem hiding this comment.
Oh, right! This is much simpler indeed, thnx!
There was a problem hiding this comment.
OK, so finally it is slightly more complex as we can't simply do const startIndex = includeComponents ? getDirectiveStartIndex(tNode) : getDirectiveStartIndex(tNode) + 1; const endIndex = getDirectiveEndIndex(tNode, startIndex); as we don't know if a given element has a component on it or not.
Anyway, I've decided to change this method to always return components and people can filter them out if not needed.
There was a problem hiding this comment.
The default assignment generates some additional code, especially in ES5 targets. Why not simply leave it optional?
There was a problem hiding this comment.
changing back to includeComponents?: boolean
There was a problem hiding this comment.
Does this now mean that getDirectives will return any components inside no matter what? Can there not be an if statement that checks the first value to see if it's a component instance? There should be a new function here if you want to have a combined list of of the component + directives.
There was a problem hiding this comment.
Adding the includeComponents flag (falsy by default) to this method so we can decide if components should be returned or not.
mhevery
left a comment
There was a problem hiding this comment.
Please take care of the comments. LGTM otherwise.
There was a problem hiding this comment.
I think {}[] is better than any[] as it is more restrictive. For example array of numbers will not match {} but will match any
There was a problem hiding this comment.
OK, changing it back
5be12f8 to
1d68e58
Compare
|
You can preview 1d68e58 at https://pr26113-1d68e58.ngbuilds.io/. |
|
Marking as merge-assistance since:
|
There was a problem hiding this comment.
I think we can avoid the megamorphic lookup in isComponentInstance if we use the isComponent method and pass in the tNode
There was a problem hiding this comment.
Changed - didn't know about this util!
There was a problem hiding this comment.
Same here. I think we can just check the isComponent flag using the isComponent method. We can do it inside discoverDirectives maybe, since we already have the tNode there?
There was a problem hiding this comment.
Hmm, I don't think we've got access to TNode at this point any more...
There was a problem hiding this comment.
We can look it up using context.lNodeIndex, see discoverDirectiveIndices. I believe this should still be better than the megamorphic lookup.
There was a problem hiding this comment.
@kara see alternative proposal in https://github.com/angular/angular/pull/26113/files#r221942800
If we could store directives start index, no of directives we could easily just slice lViewData here. And we could use TNode's isComponent to adjust slicing start. We could even store a isComponent flag on LContext to avoid TNode lookup all the time.
WDYT?
1d68e58 to
04ed6af
Compare
|
You can preview 04ed6af at https://pr26113-04ed6af.ngbuilds.io/. |
There was a problem hiding this comment.
I'm not sure I understand why we still need to generate an array of indices when we could just slice from the directives array directly to retrieve the instances?
There was a problem hiding this comment.
@kara I think I might know where the confusion is coming from - you comment seems to imply that the discoverDirectiveIndices is used only to get directive instances but the way I understood the existing code is that discoverDirectiveIndices and discoverDirectives are 2 independent functions that could, but don't have to be used together.
In fact for the TestBed implementation I don't care about directive instances but need to get directive definitions. For this case the discoverDirectiveIndices comes handy and in this particular case I just don't want to slice LViewData to get directive instances as I don't care about instances.
In the similar spirit I've interpreted discoverDirectives as a utility function that can take any set of indices (not all directives present on a node need to be present in this set) in any particular order. Maybe this wasn't the intention of those 2 functions.
Having said all this I very much dislike the fact that we've got both directive indices and directive instances on LContext as those things can easily get out of sync.
Maybe a better approach would be to store sth like directvesStartIndex and directivesCount and have higher-level utility functions working on those 2 pieces of data? If we store the above:
- we don't have to generate an array of indices here;
- utility methods to get a set of directive instances / directive defs become trivial (array slicing as you suggest).
WDYT?
There was a problem hiding this comment.
If you need the defs in TestBed and don't want to look up the TNode, I'd prefer storing the start index/count or the TNode itself (which contains the start index/count) in LContext. Otherwise we are unnecessarily allocating an extra array in memory, as well as looping over the directives array twice for no good reason.
IIRC, the original intent of discoverDirectiveIndices was simply to grab non-component directive indices when we couldn't assume the component would be first in the list. I don't think it's particularly useful externally, so I think we should get rid of it and discoverDirectives/TestBed should use start/end indices to slice what they need directly.
There was a problem hiding this comment.
OK, so based on your comment it seems to me like I'm trying to re-purpose the discoverDirectives / discoverDirectiveIndices in the way that is different from the initial / intended design. As such I think that I will just add the needed code to the TestBed impl (I've got access to TNode).
I'm going to close this PR for now. In the future, if there is some code that can be shared / refactored I will pull it into LContext. Thnx for taking time to review and bearing with me!
|
@kara I've got an impression that we think differently about role of the I think that we can simplify the whole system, there is a proposal in the above comment. Let's discuss this in person later today. |
04ed6af to
2d71f63
Compare
|
You can preview 2d71f63 at https://pr26113-2d71f63.ngbuilds.io/. |
2d71f63 to
8210f54
Compare
This PR fixes an issue where the includeComponents argument to the discoverDirectiveIndices was not taken into account. Additionally it returns components as part of directives list when calling getDirectives (please not that we can't parametrize this function with includeComponents as results are cached).
|
You can preview 8210f54 at https://pr26113-8210f54.ngbuilds.io/. |
|
Closing based on #26113 (comment) |
|
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. |
This PR fixes an issue where the includeComponents argument to the
discoverDirectiveIndices was not taken into account.
Additionally it returns components as part of directives list when
calling getDirectives (please not that we can't parametrize this
function with includeComponents as results are cached).