NG3003:Angular 12 库中的循环依赖 - Ivy 部分编译模式

NG3003: Angular 12 Circular Dependency in library - Ivy partial compilationMode

我提出了一个问题 here
我有一个 ParentComponent,其中有一个 child ChildComponent, child 里面有 ParentComponent 所以这里有一个循环。
这是我面临的错误:

✖ Compiling with Angular sources in Ivy partial compilation mode.
ERROR: projects/api/src/lib/api.component.ts:3:1
error NG3003: One or more import cycles would need to be created to 
compile this component, which is not supported by the current compiler
configuration.

The component 'ParentComponent' is used in the template but importing
it would create a cycle:
 /lib/child/child.component.ts -> /lib/parent/parent.component.ts -> /lib/child/child.component.ts

此错误仅发生在 Angular 库中。因此,正如您所见,stackblitz 示例中没有问题,这只是一个演示。

在库的 tsconfig.lib.prod.json 文件中设置 "compilationMode": "full" 会消除此错误,但在那种情况下,我们会失去向后兼容性!

官方文档说:

Move the classes that reference each other into the same file, to avoid any imports between them. Blockquote

它确实有效,但这确实是一种丑陋的方式!而且我们有很多组件,我们就是做不到!

你能帮我吗?!

好的,网上找了一圈,终于自己解决了!
我使用了 post 建议的动态方法:

您可以在 stackblitz.
中查看我的解决方案 在这里我不得不再次提到,这个问题(NG3003)只发生在Angular libraries with partial compilationMode。

所以我之前提到的 post 不是一个完整的解决方案和一个工作示例。我添加的是一个名为 ComponentStructure:

的接口
export interface ComponentStructure {
  type: string;
  content: {
    textContent: string;
    components: ComponentStructure[];
  };
}

并且components对父组件和子组件的输入:

import { Component, Input } from '@angular/core';
import { Base } from '../base';
import { HtmlComponent } from '../child-node.directive';
import { ComponentStructure } from '../component-structure';

@HtmlComponent({ map: ['lib_parent'] })
@Component({
    selector: 'lib-parent',
    templateUrl: './parent.component.html',
  ],
})
export class ParentComponent extends Base {
  @Input() count = 3;
  @Input() set components(_components: ComponentStructure[]) {
    this.childNodes = _components;
  }
  public textContent: string = '';

  constructor() {
    super();
  }

  set content(content: any) {
    this.textContent = content.textContent;
    this.components = content.components;
  }
}

另外我把Baseclass改成如下:

import { Directive, QueryList, ViewChildren } from '@angular/core';
import { interval } from 'rxjs';
import { take } from 'rxjs/operators';
import { ChildNodeDirective } from './child-node.directive';
import { ComponentStructure } from './component-structure';

@Directive()
export abstract class Base {
  // These are elements that the template will render into the directive
  @ViewChildren(ChildNodeDirective) protected children?: QueryList<any>;
  public childNodes: ComponentStructure[] = [];
  private childrenLoaded = false;

  ngAfterViewInit(): void {
    interval(10)
      .pipe(take(5))
      .subscribe(() => {
        if (!this.childrenLoaded && this.children) {
          this.children.forEach((child: ChildNodeDirective) => {
            child.load();
          });
          this.childrenLoaded = true;
        }
      });
  }
}

我不喜欢的是 interval 这是棘手的部分。但是原始答案中使用的 AfterContentChecked 对我不起作用,我不得不这样做。
如果你对此有更好的想法,请在评论中告诉我