无界微前端学习和使用

无界微前端

无界微前端技术

官网:无界

和其他微前端技术一样,该有的都有。和qiankun的对比。

无界

iframe负责逻辑,webComponent负责Dom。

如果是新项目,且相当使用比较新的浏览器,可以考虑无界,开箱即用,当然无界也提供了兼容的降级处理

快速使用

无界已经帮我们封装好了vue和react的使用。
vue
react

新建三个项目

新建一个文件夹wujie,执行下面的命令三次,主应用选择Vue,其他两个项目分别为vue和react。
npm init vite@latest

安装无界

在主应用中,安装wujie

bash 复制代码
# vue2 框架
npm i wujie-vue2 -S
# vue3 框架
npm i wujie-vue3 -S

分别启动三个项目。
npm run dev

port:我这里的主应用为5173,子vue为5174,子react为5175。

使用

在主应用的App.vue中

html 复制代码
<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

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

html 复制代码
<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

html 复制代码
<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

html 复制代码
<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

html 复制代码
 <div>
    <router-view></router-view>
  </div>

尝试下

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


通信

父子应用之间的通信。
文档

props 通信

父应用传递给子应用数据和方法。

AppContainer.vue

html 复制代码
<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

html 复制代码
<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代码

html 复制代码
<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 复制代码
/* 主页面 CSS */
iframe {
  /* 消除边框 */
  border: none;
  /* 消除内边距和外边距 */
  padding: 0;
  margin: 0;
  /* 可选:设置宽高(避免默认尺寸过小) */
  width: 100%;
  height: 100%;
  /* 可选:隐藏溢出内容(避免默认滚动条) */
  overflow: hidden;
}

子应用的宽高调整等等,但是最好判断下是不是无界启动,还是单独启动。

生命周期

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

改造子应用

这里和qiankun的很像。

js 复制代码
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之前跳转。

重建模式

不配置保活,也不配置生命周期改造。

相关推荐
一枚前端小能手3 小时前
🚀 Node.js 25重磅发布!快来看看吧
前端·javascript·node.js
csj503 小时前
前端基础之《React(3)—webpack简介-集成JSX语法支持》
前端·react
JarvanMo4 小时前
🚀 使用 GitHub Actions 自动化 Flutter CI/CD — Android 和 iOS (TestFlight) 部署
前端
濑户川4 小时前
Vue3 项目创建指南(Vue-CLI vs Vite 对比)
前端·javascript·vue.js
Mintopia4 小时前
🚀 Next.js 16 新特性深度解析:当框架开始思考人生
前端·后端·全栈
鼓掌MVP4 小时前
Rust Web实战:构建高性能并发工具的艺术
开发语言·前端·rust·异步编程·内存安全·actix-web·高性能web服务
终焉代码4 小时前
【C++】C++11特性学习(1)——列表初始化 | 右值引用与移动语义
c语言·c++·学习·1024程序员节
Mintopia4 小时前
🌌 元宇宙 Web 场景中,AIGC 驱动的虚拟内容生成技术
前端·javascript·aigc
excel4 小时前
一文彻底搞懂 Vue3 中 ref 的源码实现(含详细注释)
前端