Cyclic import detection in ngtsc / for g3#28169
Cyclic import detection in ngtsc / for g3#28169alxhub wants to merge 3 commits intoangular:masterfrom
Conversation
|
You can preview 2e5fe41 at https://pr28169-2e5fe41.ngbuilds.io/. |
JoostK
left a comment
There was a problem hiding this comment.
Looks great, some minor things.
There was a problem hiding this comment.
I don't think this early return is correct here, but once you use _isCyclicImport the problem resolves itself
There was a problem hiding this comment.
Why isn't directives simply mapped from scope.directives? There's no initial content to deal with so that should work just fine.
There was a problem hiding this comment.
I'm actually debating whether I like this. It gets really annoying to write out example programs all the time, but having actual code to look at when you're debugging is nice. In this case I think it's okay because the programs being generated are very specific.
There was a problem hiding this comment.
This shouldn't be pure, or all the hard work for nothing ;)
There was a problem hiding this comment.
Hahahaha. Good point! I'll actually invert the test so that we expect not to have a pure call there.
There was a problem hiding this comment.
Swapping these two if and else blocks would remove the need for the negation on !cycleDetected.
There was a problem hiding this comment.
I actually wrote it this way on purpose - the common case is the if, the uncommon case is the else.
There was a problem hiding this comment.
This return here exits the whole resolve() method.
Are you saying that if a directive is an external expression but has no import we abort all resolving activity?
There was a problem hiding this comment.
Nope, as @JoostK pointed out this flow only makes sense within the _isCyclicImport function.
There was a problem hiding this comment.
This method does not appear to be used...
There was a problem hiding this comment.
Ahah, I just realised that this is a WIP. The code above in the resolve method was copied from here, which is why there are the confusing return statements there.
2e5fe41 to
5577728
Compare
|
You can preview 5577728 at https://pr28169-5577728.ngbuilds.io/. |
There was a problem hiding this comment.
nit:
const cycleDetected =
scope.directives.some(meta => this._isCyclicImport(meta.directive, origin)) ||
Array.from(scope.pipes.values()).some(pipe => this._isCyclicImport(pipe, origin));There was a problem hiding this comment.
The comment has become a bit inaccurate ;)
5577728 to
1e7bfee
Compare
|
You can preview 1e7bfee at https://pr28169-1e7bfee.ngbuilds.io/. |
JoostK
left a comment
There was a problem hiding this comment.
The CI fails because of the incorrect private export, which indicates a surprising dependency on this feature within the Angular Router codebase. That's ok for now, let me look into refactoring the Router to avoid the cyclic dep in Ivy builds sometime.
There was a problem hiding this comment.
Whoopsie, caught by failing CI :)
1e7bfee to
d5867b3
Compare
|
You can preview d5867b3 at https://pr28169-d5867b3.ngbuilds.io/. |
d5867b3 to
20bf80b
Compare
|
You can preview 20bf80b at https://pr28169-20bf80b.ngbuilds.io/. |
20bf80b to
5179313
Compare
|
You can preview 5179313 at https://pr28169-5179313.ngbuilds.io/. |
There was a problem hiding this comment.
nit: may be use map here (and for directives too)?
const pipes: Expression[] = scope.pipes.map(pipe => pipe.toExpression(context) !);
9804468 to
230c30e
Compare
This commit implements a cycle detector which looks at the import graph of TypeScript programs and can determine whether the addition of an edge is sufficient to create a cycle. As part of the implementation, module name to source file resolution is implemented via a ModuleResolver, using TS APIs.
230c30e to
2d633bd
Compare
By its nature, Ivy alters the import graph of a TS program, adding imports where template dependencies exist. For example, if ComponentA uses PipeB in its template, Ivy will insert an import of PipeB into the file in which ComponentA is declared. Any insertion of an import into a program has the potential to introduce a cycle into the import graph. If for some reason the file in which PipeB is declared imports the file in which ComponentA is declared (maybe it makes use of a service or utility function that happens to be in the same file as ComponentA) then this could create an import cycle. This turns out to happen quite regularly in larger Angular codebases. TypeScript and the Ivy runtime have no issues with such cycles. However, other tools are not so accepting. In particular the Closure Compiler is very anti-cycle. To mitigate this problem, it's necessary to detect when the insertion of an import would create a cycle. ngtsc can then use a different strategy, known as "remote scoping", instead of directly writing a reference from one component to another. Under remote scoping, a function 'setComponentScope' is called after the declaration of the component's module, which does not require the addition of new imports. FW-647 #resolve
2d633bd to
34b87a1
Compare
This commit implements a cycle detector which looks at the import graph of TypeScript programs and can determine whether the addition of an edge is sufficient to create a cycle. As part of the implementation, module name to source file resolution is implemented via a ModuleResolver, using TS APIs. PR Close #28169
…ed (#28169) By its nature, Ivy alters the import graph of a TS program, adding imports where template dependencies exist. For example, if ComponentA uses PipeB in its template, Ivy will insert an import of PipeB into the file in which ComponentA is declared. Any insertion of an import into a program has the potential to introduce a cycle into the import graph. If for some reason the file in which PipeB is declared imports the file in which ComponentA is declared (maybe it makes use of a service or utility function that happens to be in the same file as ComponentA) then this could create an import cycle. This turns out to happen quite regularly in larger Angular codebases. TypeScript and the Ivy runtime have no issues with such cycles. However, other tools are not so accepting. In particular the Closure Compiler is very anti-cycle. To mitigate this problem, it's necessary to detect when the insertion of an import would create a cycle. ngtsc can then use a different strategy, known as "remote scoping", instead of directly writing a reference from one component to another. Under remote scoping, a function 'setComponentScope' is called after the declaration of the component's module, which does not require the addition of new imports. FW-647 #resolve PR Close #28169
This commit implements a cycle detector which looks at the import graph of TypeScript programs and can determine whether the addition of an edge is sufficient to create a cycle. As part of the implementation, module name to source file resolution is implemented via a ModuleResolver, using TS APIs. PR Close angular#28169
…ed (angular#28169) By its nature, Ivy alters the import graph of a TS program, adding imports where template dependencies exist. For example, if ComponentA uses PipeB in its template, Ivy will insert an import of PipeB into the file in which ComponentA is declared. Any insertion of an import into a program has the potential to introduce a cycle into the import graph. If for some reason the file in which PipeB is declared imports the file in which ComponentA is declared (maybe it makes use of a service or utility function that happens to be in the same file as ComponentA) then this could create an import cycle. This turns out to happen quite regularly in larger Angular codebases. TypeScript and the Ivy runtime have no issues with such cycles. However, other tools are not so accepting. In particular the Closure Compiler is very anti-cycle. To mitigate this problem, it's necessary to detect when the insertion of an import would create a cycle. ngtsc can then use a different strategy, known as "remote scoping", instead of directly writing a reference from one component to another. Under remote scoping, a function 'setComponentScope' is called after the declaration of the component's module, which does not require the addition of new imports. FW-647 #resolve PR Close angular#28169
|
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. |
No description provided.