来自未在动态编译组件中渲染的不同模块中加载的角组件

发布于 2025-01-29 14:32:38 字数 2405 浏览 5 评论 0原文

我们的SaaS需要为不同客户提供不同的主页。我们的方法是在数据库中具有不同的模板。我们还具有在不同的模块中定义的组件,这些组件必须在不同的主页中使用。 因此,我们正在动态创建主页组件,从默认的组件继承。

我们处于Angular 13中,

它在开发人员中起作用,但与AOT无关。 我们没有任何错误,并且处理了动态组件中的插值,但是来自不同模块的组件没有渲染,看起来它们似乎没有被编译,即被视为平面HTML标签。

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterContentInit {

  title = 'dynamic';
  static factory: ComponentFactory<any> | undefined;
  template = "<h1>Component loaded dynamically</h1> <div>Below should be rendered a component loaded from another module</div><app-widget-component #theComponent></app-widget-component>";
   
  @ViewChild(AnchorDirective, { static: true }) anchorHost: AnchorDirective | undefined;  

  ngOnInit(): void {    

  }

  constructor(public _compiler: Compiler,
    public injector: Injector) {

  }

  ngAfterContentInit(): void {
    this.loadContent(this.template, "");
  }

  loadContent(content: string, javascript: string) {


    const cmpClass = class DynamicComponent extends DynamicComponentComponent {
      text: string = "Text";

      constructor(injector: Injector) {
        super(injector)
      }
    };

    (cmpClass as any).ctorParameters = () => [{ type: Injector }];
    
    const metadata = new Component({
      selector: "compiled-at-runtime",
      template: content
      // todo: check styles and other options
    });

    const decoratedCmp = Component(metadata)(cmpClass);

    const moduleDef = NgModule({
      imports: [WidgetModuleModule,CommonModule, RouterModule, FormsModule],
      declarations: [decoratedCmp]
    })(class DynamicHtmlModule { });

    const moduleWithComponentFactory = this._compiler.compileModuleAndAllComponentsSync(
      moduleDef
    );    

    let factory = moduleWithComponentFactory.componentFactories.find(
      x => x.selector === "compiled-at-runtime"
    );

    let viewContainerRef = this.anchorHost!.viewContainerRef;
    const injector = Injector.create({
      providers: [],
      parent: viewContainerRef.injector
    });

    const componentRef = viewC  
    
  } 
}

在产品中,我们得到了:

“

and dev:

“

Our SaaS need to offer different home pages for different customers. Our approach is to have the different templates in the database. We also have components defined in a different module that must be used in the different home pages.
So we're creating the home-page component dynamically, inheriting from the default one.

We're in Angular 13

It works in the dev, but not in prod with AOT.
We don't get any error, and the interpolations in the dynamic component are processed, but the components coming from a different module are not rendered, it looks like they are not compiled, that is, treated as plane HTML tags.

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterContentInit {

  title = 'dynamic';
  static factory: ComponentFactory<any> | undefined;
  template = "<h1>Component loaded dynamically</h1> <div>Below should be rendered a component loaded from another module</div><app-widget-component #theComponent></app-widget-component>";
   
  @ViewChild(AnchorDirective, { static: true }) anchorHost: AnchorDirective | undefined;  

  ngOnInit(): void {    

  }

  constructor(public _compiler: Compiler,
    public injector: Injector) {

  }

  ngAfterContentInit(): void {
    this.loadContent(this.template, "");
  }

  loadContent(content: string, javascript: string) {


    const cmpClass = class DynamicComponent extends DynamicComponentComponent {
      text: string = "Text";

      constructor(injector: Injector) {
        super(injector)
      }
    };

    (cmpClass as any).ctorParameters = () => [{ type: Injector }];
    
    const metadata = new Component({
      selector: "compiled-at-runtime",
      template: content
      // todo: check styles and other options
    });

    const decoratedCmp = Component(metadata)(cmpClass);

    const moduleDef = NgModule({
      imports: [WidgetModuleModule,CommonModule, RouterModule, FormsModule],
      declarations: [decoratedCmp]
    })(class DynamicHtmlModule { });

    const moduleWithComponentFactory = this._compiler.compileModuleAndAllComponentsSync(
      moduleDef
    );    

    let factory = moduleWithComponentFactory.componentFactories.find(
      x => x.selector === "compiled-at-runtime"
    );

    let viewContainerRef = this.anchorHost!.viewContainerRef;
    const injector = Injector.create({
      providers: [],
      parent: viewContainerRef.injector
    });

    const componentRef = viewC  
    
  } 
}

In prod we got :

Production/AOT

And in dev:

Dev

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

红焚 2025-02-05 14:32:38

我的团队今天遇到了同样的问题(@Angular/CLI版本15.0.1),我们的两个自定义组件在开发模式下运行良好,但在生产模式下呈现不佳。

在我们从这些问题组件中的导入中删除了所有无用的参考\方法之后,它起作用。

/*
它应该是JIT和AOT之间的不同行为,但我们没有发现根本原因。 :(
*/

更新:
好吧,事实证明,我们的组件中有一个循环参考(只是进口但未使用),并且在拆除它之前删除的进口删除并解决了问题。不确定为什么在Angular中有圆形引用时,在DEV模式或产品模式下都没有警告或错误。需要在源代码中进行更多挖掘:p

My team got the same issue today (@angular/cli version 15.0.1), two of our custom components work well in the dev mode, but not rendered in the production mode.

It works after we removed all useless references\methods from the imports in these issue components.

/*
It shall be the different behaviors between JIT and AOT, but we don't find out the root cause. :(
*/

UPDATE:
Well, it turns out that there was a circular reference (just imported but not been used) in our components, and the imports removing we did before just breaks it and fixed the issue. Not sure why there's no warnings or errors in the neither dev mode nor prod mode when there's a circular reference in Angular. Need to dig more in the source code :-P

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文