J'Blog
← 返回文章列表

跨应用组件共享:使用模块联邦实现多框架协作

跨应用组件共享:使用模块联邦实现多框架协作

项目背景

在现代前端开发中,我们常常会遇到多个使用不同技术栈构建的前端项目,例如Vue、React等。这些项目之间可能存在共性功能或组件,但传统方式下需要为每个项目单独维护一套代码,导致重复开发和维护成本增加。本文将介绍如何通过模块联邦技术实现跨应用的组件共享,解决这一痛点问题。

实现方案

我们选择使用@originjs/vite-plugin-federation插件来实现这一目标。@originjs/vite-plugin-federation是一个基于Vite的模块联邦(Module Federation)插件,它允许在多个独立的Vite构建项目之间共享代码和依赖,实现微前端架构或跨应用的组件共享。

模块联邦的核心思想是将应用程序拆分为多个独立的构建块,这些构建块可以动态组合成一个完整的应用。每个构建块都可以作为提供者(Provider)或消费者(Consumer),或者同时扮演这两种角色。这种架构模式不仅实现了代码共享,还保持了应用的独立性和可扩展性。

实现步骤

  1. 在React项目中正常开发组件,使用ref抛出回调函数

    首先,我们在React项目中开发需要共享的组件。以Button组件为例,确保组件已经完成开发并通过测试。

  2. 在vite.config文件中配置并导出组件

    // vite.config.js
    import { defineConfig } from "vite";
    import react from "@vitejs/plugin-react";
    import federation from "@originjs/vite-plugin-federation";
    
    export default defineConfig({
      plugins: [
        react(),
        federation({
          name: "react_app", // 应用名称(唯一标识,用于远程引用)
          filename: "remoteEntry.js", // 远程入口文件名
          exposes: {
            // 导出的组件,键为远程引用路径,值为本地文件路径
            "./ReactButton": "./src/components/Button.jsx",
          },
          shared: ["react", "react-dom"], // 共享依赖,避免重复打包
        }),
      ],
      build: {
        target: "esnext", // 需要支持动态 import
      },
    });

    在配置中,我们通过exposes选项指定要共享的组件,通过shared选项指定需要共享的依赖项,这样可以避免重复打包,减小最终包体积。

  3. 在Vue项目中配置远程组件引用

    // vite.config.js
    import { defineConfig } from "vite";
    import vue from "@vitejs/plugin-vue";
    import federation from "@originjs/vite-plugin-federation";
    
    export default defineConfig({
      plugins: [
        vue(),
        federation({
          name: "vue_app",
          remotes: {
            // 引用远程 React 项目
            // �名为本地引用名称,值为远程入口地址
            react_app: "http://localhost:5001/assets/remoteEntry.js",
          },
          shared: ["vue"], // 共享依赖
        }),
      ],
      build: {
        target: "esnext",
      },
    });

    在Vue项目的配置中,我们通过remotes选项指定要引用的远程应用及其入口地址。这里我们引用了之前配置的React应用。

  4. 在Vue组件中动态加载并使用React组件

    <template>
      <div>
        <h1>Vue App</h1>
        <Suspense>
          <template #default>
            <ReactButton />
          </template>
          <template #fallback>
            Loading React Button...
          </template>
        </Suspense>
      </div>
    </template>
    
    <script>
    import { defineAsyncComponent } from "vue";
    
    export default {
      components: {
        // 动态加载远程 React 组件
        ReactButton: defineAsyncComponent(() =>
          import("react_app/ReactButton").then((mod) => mod.default)
        ),
      },
    };
    </script>

    在Vue组件中,我们使用Vue 3的defineAsyncComponent方法动态加载远程的React组件。通过Suspense组件处理加载状态,提供更好的用户体验。

    注意:远程组件的引用路径格式为应用名/导出的组件路径,与我们在React项目的vite.config.js中通过exposes定义的路径保持一致。

注意事项

  • 确保远程应用的入口地址可访问,在生产环境中需要使用正确的URL
  • 合理配置共享依赖,避免重复打包或依赖冲突
  • 处理组件加载状态,提供良好的用户体验
  • 注意跨框架组件的样式隔离问题
  • 考虑组件版本兼容性,特别是共享依赖的版本

总结

通过模块联邦技术,我们成功实现了不同框架(Vue、React)之间的组件共享,有效提高了代码复用率并降低了维护成本。这种架构模式特别适合大型企业级应用或需要渐进式迁移的场景,为微前端架构的实现提供了强有力的技术支持。