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

如何在同一页面运行两个不同Angular版本应用并实现组件复用

同页面运行Angular 9与Angular 15应用并实现跨应用组件加载

一、基础准备

  • 分别构建两个应用,指定不同输出目录避免文件冲突:
    • Angular 9:执行 ng build --prod --output-path dist/legacy-app
    • Angular 15:执行 ng build --output-path dist/new-app
  • 将两个构建后的dist目录部署到同一Web服务器,确保资源访问路径正确。

二、在同一页面嵌入两个应用

  1. 在宿主HTML页面中添加独立的DOM容器:
<!-- 旧应用容器 -->
<div id="legacy-app-root"></div>
<!-- 新应用容器 -->
<div id="new-app-root"></div>
  1. 按顺序引入两个应用的构建产物脚本和样式(Angular 9可能包含main-es5.js和main-es2015.js,需根据浏览器兼容情况选择):
<!-- 旧应用资源 -->
<link rel="stylesheet" href="legacy-app/styles.css">
<script src="legacy-app/runtime-es2015.js"></script>
<script src="legacy-app/polyfills-es2015.js"></script>
<script src="legacy-app/main-es2015.js"></script>

<!-- 新应用资源 -->
<link rel="stylesheet" href="new-app/styles.css">
<script src="new-app/runtime.js"></script>
<script src="new-app/polyfills.js"></script>
<script src="new-app/main.js"></script>
  1. 修改两个应用的启动逻辑,指定各自的DOM容器:
    • Angular 9的main.ts:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule, { ngZone: 'noop' })
  .then(moduleRef => {
    const appRoot = document.getElementById('legacy-app-root');
    if (appRoot) {
      moduleRef.instance.bootstrap(appRoot);
    }
  })
  .catch(err => console.error(err));
  • Angular 15的main.ts(独立组件模式):
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { provideZoneChangeDetection } from '@angular/core';

bootstrapApplication(AppComponent, {
  providers: [provideZoneChangeDetection({ eventCoalescing: true })],
  ngZone: 'noop'
}).then(appRef => {
  const appRoot = document.getElementById('new-app-root');
  if (appRoot) {
    const rootNode = appRef.injector.get(AppComponent).hostView.rootNodes[0];
    appRoot.appendChild(rootNode);
  }
}).catch(err => console.error(err));

三、实现新应用加载旧应用组件

1. 旧应用配置组件导出

  • 在旧应用的angular.json中开启UMD模块打包:
"projects": {
  "legacy-app": {
    "architect": {
      "build": {
        "options": {
          "umdModuleIds": {
            "@angular/core": "ng.core",
            "@angular/common": "ng.common",
            "rxjs": "rxjs"
          },
          "allowedCommonJsDependencies": ["rxjs"]
        }
      }
    }
  }
}
  • 创建public-api.ts作为组件导出入口:
export { LegacyComponent } from './app/legacy-component/legacy-component.component';
export { LegacyModule } from './app/legacy-module/legacy-module.module';

2. 新应用引入并加载旧组件

  • 在新应用的angular.json中添加旧应用UMD脚本引用:
"scripts": [
  "../dist/legacy-app/main.umd.js"
]
  • 在新应用组件中动态加载旧应用组件:
import { Component, ViewChild, ViewContainerRef, OnInit } from '@angular/core';

// 声明旧应用导出的全局变量
declare const legacyApp: {
  LegacyComponent: any;
};

@Component({
  selector: 'app-new-host',
  template: '<div #legacyHost></div>'
})
export class NewHostComponent implements OnInit {
  @ViewChild('legacyHost', { read: ViewContainerRef }) legacyHost!: ViewContainerRef;

  ngOnInit(): void {
    // 动态创建旧组件实例
    const componentRef = this.legacyHost.createComponent(legacyApp.LegacyComponent);
    
    // 传递输入属性
    componentRef.instance.legacyInput = '来自新应用的参数';
    
    // 监听旧组件输出事件
    componentRef.instance.legacyOutput.subscribe((data: any) => {
      console.log('旧组件返回数据:', data);
    });
  }
}

四、关键注意事项

  • Zone.js冲突处理:两个应用默认都会加载Zone.js,会导致变更检测异常,建议在启动时配置ngZone: 'noop',手动调用componentRef.changeDetectorRef.detectChanges()管理组件变更。
  • 依赖版本隔离:Angular 9和15核心库版本差异极大,不要尝试共享依赖,让两个应用各自打包独立依赖包,避免版本冲突。
  • 样式隔离:给两个应用的样式添加独特前缀,或在组件中使用ViewEncapsulation.ShadowDom,防止样式相互污染。
  • 内存管理:动态加载旧组件后,在不需要时调用componentRef.destroy()销毁实例,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:07:21