Tao - 道
Tao 是一个基于 iframe 实现的微前端集成方案,可以在主应用中以 iframe 的形式集成子应用,同时提供了与 qiankun 子应用共用的通信 api,与 qiankun 一起承载微前端的架构实现。
安装
npm i -S @fescotech/tao@latest
api 说明
目前提供包括加载子应用、通信等 4 个接口
- loadMicroAppIframe: 加载 iframe 子应用
- getAppMode: 获取 app 当前运行模式
- initIframeBridge: 初始化 iframe 通信 bridge
- callMasterApi: 子应用通过该接口调用主应用暴露的 api
loadMicroAppIframe(app)
手动加载/卸载 iframe 子应用
参数
-
app - object - 必选,微应用的基础信息
- name - string - 必选,微应用的名称,确保在应用间唯一
- entry - string - 必选,微应用的入口地址, 如
//localhost:8080
- container - string - 必选,微应用的容器节点选择器,如
#iframe-container
- props - object - 可选,初始化时传递给微应用的数据
返回值
微应用的实例,实例包含以下属性/接口,可根据实际情况在合适时机调用
- 挂载应用 - mount(): Promise
- 卸载应用 - unmount(): Promise
- 应用启动结果 - bootstrapPromise: Promise
- 应用挂载结果 - mountPromise: Promise
- 应用卸载结果 - unmountPromise: Promise
用法/示例
以 react 主应用中加载一个 iframe 子应用为例
import { loadMicroAppIframe } from "@fescotech/tao";
import React from "react";
class App extends React.Component {
microApp = null;
componentDidMount() {
this.microApp = loadMicroAppIframe({
name: "app1",
entry: "//localhost:8080",
container: "#iframe-container",
props: {
message: "hello",
},
});
}
componentWillUnmount() {
this.microApp.unmount();
}
render() {
return <div id="iframe-container"></div>;
}
}
getAppMode()
获取应用当前运行模式
返回值
应用当前运行模式 - string
-
__independent__
: 独立运行 -
__iframe_micro_app__
: 微前端 iframe 子应用模式 -
__qiankun_micro_app__
: 微前端-乾坤子应用模式
用法/示例
import { getAppMode } from "@fescotech/tao";
const appMode = getAppMode();
initIframeBridge(appName)
初始化 iframe 通信 bridge,使用 postMessage 在 iframe 之间实现跨域通信
仅在子应用以 iframe 方式集成时需要初始化该 iframe 通信 bridge
参数
- appName - string - 可选,子应用初始化时传入子应用名称,主应用初始化时无需传参
返回值
iframe 通信 bridge 实例,实例包含 send 和 extends 两个接口,在一个 iframe 中通过 extends 注册接口,然后在其他 iframe 中就可以通过 send 调用对应接口,进行消息互通。
-
发送消息 - send(targetName,method,data,callback,type): Function
- targetName - string - 必选,目标窗口名称
- method - string - 必选,接口名称
- data - object - 必选,消息数据
- callback - function - 可选,消息回调
- type - string - 可选,消息类型
-
注册接口 - extends(name,func): Function
- name - string - 必选, 接口名称
- func - function - 必选,接口函数
用法/示例
比如,主应用初始化 call_master_api
接口,以供子应用调用
IframeBridgeInstance.extends("call_master_api",function (data) {
console.log("调用主应用接口:",data);
const method = data.method;
const params = data.params;
const result = window.__FESCOIE_TAO_MASTER_APIS__[method](params);
console.log(
`调用主应用__FESCOIE_TAO_MASTER_APIS__.${method},参数params:[${JSON.stringify(
params
)}],返回结果: `,
result
);
return result;
});
然后在 iframe 子应用中同样初始化 iframe 通信 bridge 后,调用已在主应用注册的 call_master_api
方法
IframeBridgeInstance.send(
"master",
"call_master_api",
{ method: api,params },
(data) => {
console.log(data);
}
);
callMasterApi(api,params)
调用主应用暴露的 api 从而实现子应用向主应用通信。主应用提供接口集合并暴露,按照一定的约定方式供子应用调用,屏蔽 iframe 子应用和 qiankun 子应用的通信差异。
参数
- api - sting - 必选,调用 api 名称,必须已经在主应用的
window.FESCOIE_TAO_MASTER_APIS
中暴露出来 - params - object - 可选,调用 api 的参数
返回值
接口调用返回值 - promise
用法/示例
1. 主应用定义接口集合并调用@fescotech/tao 中的 initMasterApis 进行初始化
// 主应用 main.js
import { message } from "antd";
import { initMasterApis } from "@fescotech/tao";
// 主应用暴露给子应用的api集合
const masterApi = {
// 获取用户信息
getUserInfo: function (params: any) {
let userInfo;
if (params.type === "1") {
userInfo = {
type: "1",
name: "李四",
age: 18,
};
} else {
userInfo = {
type: "0",
name: "张三",
age: 18,
};
}
return userInfo;
},
// 弹出消息
showMessage: function (params: any) {
message.success(params.text);
},
};
// 初始化api集合
initMasterApis(masterApi);
2.子应用初始化 iframe 通信通道
- 引入 tao 中的 initFrameBridge 并初始化
- name 参数为包名,需与在主应用注册的应用名称一致。
- 如果子应用确定不会以 iframe 形式接入,则可跳过此步骤
// main.js中
import { initIframeBridge } from "@fescotech/tao";
const { name } = require("../package.json");
initIframeBridge(name);
3.子应用调用主应用 api
-
iframe 子应用和 qiankun 子应用调用方式相同
-
调用前需引入 tao 中的 callMasterApi,然后使用此接口调用主应用 api,返回 promise
以 Vue2 子应用为例
import { callMasterApi } from "@fescotech/tao";
export default {
data() {
return {
userInfo: {},// 用户信息
};
},
methods: {
// 从主应用获取用户信息
getUserInfoFromMaster() {
callMasterApi("getUserInfo",{ type: "1" })
.then((res) => {
if (res.code === 0) {
this.userInfo = res.data;
}
})
.catch((error) => {
console.log(`子应用中调用主应用接口getUserInfo error: `,error);
});
},
// 主应用弹出消息
async showMessageInMaster() {
await ("showMessage",{ text: "消息来自子应用!" });
},
},
};