文章概述
实践微前端-angular+qiankun - 从 0 到 1 篇
实践微前端-angular+qiankun - 通信和项目Nginx发布已经在紧张编写测试(欢迎回访)
引言
大家好~
本文是基于 qiankun + single-spa 的微前端最佳实践系列文章之 从 0 到 1 篇,本文将分享如何使用 qiankun + single-spa 如何搭建主应用基座,然后接入Angular技术栈的微应用,完成微前端架构的从 0 到 1。
本教程采用 Angular 作为主应用基座,接入不同的子Angular项目。
为什么需要微前端(Micro Front-end)
- 系统模块增多,单体应用变得臃肿,开发效率低下,构建速度变慢;
- 人员扩大,需要多个前端团队独立开发,独立部署,如果都在一个仓储中开发会带来一些列问题;
- 解决遗留系统,新模块需要使用最新的框架和技术,旧系统还继续使用。
构建Angular主应用基座
我们先使用 Angular-cli 生成一个 Angular 的项目,初始化主应用。
ng new mango-pro --skipTests=true --style=less --prefix=mango
--style=less 用于样式文件的文件扩展名或预处理器。--skipTests=true 如果为true,则不会为新项目生成"spec.ts"测试文件。
--prefix mango 适用于初始项目的生成选择器的前缀。
在主应用中安装 qiankun
npm i qiankun -S
将普通的项目改造成 qiankun 主应用基座,需要进行三步操作:
- 创建微应用容器 - 用于承载微应用,渲染显示微应用
- 注册微应用 - 设置微应用激活条件,微应用地址等等;
- 启动 qiankun;
创建微应用容器
我们先在主应用中创建微应用的承载容器,这个容器规定了微应用的显示区域,微应用将在该容器内渲染并显示。
我们先设置路由,路由文件规定了主应用自身的路由匹配规则,代码实现如下:
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
data: { title: '仪盘表' },
},
]
从上面的分析可以看出,我们使用了在路由表配置的 dashboard 字段进行判断,判断当前路由是否为主应用路由,最后决定渲染主应用组件或是微应用节点。
由于篇幅原因,样式实现代码就不贴出来了,最后主应用的实现效果如下图所示:
注册微应用
在构建好了主框架后,我们需要使用 qiankun 的 registerMicroApps 方法注册微应用,代码实现如下:
import { addGlobalUncaughtErrorHandler, loadMicroApp, registerMicroApps, start } from 'qiankun';
/**
* 路由监听
* @param {*} routerPrefix 前缀
*/
function genActiveRule(routerPrefix) {
// hash 路由设置
return (location) => location.hash.startsWith(routerPrefix);
// 普通路由设置
// return (location) => location.pathname.startsWith(routerPrefix);
}
/**
* 注册微应用
* 第一个参数 - 微应用的注册信息
* 第二个参数 - 全局生命周期钩子
*/
registerMicroApps(
[
// 这里注释的是可以借鉴的,之前测试留下的(还是有用的)。为什么放在这里,
// 因为还会介绍一种在实际项目中手动加载子应用的。
// {
// name: 'mango-iview', // app name registered
// entry: '//localhost:4300',
// container: document.getElementById('mango-iview-label'), // 标签id
// activeRule: genActiveRule('#/dashboard'),
// props: { microName: '我是父应用呀!', micro: 'micro' },
// },
// {
// name: 'AngularMicroApp', // app name registered
// entry: '//localhost:4300',
// container: '#angular_micro',
// activeRule: genActiveRule('/one'),
// props: { microName: '我是父应用呀!' },
// },
],
{
// qiankun 生命周期钩子 - 加载前
beforeLoad: (app: any) => {
// 加载子应用前,加载进度条
// NProgress.start();
console.log('before load', app.name);
return Promise.resolve();
},
// qiankun 生命周期钩子 - 挂载后
afterMount: (app: any) => {
// 加载子应用前,进度条加载完成
// NProgress.done();
console.log('after mount', app.name);
return Promise.resolve();
},
},
);
/**
* 添加全局的未捕获异常处理器
*/
addGlobalUncaughtErrorHandler((event: Event | string) => {
console.error(event);
const { message: msg } = event as any;
// 加载失败时提示
if (msg && msg.includes("died in status LOADING_SOURCE_CODE")) {
console.error("微应用加载失败,请检查应用是否可运行");
}
});
// 导出 qiankun 的启动函数
export default start;
调用qiankun
我们在注册好了微应用,导出 start 函数后,我们需要在合适的地方调用 start 启动主应用。
我们一般是在入口文件启动 qiankun 主应用,也就是在main.ts中代码实现如下:
import start from './micro/qiankun';
start();
最后,启动我们的主应用,效果图如下:
因为我们还没有注册任何微应用,所以这里的效果图和上面的效果图是一样的。
到这一步,我们的主应用基座就创建好啦!
接入微应用
我们现在的主应用基座只有一个主页,现在我们需要接入微应用。
qiankun 内部通过 import-entry-html 加载微应用,要求微应用需要导出生命周期钩子函数(见下图)。
从上图可以看出,qiankun 内部会校验微应用的生命周期钩子函数,如果微应用没有导出这三个生命周期钩子函数,则微应用会加载失败。
如果我们使用了脚手架搭建微应用的话,我们可以通过 webpack 配置在入口文件处导出这三个生命周期钩子函数。如果没有使用脚手架的话,也可以直接在微应用的 window 上挂载这三个生命周期钩子函数。
接入 Angular 微应用
Angular 与 qiankun 目前的兼容性并不太好,接入 Angular 微应用需要一定的耐心与技巧。
对于选择 Angular 技术栈的前端开发来说,对这类情况应该驾轻就熟(没有办法)。
使用 angular-cli 先创建一个 Angular 的项目,在命令行运行如下命令:
ng new mango-iview --skipTests=true --style=less --prefix=iview
--style=less 用于样式文件的文件扩展名或预处理器。--skipTests=true 如果为true,则不会为新项目生成"spec.ts"测试文件。
--prefix iview 适用于初始项目的生成选择器的前缀。
然后,我们给子应用添加一些内容,最后效果如下:
注册微应用
- 在构建好了主框架后,我们需要使用 qiankun 的 registerMicroApps 方法注册微应用,代码实现如下:
(有一点重复但是还是以看懂为主,不然代码不全理解的会很晦涩难懂,一头雾水!)
import { loadMicroApp, registerMicroApps, start } from 'qiankun';
/**
* 路由监听
* @param {*} routerPrefix 前缀
*/
function genActiveRule(routerPrefix) {
// hash 路由设置
return (location) => location.hash.startsWith(routerPrefix);
// 普通路由设置
// return (location) => location.pathname.startsWith(routerPrefix);
}
// loadMicroApp(
registerMicroApps(
[
{
name: 'mango-iview', // app name registered
entry: '//localhost:4300',
container: document.getElementById('mango-iview-label'), // 标签id
activeRule: genActiveRule('#/dashboard'),
props: { microName: '我是父应用呀!', micro: 'micro' },
},
// {
// name: 'AngularMicroApp', // app name registered
// entry: '//localhost:4300',
// container: '#angular_micro',
// activeRule: genActiveRule('/one'),
// props: { microName: '我是父应用呀!' },
// },
],
{
// qiankun 生命周期钩子 - 加载前
beforeLoad: (app: any) => {
// 加载子应用前,加载进度条
// NProgress.start();
console.log('before load', app.name);
return Promise.resolve();
},
// qiankun 生命周期钩子 - 挂载后
afterMount: (app: any) => {
// 加载子应用前,进度条加载完成
// NProgress.done();
console.log('after mount', app.name);
return Promise.resolve();
},
},
);
// 导出 qiankun 的启动函数
export default start;
这里需要注意路由的设置,是不是hash 类型,如果是的话就和代码一样,如果不是那路由就换成注释的路由代码(具体看代码注释内容:路由监听)。
容器(container)对应的id -> "mango-iview-label" 应该放在index.html中。
但是这样又不符合项目使用,所以之后会介绍手动加载路由的方法。
- 手动加载子应用的方法
适用于大多数需要吧子应用放在自己的component组件里面的需求,切换页面也可以卸载A子组件加载B子组件。
在新建项目完成后,我们创建几个路由页面再加上一些样式,最后效果如下:
如图所示在dashboard组件id为"mango-iview-label"的div上面加载子组件iview子应用。
在组件视图渲染完成后,获取div标签然,后手动加载该子应用。
可以两种方式都试一试,根据自己具体的业务场景和需求来选择使用。
配置微应用
在主应用的工作完成后,我们还需要对微应用进行一系列的配置。首先,我们使用 single-spa-angular 生成一套配置,在命令行运行以下命令:
ng add single-spa
ng add single-spa-angular
在生成 single-spa 配置后,我们需要进行一些 qiankun 的接入配置。我们在 Angular 微应用的入口文件 main.single-spa.ts 中,导出 qiankun 主应用所需要的三个生命周期钩子函数,代码实现如下:
从上图来分析:
- 第 18 行:微应用独立运行时,直接执行挂载函数挂载微应用。
- 第 34 行:微应用导出的生命周期钩子函数 - bootstrap。
- 第 35 行:微应用导出的生命周期钩子函数 - mount。
- 第 36 行:微应用导出的生命周期钩子函数 - unmount。
完整代码实现如下:
import { enableProdMode, NgZone } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { Router } from '@angular/router';
import { ɵAnimationEngine as AnimationEngine } from '@angular/animations/browser';
import { singleSpaAngular, getSingleSpaExtraProviders } from 'single-spa-angular';
// 微应用单独启动时运行(不引用单独访问子应用会失败)
import 'zone.js/dist/zone';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { singleSpaPropsSubject } from './single-spa/single-spa-props';
if (environment.production) {
enableProdMode();
}
// 微应用单独启动时运行
if (!(window as any).__POWERED_BY_QIANKUN__) {
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.error(err));
}
const lifecycles = singleSpaAngular({
bootstrapFunction: (singleSpaProps) => {
singleSpaPropsSubject.next(singleSpaProps);
return platformBrowserDynamic(getSingleSpaExtraProviders()).bootstrapModule(AppModule);
},
template: '<iview-root />',
Router,
NgZone,
AnimationEngine,
});
export const bootstrap = lifecycles.bootstrap;
export const mount = lifecycles.mount;
export const unmount = lifecycles.unmount;
在配置好了入口文件 main.single-spa.ts 后,我们还需要配置 webpack,使 main.single-spa.ts 导出的生命周期钩子函数可以被 qiankun 识别获取。
在pack.json文件里面会自动生成build:microxxxx,和start:microxxxx,我们把端口号修改成我们想要的直接启动就可以了!(见下图)
修改完成后,我们启动 Angular 微应用http://localhost:4300。此时我们的 Angular 微应用被正确加载啦!(见下图)
最终效果
如图可见,我们的子应用可以独立访问,也当作一个单独的项目运行。也可以加载进主应用当作主基站的一个模块来展示。
项目结构总览
最后一件事
如果您已经看到这里了,希望您还是点个赞再走吧~
您的点赞是对作者的最大鼓励,也可以让更多人看到本篇文章!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。