微前端无界方案

微前端无界方案


介绍

无界利用 iframe 和 webcomponent 来搭建天然的 js 沙箱和 css 沙箱。

能够完善的解决适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 支持、应用共享等用户的核心诉求。

官方文档




无界的使用

主应用

1、引入
// 无框架时使用'wujie'
import Wujie from 'wujie';
// 当结合框架时使用'wujie-xxx'
// import Wujie from "wujie-vue2";
// import Wujie from "wujie-vue3";
// import Wujie from "wujie-react";

const {
    bus, setupApp, preloadApp, startApp, destroyApp } = Wujie;

提示

如果主应用是 vue 框架可直接使用 wujie-vue,react 框架可直接使用 wujie-react

2、设置子应用

【非必须】由于 preloadAppstartApp 的参数重复,为了避免重复输入,可以通过 setupApp 来统一设置默认参数。

setupApp({
   
  name: '唯一id',
  url: '子应用地址',
  exec: true,
  el: '容器',
  sync: true,
});
3-1、启动子应用
startApp({
    name: '唯一id' });
3-2、预加载
preloadApp({
    name: '唯一id' });
3-3、以组件形式调用

无界支持以组件的形式使用。

vue
安装
# vue2 框架
npm i wujie-vue2 -S
# vue3 框架
npm i wujie-vue3 -S
引入
// main.js

// vue2
import WujieVue from 'wujie-vue2';
// vue3
// import WujieVue from "wujie-vue3";

// 全局注册组件(以vue为例)
Vue.use(WujieVue);

const {
    bus, setupApp, preloadApp, startApp, destroyApp } = WujieVue;
使用

使用 组件,相当于使用了startApp来调用,因此可以忽略startApp的使用了!!

<template>
  <!-- 单例模式,name相同则复用一个无界实例,改变url则子应用重新渲染实例到对应路由 -->
  <WujieVue
    width="100%"
    height="100%"
    name="vue2"
    :url="vue2Url"
    :sync="true"
    :fetch="fetch"
    :props="props"
    :beforeLoad="beforeLoad"
    :beforeMount="beforeMount"
    :afterMount="afterMount"
    :beforeUnmount="beforeUnmount"
    :afterUnmount="afterUnmount"
  ></WujieVue>
  <!-- 子应用通过$wujie.bus.$emit(event, args)出来的事件都可以直接@event来监听 -->
</template>
<script>
  // import hostMap from "./hostMap";

  export default {
     
    computed: {
     
      vue2Url() {
     
        // 这里拼接成子应用的域名(例如://localhost:7200/home)
        return hostMap('//localhost:7200/') + `#/${
       this.$route.params.path}`;
      },
    },
  };
</script>
// hostMap.js
const map = {
   
  '//localhost:7100/': '//wujie-micro.github.io/demo-react17/',
  '//localhost:7200/': '//wujie-micro.github.io/demo-vue2/',
  '//localhost:7300/': '//wujie-micro.github.io/demo-vue3/',
  '//localhost:7500/': '//wujie-micro.github.io/demo-vite/',
};

export default function hostMap(host) {
   
  if (process.env.NODE_ENV === 'production') return map[host];
  return host;
}

WujieVue组件接收的参数如下:

WujieVue组件接收的参数基本上与startApp的一致。

不同之处在于startApphtmlel,没有widthheight

const wujieVueOptions = {
   
  name: 'WujieVue',
  props: {
   
    width: {
    type: String, default: '' },
    height: {
    type: String, default: '' },
    name: {
    type: String, default: '' },
    loading: {
    type: HTMLElement, default: undefined },
    url: {
    type: String, default: '' },
    sync: {
    type: Boolean, default: false },
    prefix: {
    type: Object, default: undefined },
    alive: {
    type: Boolean, default: false },
    props: {
    type: Object, default: undefined },
    replace: {
    type: Function, default: undefined },
    fetch: {
    type: Function, default: undefined },
    fiber: {
    type: Boolean, default: true },
    degrade: {
    type: Boolean, default: false },
    plugins: {
    type: Array, default: null },
    beforeLoad: {
    type: Function, default: null },
    beforeMount: {
    type: Function, default: null },
    afterMount: {
    type: Function, default: null },
    beforeUnmount: {
    type: Function, default: null },
    afterUnmount: {
    type: Function, default: null },
    activated: {
    type: Function, default: null },
    deactivated: {
    type: Function, default: null },
    loadError: {
    type: Function, default: null },
  },
};




子应用改造

无界对子应用的侵入非常小,在满足跨域条件下子应用可以不用改造。

1、前提

子应用的资源和接口的请求都在主域名发起,所以会有跨域问题,子应用必须做cors 设置

app.use((req, res, next) => {
   
  // 路径判断等等
  res.set({
   
    'Access-Control-Allow-Credentials': true,
    'Access-Control-Allow-Origin': req.headers.origin || '*',
    'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type',
    'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
    'Content-Type': 'application/json; charset=utf-8',
  });
  // 其他操作
});

2、生命周期改造

改造入口函数:

  • 将子应用路由的创建、实例的创建渲染挂载到window.__WUJIE_MOUNT函数上
  • 将实例的销毁挂载到window.__WUJIE_UNMOUNT
  • 如果子应用的实例化是在异步函数中进行的,在定义完生命周期函数后,请务必主动调用无界的渲染函数 window.__WUJIE.mount()
具体操作可以参考下面示例
// vue 2

if (window.__POWERED_BY_WUJIE__) {
   
  let instance;
  window.__WUJIE_MOUNT = () => {
   
    const router = new VueRouter({
    routes });
    instance = new Vue({
    router, render: (h) => h(App) }).$mount('#app');
  };
  window.__WUJIE_UNMOUNT = () => {
   
    instance.$destroy();
  };
} else {
   
  new Vue({
    router: new VueRouter({
    routes }), render: (h) => h(App) }).$mount('#app');
}
// vue 3

if (window.__POWERED_BY_WUJIE__) {
   
  let instance;
  window.__WUJIE_MOUNT = () => {
   
    const router = createRouter({
    history: createWebHistory(), routes });
    instance = createApp(App);
    instance.use(router);
    instance.mount('#app');
  };
  window.__WUJIE_UNMOUNT = () => {
   
    instance.unmount();
  };
} else {
   
  createApp(App)
    .use(createRouter({
    history: createWebHistory(), routes }))
    .mount('#app');
}
// vite

declare global {
   
  interface Window {
   
    // 是否存在无界
    __POWERED_BY_WUJIE__?: boolean;
    // 子应用mount函数
    __WUJIE_MOUNT: () => void;
    // 子应用unmount函数
    __WUJIE_UNMOUNT: () => void;
    // 子应用无界实例
    __WUJIE: {
    mount: () => void };
  }
}

if (window.__POWERED_BY_WUJIE__) {
   
  let instance: any;
  window.__WUJIE_MOUNT = () => {
   
    const router = createRouter({
    history: createWebHistory(), routes });
    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(createRouter({
    history: createWebHistory(), routes })).mount
### 无界框架中子应用方法调用的实现方式 在微前端架构中,无界框架(Boundary Framework)是一种常见的解决方案,用于管理多个独立开发和部署的子应用。为了实现在父应用中调用子应用的方法,通常需要借助特定的技术手段来完成跨边界通信。 #### 1. **通过全局对象暴露方法** 无界框架允许子应用将自己的功能或方法注册到一个全局对象上,这样主应用可以通过访问该全局对象间接调用子应用中的方法。例如,在子应用初始化时可以执行如下代码: ```javascript window.subAppMethods = { sayHello: function(name) { console.log(`Hello, ${name}!`); } }; ``` 随后,主应用可以直接通过 `window.subAppMethods.sayHello('World');` 调用子应用的功能[^1]。 #### 2. **利用事件总线机制** 另一种常用的方式是基于事件驱动模型构建一个事件总线(Event Bus),使得主应用能够向子应用发送消息并触发相应的处理逻辑。以下是简单的实现示例: ##### 子应用端监听事件: ```javascript document.addEventListener('customEvent', (event) => { const data = event.detail; console.log('Received from parent:', data); }); ``` ##### 主应用端派发事件: ```javascript const customEvent = new CustomEvent('customEvent', { detail: 'Message from Parent' }); document.dispatchEvent(customEvent); ``` 这种方式不仅实现了父子之间的交互,还保持了模块间的松耦合特性[^2]。 #### 3. **采用PostMessage API进行跨域通讯** 如果涉及到不同域名下的子应用,则可运用浏览器原生支持的 PostMessage 技术来进行安全有效的数据交换。下面展示了一个基本的例子: ##### 发送方(通常是主应用卡槽所在位置): ```javascript childWindow.postMessage({ action: 'invokeMethod', methodName: 'sayHello', args: ['User'] }, '*'); ``` ##### 接收方(即目标子应用内部定义好相应处理器): ```javascript window.onmessage = function(event) { if (event.data.action === 'invokeMethod') { this[event.data.methodName](...event.data.args); // 动态调用指定函数名及其参数列表 } } ``` 此方法特别适合于那些无法直接修改源码或者存在严格同源策略限制的情况[^3]。 ### 总结 综上所述,在微前端环境下使用无界框架时,有多种途径可供选择以达成从外部控制内部业务流程的需求。无论是简单粗暴地挂载公开接口至 window 上还是精心设计一套完善的发布订阅模式乃至依赖标准化协议如 postMessage 都各有千秋需视实际场景灵活选用最佳实践方案
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值