You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Native Expo中通过Module Federation使用Web Component微前端?

在React Native Expo中通过Module Federation集成Web Component微前端

首先明确核心前提:React Native Expo本身不支持直接渲染Web Component(因为RN是原生渲染引擎,Web Component是浏览器标准),所以必须通过WebView承载Web Component,同时借助Module Federation实现微前端的动态加载。以下是可落地的实现步骤:

一、微前端侧配置(Web Component + Module Federation)

每个微前端需要打包成可通过Module Federation暴露的Web Component,这里以Webpack为例:

  1. 配置Module Federation暴露Web Component
// 微前端项目的webpack.config.js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'MicroFrontend1', // 微前端唯一标识
      filename: 'remoteEntry.js', // 远程入口文件
      exposes: {
        './MyWebComponent': './src/components/MyWebComponent', // 暴露Web Component模块
      },
      shared: { react: { singleton: true }, 'react-dom': { singleton: true } }, // 共享React类依赖(如果用React封装Web Component)
    }),
  ],
};
  1. 编写支持参数接收的Web Component
    如果你的Web Component需要接收外部参数,通过属性监听机制实现:
// src/components/MyWebComponent.js
class MyWebComponent extends HTMLElement {
  // 声明需要监听的属性列表
  static get observedAttributes() {
    return ['user-id', 'auth-token'];
  }

  // 属性值变化时触发业务逻辑
  attributeChangedCallback(name, oldVal, newVal) {
    if (name === 'user-id') {
      this.fetchUserData(newVal);
    } else if (name === 'auth-token') {
      this.setAuthToken(newVal);
    }
  }

  async fetchUserData(userId) {
    // 带参数请求接口的逻辑
    const res = await fetch(`https://api.example.com/users/${userId}`, {
      headers: { 'Authorization': this.getAttribute('auth-token') }
    });
    const data = await res.json();
    // 更新组件内容
    this.innerHTML = `<div>当前用户:${data.name}</div>`;
  }

  setAuthToken(token) {
    // 存储鉴权token的逻辑
  }
}

// 注册自定义元素
customElements.define('my-web-component', MyWebComponent);
export default MyWebComponent;

二、Expo项目侧集成WebView加载微前端

使用expo-webview来承载微前端的Web环境,实现动态加载和参数传递:

  1. 安装依赖
npx expo install expo-webview
  1. 封装微前端加载组件
// components/MicroFrontendLoader.jsx
import React from 'react';
import { WebView } from 'expo-webview';

const MicroFrontendLoader = ({ remoteUrl, params = {} }) => {
  // 注入到WebView的加载脚本:加载remoteEntry并渲染Web Component,同时传递参数
  const loadScript = `
    // 初始化参数
    window.mfParams = ${JSON.stringify(params)};
    
    // 动态加载微前端
    (async function() {
      try {
        // 加载远程入口文件
        const remoteContainer = await import('${remoteUrl}/remoteEntry.js');
        // 获取暴露的Web Component模块
        const MyWebComponent = await remoteContainer.get('./MyWebComponent');
        
        // 创建组件实例并设置参数(驼峰转短横线适配HTML属性命名)
        const element = document.createElement('my-web-component');
        Object.entries(window.mfParams).forEach(([key, value]) => {
          const attrKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
          element.setAttribute(attrKey, value);
        });
        
        // 将组件挂载到页面
        document.body.appendChild(element);
      } catch (err) {
        console.error('微前端加载失败:', err);
      }
    })();
  `;

  return (
    <WebView
      source={{ uri: 'https://your-static-host.com/blank.html' }} // 空白页面作为载体,也可直接用微前端的宿主页
      injectedJavaScriptBeforeContentLoaded={loadScript}
      style={{ flex: 1, marginVertical: 10 }}
      allowUniversalAccessFromFileURLs={true}
    />
  );
};

export default MicroFrontendLoader;
  1. 在主App中使用组件
    区分需要传参和无需传参的微前端:
// App.jsx
import React from 'react';
import { View, StyleSheet } from 'react-native';
import MicroFrontendLoader from './components/MicroFrontendLoader';

export default function App() {
  return (
    <View style={styles.container}>
      {/* 无需传参的微前端 */}
      <MicroFrontendLoader remoteUrl="https://mf-static-1.example.com" />
      <MicroFrontendLoader remoteUrl="https://mf-static-2.example.com" />
      
      {/* 需要传参的微前端 */}
      <MicroFrontendLoader 
        remoteUrl="https://mf-static-3.example.com" 
        params={{ userId: 'user_12345', authToken: 'Bearer_abcxyz' }} 
      />
      <MicroFrontendLoader 
        remoteUrl="https://mf-static-4.example.com" 
        params={{ productId: 'prod_67890' }} 
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 16,
  },
});

三、解决Re.Pack适配问题

你之前尝试Re.Pack失败是因为Re.Pack的Module Federation是针对React Native组件的模块共享方案,并不适用于Web Component。Web Component必须运行在浏览器环境中,所以必须通过WebView隔离环境,不能直接在RN的JS引擎中加载。

四、常见问题排查

  • 跨域错误:确保微前端服务器配置CORS,允许Expo项目的域名(开发环境可临时设为*)访问remoteEntry.js
  • 参数不生效:检查参数名是否转为HTML短横线格式,Web Component的observedAttributes是否正确声明
  • 加载失败:确认remoteUrl正确、remoteEntry.js可访问,WebView的JS注入逻辑无语法错误

内容的提问来源于stack exchange,提问作者Ram Vishwakarma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:37:35