kJ2WxJId 发表于 2025-2-19 15:55:50

微前端之桥接方案, 打破技术栈次元壁-实现无缝对接

简介

1. 微前端桥接方案是什么?

是一种新的微前端解决方案,使用了一种巧妙的方法去实现了微前端架构, 只需通过调用高阶函数即可实现不同技术栈之间的互通
2.何谓无缝?

微应用接入与原生技术栈应用毫无差异,不需要任何额外的信息
3. 为什么需要,是否重复造轮子?

在项目实践落地过程中,调研过和尝过不同的落地方案要么是兼容性问题,要么就是项目改造有点重, css 样式隔离也是一个头疼的问题. 于是 bridge 方案就此诞生了.
现在有很多微前端方案, 为什么要用bridge方案? 先来总结和梳理一下目前主流的几种方法:
1. 基于 Webpack 5 的 Module Federation

[*]优点:可实现第三方依赖共享,减少不必要的代码引入;微应用可动态更新,无需重新打包发布整合应用;去中心化,每个微应用间可直接通信。
[*]缺点:对 webpack5 的依赖度较高,项目若不使用 webpack5 则难以接入。
2. 基于 iframe

[*]优点:实现简单,无需对现有应用进行大量改造;能提供浏览器原生的硬隔离,JS、CSS、DOM 都完全隔离开,互不影响;可通过 postMessage API 进行消息传递。
[*]缺点:无法保持路由状态,刷新后路由丢失,浏览器前进后退功能受限;应用间上下文难以共享,交互困难;弹窗只能在 iframe 内部展示;全量资源加载,性能较差;不利于 SEO。
3. 基于 Web Components + 沙箱

[*]优点:CSS 和 JavaScript 天然隔离,避免样式冲突和脚本污染;原生浏览器支持,不依赖特定框架或库;多个子应用可并存,支持并行开发和独立部署。
[*]缺点:浏览器兼容性存在问题,部分浏览器不完全支持;开发成本较高,可能需要重写现有应用;组件间通信需要额外设计。
4. sigle-spa + 沙箱

[*]优点:技术栈无关,任意技术栈的应用均可接入;采用 HTML entry 接入方式,接入成本低;提供了样式隔离、JS 沙箱、资源预加载等功能。
[*]缺点:样式隔离问题不完善,打包工具有一定限制等,组件通信问题等...
基本上不是样式隔离出了问题,就是兼容性出了问题....
bridge方案和其他微前端方案的区别是什么?


[*]1.使用更简单,使用更自然,无额外知识,通过高阶函数创建桥接组件并直接使用
[*]2.无 iframe 和 shadow dom 的依赖, 兼容性更好
[*]3.组件通信更自然(通过原生 props 属性可进行父子组件通信)
[*]4.可组件化导入子应用/子组件
[*]5.样式隔离问题处理更优(采用css-module 或者 scoped 隔离方案取决于项目自身打包工具的配置)
那如何证明上述结论呢?废话不多说直接上代码.
代码演示

以react 18 为主应用作为举例, 如果要接入vue2

1. 第一步创建桥接应用
//假设子应用路径为 .children-app/accesstor/Buttonimport vue from 'vue'import { createVueBridge } from 'micro-frontend-bridge/for-react'import Button from './Button.vue'//假设子应用是一个vue2的项目//为vue2创建一个桥接访问器const accesstor = createVueBridge(vue)//访问器是一个高阶函数,用来链接vue button按钮export default accesstor(Button)第二步输出桥接组件

通过打包工具将button打包成 lib 输入到主应用里

第三步主应用使用桥接组件
//假设主应用有一个main.jsx文件和bridge文件夹存在桥接组件//主应用是一个React 18 项目import React from 'react'import Button from 'bridge/Button'//在react18中使用vue2的按钮 推荐使用大写组件名称区别桥接组件const BUTTON = Button(React)const App = () => {return (    <div>      <BUTTON color="grey" />    </div>)}没错这个时候react 18和 vue2 已经无缝连接了, 那么如何进行组件通信呢?
组件通信也是非常自然的, 直接基于props传递属性即可, 代码中的color属性会传递给vue2的button, 通过回调函数也可以进行父子组件通信与原生通信模式无差异. (末尾有在线地址可以直接实践).
总结一下就是 :

[*]创建桥接组件
[*]输出组件
[*]使用桥接组件
在这里其实第二步打包组件输出lib的过程根据项目架构的特点是可以省去的, 可以把桥接组件放在主应用内,对主应用添加子应用的打包支持,如果你的主应用用的是webpack,那么对子应用添加vue打包支持即可,就可以省略配置打包lib这一步了
示范如下,调整桥接组件目录到主应用
//假设桥接组件应用路径为 bridge/Buttonimport vue from './children-app/node_modules/vue'import { createVueBridge } from 'micro-frontend-bridge/for-react'//这里路径引入做了调整import Button from '../children-app/Button.vue'//假设子应用是一个vue2的项目//为vue2创建一个桥接访问器const accesstor = createVueBridge(vue)//访问器是一个高阶函数,用来链接vue button按钮export default accesstor(Button)调整webpack打包支持
{          test: /\.vue$/,          include: ,          use: {            loader: './children-app/node_modules/vue-loader/lib',            options: {            compiler: Vue2TemplateCompiler            }          }      },使用组件
//假设主应用有一个main.jsx文件和bridge文件夹存在桥接组件//主应用是一个React 18 项目import React from 'react'import Button from 'bridge/Button'//在react18中使用vue2的按钮 推荐使用大写组件名称区别桥接组件const BUTTON = Button(React)const App = () => {return (    <div>      <BUTTON color="grey" />    </div>)}(具体的演示看末尾线连接)
如何优化这个微前端应用?


一般来说微前端接入项目由于不同技术栈的存在, 可能会导致包体积过大的问题, 由于本身bridge方案本身是基于高阶函数实现的,使用动态import和suspense就可以实现按需加载达到优化的目的了.
最后以vue2和vue3做为主应用作为举例子,如果接入react组件

import React from 'react'import ReactDOM from 'react-dom'import { h } from 'vue'import { createReactBridge } from '@micro-frontend-bridge/for-vue'import { App } from './reactApp.tsx'// create vue3 accessorconst v3reactAccessor = createReactBridge(React, ReactDOM)// create vue2 accessorconst v2reactAccessor = createReactBridge(React, ReactDOM)//bridge react app to vue3const V3APP = v3reactBridge(h)(App)//bridge react app to vue2const V2APP = v2reactBridge()(App)sfc file
<template>   <V2APP /> </template><template>   <V3APP /> </template>在线演示

点我
仓库地址

hanyaxxx/micro-frontend-bridge
页: [1]
查看完整版本: 微前端之桥接方案, 打破技术栈次元壁-实现无缝对接