微前端-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; } }, }); } } }
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, },
微应用配置
参考 angular微应用1 使用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 代码删掉。
新增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 时,
src/index.html :
-+ id="project">
src/app/root.component.ts :
- selector: 'app-root', + selector: '#project app-root',