mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(compiler-cli): error on cyclic imports in partial compilation (#40782)
Our approach for handling cyclic imports results in code that is not easy to tree-shake, so it is not suitable for publishing in a library. When compiling in partial compilation mode, we are targeting such library publication, so we now create a fatal diagnostic error instead of trying to handle the cyclic import situation. Closes #40678 PR Close #40782
This commit is contained in:
committed by
Joey Perrott
parent
a4c00c2148
commit
322951af49
@@ -0,0 +1,55 @@
|
||||
@name Import Cycle Detected
|
||||
@category compiler
|
||||
@shortDescription Import cycles would need to be created to compile this component
|
||||
|
||||
@description
|
||||
|
||||
A component, directive or pipe that is referenced by this component would require the compiler
|
||||
to add an import that would lead to a cycle of imports. For example, consider a scenario where
|
||||
a `ParentComponent` references a `ChildComponent` in its template:
|
||||
|
||||
<code-example path="errors/cyclic-imports/parent.component.ts" header="parent.component.ts"></code-example>
|
||||
|
||||
<code-example path="errors/cyclic-imports/child.component.ts" header="child.component.ts"></code-example>
|
||||
|
||||
There is already an import from `child.component.ts` to `parent.component.ts` since the `ChildComponent`
|
||||
references the `ParentComponent` in its constructor.
|
||||
|
||||
But note that the parent component's template contains `<child></child>`. The generated code for this
|
||||
template must therefore contain a reference to the `ChildComponent` class. In order to make this reference
|
||||
the compiler would have to add an import from `parent.component.ts` to `child.component.ts`, which would
|
||||
cause an import cycle:
|
||||
|
||||
```
|
||||
parent.component.ts -> child.component.ts -> parent.component.ts
|
||||
```
|
||||
|
||||
### Remote Scoping
|
||||
|
||||
To avoid adding imports that create cycles, additional code is added to the `NgModule` class where
|
||||
the component is declared that wires up the dependencies. This is known as "remote scoping".
|
||||
|
||||
|
||||
### Libraries
|
||||
|
||||
Unfortunately, "remote scoping" code is side-effectful, which prevents tree shaking, and cannot
|
||||
be used in libraries. So when building libraries using the `"compilationMode": "partial"` setting,
|
||||
any component that would require a cyclic import will cause this `NG3003` compiler error to be raised.
|
||||
|
||||
|
||||
@debugging
|
||||
|
||||
The cycle that would be generated is shown as part of the error message. For example:
|
||||
|
||||
<code-example hideCopy="true">
|
||||
<span class="nocode">The component ChildComponent is used in the template but importing it would create a cycle:
|
||||
/parent.component.ts -> /child.component.ts -> /parent.component.ts</span>
|
||||
</code-example>
|
||||
|
||||
Use this to identify how the referenced component, pipe or directive has a dependency back to the
|
||||
component being compiled. Here are some ideas for fixing the problem:
|
||||
|
||||
* Try to re-arrange your dependencies to avoid the cycle. For example using an intermediate interface
|
||||
that is stored in an independent file that can be imported to both dependent files without
|
||||
causing an import cycle.
|
||||
* Move the classes that reference each other into the same file, to avoid any imports between them.
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ParentComponent } from './parent.component';
|
||||
|
||||
@Component({selector: 'app-child', template: 'The child!'})
|
||||
export class ChildComponent {
|
||||
constructor(private parent: ParentComponent) {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ChildComponent } from './child.component';
|
||||
import { ParentComponent } from './parent.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ParentComponent, ChildComponent]
|
||||
})
|
||||
export class AppModule {}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({selector: 'app-parent', template: '<app-child></app-child>'})
|
||||
export class ParentComponent {}
|
||||
Reference in New Issue
Block a user