简介
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/Button
import 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/Button
import 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: [path.resolve(__dirname, 'children-app')],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 accessor
const v3reactAccessor = createReactBridge(React, ReactDOM)// create vue2 accessor
const v2reactAccessor = createReactBridge(React, ReactDOM)//bridge react app to vue3
const V3APP = v3reactBridge(h)(App)//bridge react app to vue2
const V2APP = v2reactBridge()(App)
sfc file
<template><V2APP />
</template><template><V3APP />
</template>
在线演示
点我
仓库地址
hanyaxxx/micro-frontend-bridge