微前端-angular+qiankun+single-spa

什么是微前端?

主应用配置

采用 Angular 作为主应用基座,接入不同的子Angular项目构建angular主应用基座

使用angular cli生成angular项目

ng new main

在主应用中安装 qiankun

yarn add qiankun -D

将普通的angular项目改成主应用基座

1 在layout页面添加微应用容器

<nz-content class="content">
    <div id="micro-app-container"></div>
    <router-outlet></router-outlet>
</nz-content>

2 注册微应用

export class AppComponent implements OnInit {
  CONTAINER = '#micro-app-container';
  microApps = [];
  constructor(private router: Router, private startSvc: StartService) { }

  ngOnInit(): void {
    const apps = this.startSvc.getConfig().MicroApps;
    if (apps && apps.length > 0) {
      apps.forEach((entry: any) => {
        const paths = `/micro/${entry.Path}`;
        const name = entry.Name;
        const app = {
          name: name,
          entry: paths,
          container: this.CONTAINER,
          activeRule: () => {
            return this.canActive(`/${name}`);
          },
        };
        this.microApps.push(app);
      });

      registerMicroApps(this.microApps);
    }
  }

  canActive(url: string) {
    return this.router.url.startsWith(url);
  }

}

3 添加微应用加载器MicroComponent,统一处理微应用资源引导,启用微应用

export class MicroComponent implements OnInit, AfterViewInit {
  CONTAINER = '#micro-app-container';
  constructor(private startSvc: StartService) { }

  ngOnInit(): void {
  }

  ngAfterViewInit(): void {
    const apps = this.startSvc.getConfig().MicroApps;

    if (!window.qiankunStarted && apps && apps.length > 0 && document.getElementById(this.CONTAINER)) {
      window.qiankunStarted = true;
      start({
        prefetch: 'all',
        // 指定部分特殊的动态加载的微应用资源(css/js) 不被 qiankun 劫持处理
        excludeAssetFilter: (assetUrl: string) => {
          if (assetUrl.includes('/assets/')) {
            return true;
          }
        },
      });
    }
  }
}

 

在主应用的某个路由页面加载微应用 

注册微应用时仅需要在app-routing.ts添加相应的path即可:

{
        path: 'project',
        component: MicroComponent,
        children: [{ path: '**', component: EmptyComponent }],
      },

配置开发环境proxy
在开发环境中,主应用和微应用分别运行在两个不同的进程(网站)中。调试时应在proxy.conf.js 配置代理

{
    context: ['/micro/project'],
    target: 'http://localhost:4200', //微应用地址
    secure: false,
 },

 

微应用配置

使用angular cli生成angular项目

ng new micro

2 在微应用中安装 single-spa-angular 插件来配置微应用 参考 single-spa-angular 的官网 和 angular demo 

ng add single-spa-angular

angular.json: builder改成了自定义Webpack构建器 "builder": "@angular-builders/custom-webpack:browser";主文件入口改成了main.single-spa.ts

tsconfig.app.json: 解决 zone.js 的问题:1在父应用引入 zone.js,需要在 import qiankun 之前引入。2将微应用的 src/polyfills.ts 里面的引入 zone.js 代码删掉。

新增extra-webpack.config.js,主要作用是允许开发环境跨域和 umd 打包,让主应用能正确识别微应用暴露出来的一些信息

新增的main.single-spa.ts,导出 bootstrapmountunmount 三个生命周期钩子,以供主应用在适当的时机调用。

新增emptyRouteComponet,为应用间跳转做过度。asset-url.ts,动态加载子应用内assets时,能正确引入assets资源。

 

3 修改angular.json

"architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "baseHref": "/micro/project/",
            "deployUrl": "/micro/project/",
            "outputPath": "wwwroot/micro/project",
            "index": "src/index.html",
            "main": "src/main.single-spa.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": true,
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.less"
            ],
            "scripts": [],
            "customWebpackConfig": {
              "path": "extra-webpack.config.js",
              "libraryName": "micro",
              "libraryTarget": "umd"
            }
          },
...
}
...
}

 

4和5不需要,也可以

修改public-path

在入口文件main.micro.ts修改__webpack_public_path__ 

__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ + 'project/'

需在typing.d.ts文件声明

declare var __webpack_public_path__;

interface Window {
  __POWERED_BY_QIANKUN__: any;
  __INJECTED_PUBLIC_PATH_BY_QIANKUN__: any;
}

设置APP_BASE_HREF

当微应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子。

为使微应用能够正确接入基座,应在root.module.ts中设置APP_BASE_HREF 。  

providers: [
    { provide: APP_BASE_HREF, useValue: window.__POWERED_BY_QIANKUN__ ? '/' : '/micro/' },
  ],

 

6 路由配置

业务相关路由初始化时,第一级路由的path应当以微应用编码命名,并在children里追加下级路由:

EmptyRouteComponent,为应用间跳转做过度,解决 cannot match url 的报错问题
const routes: Routes = [
  {
    path: 'project',
    // canActivateChild: [RightGuard],
    children: [
      { path: '', redirectTo: 'week', pathMatch: 'full' },
        { path: 'apply', component: ApplyComponent },
        { path: 'statistics', component: StatisticsComponent },
        { path: 'setting', component: SettingComponent },
      { path: '**', redirectTo: '/404' },
    ],
  },
  { path: '**', component: EmptyRouteComponent },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})

 

7 差异化app-root

为了防止主应用或其他微应用也为 angular 时,<app-root></app-root> 会冲突的问题,需要为<app-root> 加上唯一的 id,并以当前应用的业务模块编码命名。

src/index.html :

- <app-root></app-root>
+ <app-root id="project"></app-root>

src/app/root.component.ts :

- selector: 'app-root',
+ selector: '#project app-root',

 

 

 

posted @ 2022-01-21 18:07  litiyi  阅读(1146)  评论(0编辑  收藏  举报