VITE + 邦联模块(module federation)实现

好了,来填坑了,在基于VITE手动搭建Single-spa框架一文中,曾说过,确认前后端均采用微服务+单点登录方案后,就去筛选前端微服务方案了么。那么,第二个前端微服务方案,如期而至了。

前端微服务方案,当时用的比较多的,主要是有以下几个方案:

  1. google 旗下的 single-spa.
  2. 阿里旗下,基于 single-spa 的 Qiankun.
  3. 京东基于 webComponent 原生组件的 Micro-app.
  4. module federation, webpack5 原生支持的技术方案.
  5. 字节跳动推出的 garfish.

当然,也还有其他前端微服务框架和方案,如:Luigi, open components, piral 等等,不一而足。只是前述列表,才是我做了预研和 demo 的方案,本想一个一个讲一讲各个方案的优缺点,但我仅仅前浅显的做了demo,没有深入研究,就请参考除了 Qiankun, 这些微前端框架或许更适合你「建议收藏」这篇文章吧。调研时,还没用过 vite,所以直接使用的 webpack5,现在 vite 性能上已经超出了 webpack,所以,就使用 vite 来完成这个 demo 吧。

基座(base)

使用 手动搭建VITE + REACT 一文中搭建的 React 项目作为基础项目,作为 base 项目。项目结构如下图:

关键配置如下:

typescript 复制代码
....原有配置
+ import federation from '@originjs/vite-plugin-federation'
export default defineConfig({
    plugins:[
        ... 原有配置
        federation({
            name:'host',
            remotes:{
                // 远程模块引入 引入格式 name:入口地址,远程组件需要打包部署后,运行在一个实体服务器内,或者使用开发服务器
                'remote':'localhost:30001/remote.js'
            },
            shared:['react','react-dom'] // 共享依赖
        })
    ]
    ... 原有配置
})

子项目(remote, 向 base 提供组件)

同上,项目同样为 react 项目,项目结构相同,只是新增了 components 目录,其中存放了需要向外暴露的公共组件,关键配置如下:

typescript 复制代码
....原有配置
+ import federation from '@originjs/vite-plugin-federation'
export default defineConfig({
    plugins:[
        ... 原有配置
        federation({
            name:'remote', // 名称,唯一标识
            filename:'remote.js', // 入口文件名称,可以不填,不填则是默认的 remoteEntry.js
            exposs:{
                // 暴露的模块路径及访问别名 访问别名:模块路径
                './Button': './src/components/button/index.tsx'
            },
            shared:['react','react-dom'] // 共享依赖
        })
    ],
    build:{
        ... 原有配置
        target:'esnext' // 必须使用 ES 模块
    },
    server:{
        ... 原有配置
        headers: {'Access-Control-Allow-Origin':'*' // 允许跨域访问
    }
    ... 原有配置
})

在base项目中引用远程组件

typescript 复制代码
import React, { Suspense, lazy } from 'react'

const RemoteButton = lazy(() => import('remote/Button')) // 引入远程组件,remote 是在 vite.config.ts 中配置的name
const App: React.FC = () => {
  console.log('App')
  return (
    <div>
      <Suspense fallback={<div>loading</div>}>
        <RemoteButton />
      </Suspense>
    </div>
  )
}

export default App

注意事项

如果使用ts,eslint会报类型错误,需要去定义类型。

typescript 复制代码
// global.d.ts,可以放在项目根目录下
declare module 'remote-app/Button' {
  const component: any
  export default component
}

可使用场景

  1. 调研时,使用的是webpack5,原生支持 federation。
  2. 使用 vite 时,需要使用 vite-plugin-federation 插件来实现。
  3. 使用时,需要注意版本,各版本不兼容的情况下,功能会缺失。
  4. 跨框架使用,要注意各框架的的区别,各模块的依赖,需要在 shared 中配置,否则依赖框架的功能会失效。
  5. 各远程项目独立运行时,建议打包后,放在web容器中部署运行,使用 vite 的 server 模块时,会碰到无法加载到入口 (remoteEntry.js) 找不到的尴尬情况。(目前我还没解决,主要是不打包的情况下,remoteEntry.js这个文件不会生成)。
  6. 该方案比较适合的场景,是独立的纯逻辑组件|纯UI组件复用,且颗粒度较小。有副作用(例如影响提供远程组件的项目里的数据,对提供远程组件的项目的业务逻辑有影响)的话,需要谨慎使用,除非各个项目组协调一致。

结语

由于当时公司各个项目的后台管理端采用的框架 (vue2,react,angular,backbone) 各不相同,且版本也五花八门没有统一,使用邦联模块的改造难度和工作量远超预期,所以当时我们并未选用该方案。好了,下期,我们讲讲阿里的Qiankun,以及为啥我们也没选它。

相关推荐
TechStack 创行者3 小时前
Docker+Flask 实战:打造高并发微服务架构
运维·docker·微服务·容器·架构
一朵好运莲4 小时前
Next+React项目启动慢刷新慢的解决方法
前端·react.js·前端框架
Aska_Lv4 小时前
mybatis+springboot+MySQL批量插入 1w 条数据——探讨
后端·架构
桂月二二5 小时前
云原生Serverless平台:无服务器计算的架构革命
云原生·架构·serverless
Wgllss5 小时前
金三银四,分享N年前准备的面试真经,可能适用绝大部分人
android·架构·android jetpack
易元6 小时前
设计模式-组合模式
后端·架构
王嘉俊9256 小时前
OpenHarmony体系架构深度解析
架构·arkts·鸿蒙·鸿蒙系统·openharmony
绿算技术7 小时前
DPU的架构:模块化与可扩展性
科技·算法·缓存·架构
桂月二二8 小时前
云原生容器编排:Kubernetes的架构演进与实践
云原生·架构·kubernetes