什么是微前端?
主应用配置
采用 Angular 作为主应用基座,接入不同的子Angular项目构建angular主应用基座
使用angular cli生成angular项目
在主应用中安装 qiankun
将普通的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;
}
},
});
}
}
}
4 在主应用的某个路由页面加载微应用
注册微应用时仅需要在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,
},
微应用配置
1 使用angular cli生成angular项目
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,导出 bootstrap
、mount
、unmount
三个生命周期钩子,以供主应用在适当的时机调用。
新增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不需要,也可以
4 修改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;
}
5 设置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 :