- 安装 qiankun
 
- 增加子应用加载入口组件 
micro-app.component.ts
import { Component, ElementRef, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { MicroApp, loadMicroApp } from 'qiankun';
@Component({
  selector: 'micro-app',
  template: `
    <div id="haydnSccMicroApp"></div>
  `,
})
export class MicroAppComponent {
  public loading = true;
  public microApp: MicroApp;
  public port = this.route.snapshot.data.port;
  public name = this.route.snapshot.data.name;
  constructor(
    private el: ElementRef,
    private route: ActivatedRoute
  ) {}
  ngAfterViewInit() {
    this.microApp = loadMicroApp(
      {
        name: this.name,
        entry: this.getSubAppEntry(),
        container: this.el.nativeElement,
      },
      {
        singular: true,
      },
      {
        afterMount: () => {
          this.loading = false;
          return Promise.resolve();
        },
      }
    );
  }
  ngOnDestroy() {
    this.microApp.unmount();
  }
  getSubAppEntry() {
    // 开发模式加载子应用
    if (location.hostname === 'localhost') {
      const { hostname } = location;
      return `//${hostname}:${this.port}`;
    }
    // 线上环境根据项目部署方式调整
  }
}
 
- 路由配置
import { MicroAppComponent } from './micro-app.component';
const defaultRoutes: Routes = [
 {
   path: 'sub-app',
   canActivateChild: [],
   children: [
     {
       path: '**',
       component: MicroAppComponent,
       data: { port: '4200', name: 'sub-app' }, // name值与子应用package.json中name对应
     },
   ],
 },
]
 
- 在入口启动 qiankun
import { start } from 'qiankun';
// start();
// 这里踩坑了,具体问题参考 https://github.com/single-spa/single-spa-angular/issues/529#issuecomment-2503746846
start({ urlRerouteOnly: false });
 
- 添加文件 
src/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
 
- 修改 
main.ts
import './public-path';
import { enableProdMode, NgZone } from '@angular/core';
import { Router } from '@angular/router';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { singleSpaAngular, getSingleSpaExtraProviders } from 'single-spa-angular';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
  enableProdMode();
}
if (!(window as any).__POWERED_BY_QIANKUN__) {
  platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .catch(err => {});
}
const { bootstrap, mount, unmount } = singleSpaAngular({
  bootstrapFunction: singleSpaProps => {
    return platformBrowserDynamic(getSingleSpaExtraProviders()).bootstrapModule(AppModule);
  },
  template: '<sub-app-root />',
  Router,
  NgZone,
});
export { bootstrap, mount, unmount };
 
- 修改 
src\polyfills.ts,注释掉 zone.js 的引入 
- 修改 webpack 配置
const singleSpaAngularWebpack = require('single-spa-angular/lib/webpack').default;
const appName = require('../package.json').name;
const DefinePlugin = require('webpack/lib/DefinePlugin');
const { merge } = require('webpack-merge');
module.exports = (angularWebpackConfig, options) => {
  const singleSpaWebpackConfig = singleSpaAngularWebpack(angularWebpackConfig, options);
  const config = {
    devServer: {
      headers: {
        'Access-Control-Allow-Origin': '*',
      },
    },
    output: {
      library: `${appName}-[name]`,
      libraryTarget: 'umd',
      chunkLoadingGlobal: `webpackJsonp_${appName}`,
    },
  };
  const mergedConfig = merge(singleSpaWebpackConfig, config);
  return mergedConfig;
};
 
- 修改路由配置
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LayoutEmptyComponent } from '../layout/empty/empty.component';
const routes: Routes = [
  {
    path: 'sub-app', // 此处需要定义与主项目中相同的路由
    children: [], // 路由定义放到children下
  },
  {
    path: '**', // 必须要定义,否则匹配不到路由时会报错
    component: LayoutEmptyComponent,
  },
];
@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      useHash: true,
      scrollPositionRestoration: 'top',
    }),
  ],
  exports: [RouterModule],
  // 为什么不采用下面的方式,而是重复定义与主项目相同的路由名称?
  // 通过 routerLink 跳转时会自动带上 /sub-app 前缀,要跳转到非当前子应用路由时路径会错误,而使用上面的方法可以直接使用routerLink跳转到非当前子应用定义的路由页面
  providers: [
   { provide: APP_BASE_HREF, useValue: window.__POWERED_BY_QIANKUN__ ? '/sub-app' : '/' },
 ],
})
export class RouteRoutingModule {}