无界微前端学习和使用
无界微前端
- 无界微前端技术
- 快速使用
- 新建三个项目
- 安装无界
- 使用
- 增加路由
- 主应用路由
- 子应用vue路由
- 通信
- props 通信
- eventBus 通信
- window 通信
- 兼容
- 生命周期
- 改造子应用
- 改造主应用
- 运行模式
- 保活模式
- 单例模式
- 重建模式
无界微前端技术
官网:无界
和其他微前端技术一样,该有的都有。和qiankun的对比。

无界

iframe负责逻辑,webComponent负责Dom。
如果是新项目,且相当使用比较新的浏览器,可以考虑无界,开箱即用,当然无界也提供了兼容的降级处理。
快速使用
无界已经帮我们封装好了vue和react的使用。
vue
react
新建三个项目
新建一个文件夹wujie,执行下面的命令三次,主应用选择Vue,其他两个项目分别为vue和react。
npm init vite@latest

安装无界
在主应用中,安装wujie
# vue2 框架
npm i wujie-vue2 -S
# vue3 框架
npm i wujie-vue3 -S
分别启动三个项目。
npm run dev
port:我这里的主应用为5173,子vue为5174,子react为5175。
使用
在主应用的App.vue中
<script setup>
import WujieVue from 'wujie-vue3';
</script>
<template><div><WujieVue url="http://localhost:5174" name="vue" /></div>
</template>
在子vue应用App.vue


把主应用Aoo.vue中的子应用链接改为5175

增加路由
主应用和vue子应用安装 vue-router
npm install vue-router@4
主应用路由
在src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';const router = createRouter({history: createWebHistory(),routes: [{path: '/',name: 'Home',component: () => import('../views/Home.vue'),},{path: '/about',name: 'About',component: () => import('../views/About.vue'),},{path: '/vue/:pathMatch(.*)*',name: 'vue',component: () => import('../views/AppContainer.vue'),},],
});export default router;
新增文件

在AppContainer.vue中
<template><WujieVue :url="path" name="vue" />
</template><script setup>
import { computed } from 'vue';
import { useRoute } from 'vue-router';const baseUrl = 'http://localhost:5174/';const route = useRoute();const path = computed(() => {const pathMatch = route?.params?.pathMatch || [];return baseUrl + pathMatch.join('/');
});
</script><style></style>
在main.js引入路由

在 App.vue
<script setup></script><template><div><div><router-link to="/">home | </router-link><router-link to="/about">about | </router-link><router-link to="/vue/about">vue | </router-link><router-link to="/vue/">vue1 </router-link></div><div><router-view v-slot="{ Component }"><transition name="fade"><keep-alive :include="['Home', 'AppContainer']"><component :is="Component" /></keep-alive></transition></router-view></div></div>
</template><style scoped>
.logo {height: 6em;padding: 1.5em;will-change: filter;transition: filter 300ms;
}
.logo:hover {filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
子应用vue路由

Home.vue
<template><div>首页<button @click="toAbout">去About</button><HelloWorld msg="Vite + Vue" /></div>
</template><script setup>
import { useRouter } from 'vue-router';
import HelloWorld from '../components/HelloWorld.vue';const router = useRouter();const toAbout = () => {router.push('/about');
};
</script><style></style>
App.vue
<div><router-view></router-view></div>
尝试下

但是这里的话,在vue1这里,进入子应用About,刷新后会在vue子应用首页。



通信
父子应用之间的通信。
文档
props 通信
父应用传递给子应用数据和方法。
父AppContainer.vue
<template><div><h4>父:{{ count }}</h4><WujieVue:url="path":props="{ data: { count }, add }":sync="true"name="vue"/></div>
</template><script setup>
import { computed, ref } from 'vue';
import { useRoute } from 'vue-router';const count = ref(0);
const add = () => {count.value++;
};const baseUrl = 'http://localhost:5174/';const route = useRoute();const path = computed(() => {const pathMatch = route?.params?.pathMatch || [];return baseUrl + pathMatch.join('/');
});
</script><style></style>
子About,vue
<template><div><h5>子{{ props.data.count }}</h5><button @click="countAdd">Count++</button></div>
</template><script setup>
const props = window.$wujie?.props;
const countAdd = () => {props.add();
};
</script><style></style>

子中数据没更新。
eventBus 通信
我们可以让父应用发出数据更新的事件,让子应用接受到事件后更新显示。
更新AppContainer.vue代码

更新子应用About.vue代码
<template><div><h5>子{{ count }}</h5><button @click="countAdd">Count++</button></div>
</template><script setup>
import { ref } from 'vue';const props = window.$wujie?.props;
const count = ref(props?.data?.count || 0);const countAdd = () => {props.add();
};
window.$wujie?.bus.$on('add', function (num) {count.value = num;
});
</script><style></style>

window 通信
在子应用About.vue中

在主应用AppContainer.vue中



兼容
降级处理。

无界会自动处理,如果你想强制开启

开启后变成这样了
要做一些样式调整。
比如给容器加个高度

主应用style.css调整iframe样式
/* 主页面 CSS */
iframe {/* 消除边框 */border: none;/* 消除内边距和外边距 */padding: 0;margin: 0;/* 可选:设置宽高(避免默认尺寸过小) */width: 100%;height: 100%;/* 可选:隐藏溢出内容(避免默认滚动条) */overflow: hidden;
}
子应用的宽高调整等等,但是最好判断下是不是无界启动,还是单独启动。


生命周期
需要在子应用进行生命周期改造。


改造子应用
这里和qiankun的很像。
if (window.__POWERED_BY_WUJIE__) {console.log('wujie vue child');let instance;window.__WUJIE_MOUNT = () => {instance = createApp(App);instance.use(router);instance.mount('#app');};window.__WUJIE_UNMOUNT = () => {instance.unmount();};/*由于vite是异步加载,而无界可能采用fiber执行机制所以mount的调用时机无法确认,框架调用时可能vite还没有加载回来,这里采用主动调用防止用没有mount无界mount函数内置标记,不用担心重复mount*/window.__WUJIE.mount();
} else {createApp(App).use(router).mount('#app');
}

改造主应用



运行模式

这里我们每次切换路由,都会触发生命周期函数。
保活模式



开启保活模式后 只在首次触发。但是他会额外的触发

如果我们做B端,比如重构的时候,运行在新项目,但是新项目是需要时间来重构的,怎么办呢,按照官方说法,不推荐保活模式,推荐单例模式。
单例模式
我们刚刚进行了生命周期改造,把保活模式去掉,就是单例模式。

但是按照刚刚的生命周期方法做,路由显示会有问题。

可能我的打开方式不对。
在主应用中通知路径,在子应用mount之前跳转。




重建模式
不配置保活,也不配置生命周期改造。
