微前端基础知识入门篇(二)
# 概述
在上一篇介绍了一些微前端的基础知识,详见微前端基础知识入门篇一 (opens new window)。本文主要介绍qiankun
微前端框架的实战入门内容。
# qiankun
微前端实践
通过Vite
脚手架分别创建三个程序,主应用A为:vite
+vue3
+ts
,两个微应用分别为B:vite
+vue3
+ts
;C:vite
+React
+ts
。因为qiankun
的微应用是技术无关性,因此微应用可以是一个简单网页html
,也可以是任意前端框架搭建的一个网页应用。
三个应用分别安装qiankun
库,终端运行如下命令:
yarn add qiankun
# 微应用的注册
在主应用A中程序入口文件src/main.ts
中注册微应用如下:
import { createApp } from "vue";
import { registerMicroApps, start } from "qiankun";
import App from "./App.vue";
const app = createApp(App);
app.mount("#app");
registerMicroApps([
{
name: "B_App",
entry: "//localhost:5157",
container: "#main_container",
activeRule: "/cb",
},
{
name: "C_App",
entry: "//localhost:5158",
container: "#main_container",
activeRule: "/c",
},
]);
start();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 代码分析
registerMicroApps
函数
该函数是基于路由去配置微应用,其语法为:registerMicroApps(apps,lifeCycles?)
。
- 参数
apps
:必选,微应用的注册信息,其类型为Array<ReigsterableApp>
lifeCycles
:可选,全局的微应用生命周期钩子,其类型为LifeCycles
- 类型
RegisterableApp
:一个对象,其属性如下:name
:必选,微应用名称且唯一entry
:必选,微应用入口,可以是字符,表示微应用访问地址;也可以是对象,其属性html
对应的就是微应用的html
内容字符串container
:必选,#main_container
为微应用在主应用挂载的容器,可以是主应用中任意一个存在的DOM
元素,且多个微应用之间也是独立的,挂载的容器自不必相同。activeRule
:必选,微应用的激活规则,当主应用的地址栏url
匹配到改规则时,该微应用就会被激活,其值也可以是一个函数、数组字符串或者数组函数,函数接受的参数就是当前location
,函数的返回值是一个布尔值,true
表示匹配成功。loader
:可选,类型是一个函数接受一个布尔值,表示loading
状态,当其值发生变化时,会调用该函数props
:可选,类型是一个对象,可以用于主应用传递给微应用的数据
LifeCycles
:生命周期集合,每个属性值都是一个函数,或者是一个数组函数,函数返回一个Promise
,接受的参数是RegisterableApp
类型的对象,其属性可选值分别为beforeLoad
,beforeMount
,afterMount
,beforeUnmount
和afterUnmount
start()函数
start()
函数主要用于启动qiankun
主应用,其参数都是可选的,如下
prefetch
:是否开启微应用的静态资源预加载,默认值是true
,其值可以为下面几个true
:第一个微应用mountted
后,开始预加载其余微应用的静态资源all
:主应用start
后就开始预加载所有微应用静态资源string[]
:在第一个微应用mounted
后开始加载数组内的微应用资源function
:自定义微应用的资源加载时机
sandbox
:是否开启沙箱,默认为true
,其值也可以是一个对象{strictStyleIsolation:boolean,experimentalStyleIsolation:boolean}
,表示是否开启严格的样式隔离,默认情况下会为每个应用的容器包裹一个shadow dom
节点,从而隔离样式。singular
:可选,表示是否是单实例场景,即同一时间只会渲染一个微应用,默认为true
fetch
:用来定制请求微应用资源的方式的一个配置项。它可以用来替换默认的资源获取方式。允许开发者自定义获取微应用资源(如JS
、CSS
文件等)的方式getPublicPath
:用来获取微应用的公共路径getTemplate
:用于动态获取微应用的HTML
模板excludeAssetFilter
: 过滤不需要加载的静态资源,优化性能
# 微应用的改造
前面通过Vite
创建了两个应用B
和C
,在这两个应用中分别都安装qiankun
和vite-plugin-qiankun
,使之成为一个微应用
# B
微应用
B
微应用的技术体系是vite
+vue3
+ts
,在其配置文件vite.config.ts
中引入qiankun
,配置如下:
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import qiankun from "vite-plugin-qiankun";
export default defineConfig({
plugins: [vue(), qiankun("vue-B-app", { useDevMode: true })],
server: {
port: 5157, //固定端口
},
});
2
3
4
5
6
7
8
9
10
第二步就是修改其入口文件main.ts
,如下:
import { createApp } from "vue";
import {
renderWithQiankun,
qiankunWindow,
QiankunProps,
} from "vite-plugin-qiankun/dist/helper";
import "./style.css";
import App from "./App.vue";
const app = createApp(App);
let root:any = null;
function render(props: QiankunProps) {
const { container } = props;
const node = container
? container.querySelector("#app")
: document.getElementById("app");
console.log("🚀 ~ render ~ node:", node);
root=app.mount(node)
return root;
}
renderWithQiankun({
mount(props: any) {
root = render(props);
},
bootstrap() {},
unmount(props: any) {
console.log(props);
root?.unmount();
},
update(props: any) {
console.log(props);
},
});
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
root = render({});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# C
微应用
C
微应用的技术体系是vite
+react
+ts
,由于都是vite
搭建的,所以其改动也差不多,不同的是main.ts
中render
部分,如下:
function render(props: QiankunProps) {
const { container } = props;
console.log("🚀 ~ render ~ container:", container)
const node = container
? container.querySelector("#root")
: document.getElementById("root");
console.log("🚀 ~ render ~ node:", node)
root = createRoot(node!);
root.render(<App />);
return root;
}
2
3
4
5
6
7
8
9
10
11
之所以不同是因为vue3
和React
挂载节点方式的区别,这个render
函数兼顾了各自的微应用独立运行和作为微应用运行两种方式。
# vite-plugin-qiankun
插件
顾名思义,vite-plugin-qiankun
插件就是为vite
搭建的应用量身定制的一款插件。我们可以来分析它在上述用到的renderWithQiankun
方法和qiankunWindow
变量。
renderWithQiankun
其实现如下:
var renderWithQiankun = function (qiankunLifeCycle) {
if (qiankunWindow === null || qiankunWindow === void 0 ? void 0 : qiankunWindow.__POWERED_BY_QIANKUN__) {
if (!window.moudleQiankunAppLifeCycles) {
window.moudleQiankunAppLifeCycles = {};
}
if (qiankunWindow.qiankunName) {
window.moudleQiankunAppLifeCycles[qiankunWindow.qiankunName] = qiankunLifeCycle;
}
}
};
2
3
4
5
6
7
8
9
10
由上可知,renderWithQiankun
函数的作用就是在确认当前应用为微应用时,会将其参数挂载到全局对象window.moudleQiankunAppLifeCycles
上,qiankunName
就是微应用在在主应用注册时的name
值。
qiankunWindow
qiankunWindow
本质上就是window
对象,其值如下:
var qiankunWindow = typeof window !== 'undefined' ? (window.proxy || window) : {}; //代理优先级最高