微前端

109 阅读5分钟

微前端

一、简介

        微前端的概念是由ThoughtWorks在2016年提出的,它借鉴了微服务的架构理念,核心在于将一个庞大的前端应用拆分成多个独立灵活的小型应用,同时可以解决一些iframe的潜在问题,通俗来说,就是在一个web应用中可以独立的运行另一个web应用。

微前端解决方案也给我们提供如下特性:

  • 单个前端部分可独立开发、测试和部署;

  • 无需重新构建即可添加、移除或替换单个前端部分;

  • 不同的前端部分可使用不同的技术构建;

  • 解决iframe硬隔离的一些问题

二、微前端实现

这里采用wujie,wujie是一个基于 Web Component 容器 + iframe 沙箱的微前端方案。能够完善的解决适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等问题。

三、应用

1. 安装wujie

主应用不限技术栈,只需引入 wujie、配置子应用路由并启动 wujie 即可。

wujie 针对 React 和 Vue 框架分别提供了 wujie-react wujie-vue2 wujie-vue3 依赖。

yarn add wujie-vue3

pnpm add wujie-vue3

npm i wujie-vue3

2. 在main.ts中挂载

import { createApp } from 'vue';
import WujieVue from 'wujie-vue3';
import App from './App.vue';
 
const app = createApp(App);
app.use(WujieVue).mount('#app');

3. 在apps文件夹下创建子应用

image

4. 在页面中应用

创建子应用

<template>
    <WujieVue 
      width="100%"
      height="100%" 
      name="sub-app" 
      :url="url" 
   
      :props="propsData" 
    />
</template>
<script setup>
  import { ref, reactive } from 'vue';

  const url = ref('http://192.168.201.0:7300/'); // 子应用的url

  const propsData = reactive({ // 传递参数
    name: '章三',
    age: '18',
  });
    // sync 路由同步
</script>

生命周期

name 为子应用唯一标识符,url 为子应用的路径地址,alive 设为 true 则是保活模式,after-mount 为子应用渲染后的生命周期钩子,无界的主要生命周期可以分为:

  • beforeLoad:子应用开始加载静态资源前触发

  • beforeMount:子应用渲染(调用window.__WUJIE_MOUNT)前触发

  • afterMount:子应用渲染(调用window.__WUJIE_MOUNT)后触发

  • beforeUnmount:子应用卸载(调用window.__WUJIE_UNMOUNT)前触发

  • afterUnmount: 子应用卸载(调用window.__WUJIE_UNMOUNT)后触发

  • activated:子应用保活模式下,进入时触发

  • deactivated:子应用保活模式下,离开时触发

运行模式:

  1. 保活模式:子应用的alive设置为true时进入保活模式,内部的数据和路由的状态不会随着页面切换而丢失。在保活模式下,子应用只会进行一次渲染,页面发生切换时承载子应用dom的webcomponent会保留在内存中,当子应用重新激活时无界会将内存中的webcomponent重新挂载到容器上。保活模式下改变  子应用的路由不会发生变化,需要采用通信的方式对子应用路由进行跳转

  2. 单例模式:子应用的alive为false且进行了生命周期改造时进入单例模式。子应用页面如果切走,会调用window.__WUJIE_UNMOUNT销毁子应用当前实例,子应用页面如果切换回来,会调用window.__WUJIE_MOUNT渲染子应用新的子应用实例,在单例式下,改变 url 子应用的路由会发生跳转到对应路由。如果主应用上有多个菜单栏用到了子应用的不同页面,在每个页面启动该子应用的时候将name设置为同一个,这样可以共享一个wujie实例,承载子应用js的iframe也实现了共享,不同页面子应用的url不同,切换这个子应用的过程相当于:销毁当前应用实例 => 同步新路由 => 创建新应用实例

  3. 重建模式:子应用既没有设置为保活模式,也没有进行生命周期的改造则进入了重建模式,每次页面切换不仅会销毁承载子应用 dom 的 webcomponent,还会销毁承载子应用js的iframe,相应的 wujie 实例和子应用实例都会被销毁。重建模式下改变 url 子应用的路由会跳转对应路由,但是在路由同步场景并且子应用的路由同步参数已经同步到主应用url上时则无法生效,因为改变url后会导致子应用销毁重新渲染,此时如果有同步参数则同步参数的优先级最高

路由同步

路由同步会将子应用路径的path+query+hash通过window.encodeURIComponent编码后挂载在主应用url的查询参数上,其中key值为子应用的 name

开启路由同步后,刷新浏览器或者将url分享出去子应用的路由状态都不会丢失,当一个页面存在多个子应用时无界支持所有子应用路由同步,浏览器刷新、前进、后退子应用路由状态也都不会丢失

开启参数 sync

父子应用通信

  • props 通信

主应用可以通过props注入数据和方法:

<WujieVue name="xxx" url="xxx" :props="{ data: xxx, methods: xxx }"></WujieVue>

子应用可以通过$wujie来获取:

const props = window.$wujie?.props; // {data: xxx, methods: xxx}
  • window 通信

主应用调用子应用的全局数据

window.document.querySelector("iframe[name=子应用id]").contentWindow.xxx;

子应用调用主应用的全局数据

window.parent.xxx;
  • eventBus 通信

无界提供一套去中心化的通信方案,主应用和子应用、子应用和子应用都可以通过这种方式方便的进行通信,

主应用使用方式:

// 如果使用wujie-vue
import WujieVue from "wujie-vue3";
const { bus } = WujieVue;


// 主应用监听事件
bus.$on("事件名字", function (arg1, arg2, ...) {});
// 主应用发送事件
bus.$emit("事件名字", arg1, arg2, ...);
// 主应用取消事件监听
bus.$off("事件名字", function (arg1, arg2, ...) {});

子应用使用方式:

// 子应用监听事件
window.$wujie?.bus.$on("事件名字", function (arg1, arg2, ...) {});
// 子应用发送事件
window.$wujie?.bus.$emit("事件名字", arg1, arg2, ...);
// 子应用取消事件监听
window.$wujie?.bus.$off("事件名字", function (arg1, arg2, ...) {});

四、总结

总的来说无界的优点还是很明显:

  • 使用iframe作为天然的 js 沙箱,不会污染主应用环境

  • 使用 Web Components 来隔离html、css,这是一个浏览器原生支持的组件封装技术,可以有效隔离元素之间的样式

  • 提供了事件总线和props传参,弥补了iframe通信困难的缺点

  • 子应用无需做任何改造,接入更简单

  • 实现了多应用激活、应用保活功能

  • 提供了vue和react组件的封装,开箱即用