You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 19应用构建器搭配Angular Elements出现重复渲染异常

Angular Elements v19 Web Component重复渲染、脚本重复加载问题分析与解决

问题场景

在Nx monorepo环境中,使用Angular 19的@angular/elements将mfe-1应用转为Web Component,通过shell应用的自定义MicroFrontendLoaderService加载其main.js脚本后,出现以下异常:

  • main.js脚本在DOM中被插入两次
  • Web Component构造函数执行两次
  • 组件重复渲染且无法正常显示

异常原因分析

1. 并发请求导致脚本重复插入

当前MicroFrontendLoaderService中的loaded变量为布尔值,若多个组件或逻辑同时调用loadScript方法,在第一个脚本加载完成前(loaded仍为false),会触发多次脚本创建操作,最终导致DOM中出现多个相同的script标签。

2. Nx静态资源自动注入

若shell应用的angular.json配置中,将mfe-1的构建产物目录添加到了assets数组中,Nx在启动shell服务时会自动将main.js注入到index.html中,加上自定义服务加载的脚本,就会造成重复引入。

3. 未处理Web Component重复注册

即使脚本重复加载,若未检查元素是否已注册,customElements.define会重复执行,触发Web Component构造函数多次调用,导致组件重复渲染。

解决方案

1. 优化Loader的并发请求处理

将loaded布尔值改为缓存加载Promise,避免并发请求时重复创建脚本:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class MicroFrontendLoaderService {
  private loadPromise: Promise<void> | null = null;

  loadScript(url: string): Promise<void> {
    // 若已有加载中的请求,直接返回缓存的Promise
    if (this.loadPromise) {
      return this.loadPromise;
    }

    this.loadPromise = new Promise((resolve, reject) => {
      const script = document.createElement('script');
      script.src = url;
      script.type = 'module';
      script.onload = () => resolve();
      script.onerror = () => reject(new Error(`Failed to load script: ${url}`));
      document.body.appendChild(script);
    });

    return this.loadPromise;
  }
}

2. 检查并修正Nx静态资源配置

打开项目根目录的angular.json,找到shell应用的assets配置项,确保未包含mfe-1的构建产物路径(例如dist/apps/mfe-1),避免Nx自动注入脚本。

3. 添加Web Component注册检查

在mfe-1的main.ts中,注册前先判断元素是否已存在,避免重复注册:

import { createCustomElement } from '@angular/elements';
import { createApplication } from '@angular/platform-browser';

import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';

(async () => {
  const appRef = await createApplication(appConfig);
  const appComponent = createCustomElement(AppComponent, {
    injector: appRef.injector,
  });

  // 仅当元素未注册时执行定义
  if (!customElements.get('nds-mfe-1')) {
    customElements.define('nds-mfe-1', appComponent);
  }
})();

内容的提问来源于stack exchange,提问作者billyjov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 15:55:09