基于 qiankun 的微前端应用
主应用
qiankun: 2.4.7
angular: 7.0.0
子应用
singlw-spa: 3.6.0
angular: 7.0.0
配置
构建主应用基座(Angular)
-
创建微应用容器 - 用于承载微应用,渲染显示微应用;
在主应用中创建微应用的承载容器,这个容器规定了微应用的显示区域,微应用将在该容器内渲染并显示。
qiankun demo 中是挂载到根目录,创建方法如下:
- 首先设置路由
const routes = [ { /** * path: 路径为 / 时触发该路由规则 * name: 路由的 name 为 Home * component: 触发路由时加载 `Home` 组件 */ path: "/", name: "Home", component: Home, },- 配置主应用和微应用的渲染区
<!--渲染主应用--> <router-outlet></router-outlet>、 <!-- 渲染子应用,subapp-viewport 之后就是根据这个id去注册微应用--> <main id="subapp-container" (autocomplete)="title"> <div id="subapp-viewport"></div> </main>但是根据我们的需求和代码目录结构,选择将子应用挂载到子组件中
1.1 如何在主应用的某个路由页面加载微应用?
-
注册微应用 - 设置微应用激活条件,微应用地址等等;
这部分 qiankun 有点bug ,所以我在网上找了重新封装的代码,直接放掉项目就好(asset/micro), 具体注册的方法封装在 index.ts 中。我们只要在 apps.ts 里面配置我们需要注册的微应用即可。
const apps = [ /** * name: 微应用名称 - 具有唯一性 * entry: 微应用入口 - 通过该地址加载微应用 * container: 微应用挂载节点 - 微应用加载完成后将挂载在该节点上 * activeRule: 微应用触发的路由规则 - 触发路由规则后将加载该微应用 */ { name: "AngularMicroApp", entry: "//localhost:10300", container: "#subapp-viewport", activeRule: "/index/portal" } ]; export default apps; -
最后,启动 qiankun;
// 引用二次封装的 qiankun import startQiankun from '../../../../assets/micro'; // Angular 微应用一定要引入 zone ,否则会报错 import "zone.js/dist/zone"; ngAfterViewInit(): void { startQiankun(); }
接入微应用
微应用的配置有两种方式,一种是 qiankun 自己的,一种是用 single-spa.
angular7 版本使用qiankun 的配置方法报错,所以使用了 single-spa
-
在微应用中安装 single-spa-angular, angular8和angular7 安装 single-spa-angular 3.0 版本。angular9 及以上安装 single-spa-angular@4 版本
# 添加 single-spa-angular ng add single-spa-angular -
在入口文件 main.ts 中接入 qiankun 的配置,导出 qiankun 主应用所需要的三个生命周期钩子函数
import 'core-js/es7/reflect'; import './public-path'; import { enableProdMode, NgZone } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { Router } from '@angular/router'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; import singleSpaAngular, { getSingleSpaExtraProviders } from 'single-spa-angular'; import { singleSpaPropsSubject } from './single-spa/single-spa-props'; if (environment.production) { enableProdMode(); } function render(param?) { return platformBrowserDynamic(param).bootstrapModule(AppModule) } // 微应用单独启动时运行 if (!(window as any).__POWERED_BY_QIANKUN__) { render(); } const { bootstrap, mount, unmount } = singleSpaAngular({ bootstrapFunction: singleSpaProps => { singleSpaPropsSubject.next(singleSpaProps); return render(getSingleSpaExtraProviders()); }, template: '<micro-app-root />', Router, NgZone: NgZone, });
/** 主应用生命周期钩子中运行 */ export { bootstrap, mount, unmount }; ``` bootstrap: bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
mount: 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
unmount:应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例 、
3. 路由中 ngMOdle 增加 providers 属性
history 路由必须加上这个,Hash 路由不需要
```ts
@NgModule({
imports: [
RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules
})
],
exports: [RouterModule],
providers: [{ provide: APP_BASE_HREF, useValue: (window as any).__POWERED_BY_QIANKUN__ ? '/index/brm' : '/' }]
})
```
4. 配置 webpack,在根目录下新建 extra-webpack.config.js,使 main.ts 导出的生命周期钩子函数可以被 qiankun 识别获取。
```ts
// micro-app-angular/extra-webpack.config.js
const singleSpaAngularWebpack = require("single-spa-angular/lib/webpack")
.default;
const webpackMerge = require("webpack-merge");
module.exports = (angularWebpackConfig, options) => {
const singleSpaWebpackConfig = singleSpaAngularWebpack(
angularWebpackConfig,
options
);
const singleSpaConfig = {
output: {
// 微应用的包名,这里与主应用中注册的微应用名称一致
library: "AngularMicroApp",
// 将你的 library 暴露为所有的模块定义下都可运行的方式
libraryTarget: "umd",
},
};
const mergedConfig = webpackMerge.smart(
singleSpaWebpackConfig,
singleSpaConfig
);
return mergedConfig;
};
```
5. 配置 package.json 和 angular.json
/*package.json: 端口号要和在主应用中注册的端口号一致*/
{
"scripts": {
"ng": "ng",
"start": "ng serve --disable-host-check --port 10400",
},
}
/*angular.json:projects.[name].architect.options 添加下面这个属性*/
"customWebpackConfig": {
"path": "./extra-webpack.config.js",
"replaceDuplicatePlugins": true
}