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

如何在React中通过Module Federation实现MFE PWA与Shell共享Service Worker?

实现Shell与MFE之间共享Service Worker的方案(基于Module Federation + React)

首先明确核心限制:Service Worker的作用域由其文件位置决定,默认只能控制当前目录及子路径;且Module Federation无法直接导出SW文件本身,只能导出注册逻辑和核心业务模块。以下是具体实现步骤与关键配置:

1. 改造MFE的PWA配置,导出可复用的SW逻辑

假设MFE使用Vite构建(CRA可通过craco适配类似逻辑):

MFE的vite.config.js配置

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { VitePWA } from 'vite-plugin-pwa';
import federation from '@originjs/vite-plugin-federation';

export default defineConfig({
  plugins: [
    react(),
    // 配置Module Federation,导出SW注册函数和核心逻辑
    federation({
      name: 'mfePwa',
      filename: 'remoteEntry.js',
      exposes: {
        './SwRegister': './src/sw-register.js',
        './SwCore': './src/sw-core.js'
      },
      shared: ['react', 'react-dom']
    }),
    // PWA插件配置,生成可跨作用域的SW
    VitePWA({
      srcDir: 'src',
      filename: 'sw.js',
      strategies: 'injectManifest', // 手动控制SW逻辑,而非默认的generateSW
      manifest: false, // 根据需求开启,若Shell有自己的manifest可关闭
      workbox: {
        globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
        scope: '/', // 让SW作用域覆盖根路径,包含Shell应用
        navigateFallbackDenylist: [/^\/shell-specific-path/] // 排除Shell专属路径(可选)
      }
    })
  ]
});

抽离SW核心逻辑(src/sw-core.js)

把缓存策略、事件处理等通用逻辑抽成模块,方便Shell复用或扩展:

export const CACHE_NAME = 'mfe-pwa-shared-cache-v1';
export const PRECACHE_ASSETS = [
  // MFE需要预缓存的静态资源
  '/mfe-app.js',
  '/mfe-styles.css'
];

// 通用fetch拦截逻辑
export const handleFetchEvent = (event) => {
  event.respondWith(
    caches.match(event.request)
      .then(cachedRes => cachedRes || fetch(event.request))
  );
};

SW入口文件(src/sw.js)

导入核心逻辑,实现标准SW生命周期:

import { CACHE_NAME, PRECACHE_ASSETS, handleFetchEvent } from './sw-core.js';

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(PRECACHE_ASSETS))
  );
});

self.addEventListener('fetch', handleFetchEvent);

// 可选:监听来自Shell的消息,动态调整缓存策略
self.addEventListener('message', (event) => {
  if (event.data.type === 'ADD_SHELL_ASSETS') {
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(event.data.assets));
  }
});

SW注册函数(src/sw-register.js)

导出注册SW的异步函数,让Shell直接调用:

export const registerSharedSw = async () => {
  if (!('serviceWorker' in navigator)) return;

  try {
    const registration = await navigator.serviceWorker.register('/sw.js', {
      scope: '/' // 强制作用域覆盖根路径
    });

    // 监听SW更新事件,通知用户刷新
    registration.addEventListener('updatefound', () => {
      const newWorker = registration.installing;
      newWorker.addEventListener('statechange', () => {
        if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
          console.log('新内容已就绪,请刷新页面');
        }
      });
    });
  } catch (err) {
    console.error('Service Worker注册失败:', err);
  }
};

2. Shell应用中导入并使用MFE的SW

Shell的vite.config.js配置

添加MFE的remote地址:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import federation from '@originjs/vite-plugin-federation';

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'shell',
      remotes: {
        mfePwa: 'http://localhost:5001/remoteEntry.js' // MFE的remoteEntry地址
      },
      shared: ['react', 'react-dom']
    })
  ]
});

在Shell入口注册SW

在src/main.jsx中导入并执行注册函数:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { registerSharedSw } from 'mfePwa/SwRegister';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// 注册共享SW
registerSharedSw();

可选:扩展SW功能

如果Shell需要添加自己的静态资源到缓存,可通过SW的消息机制传递:

// Shell的某个组件或入口中
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.ready.then(registration => {
    registration.active.postMessage({
      type: 'ADD_SHELL_ASSETS',
      assets: ['/shell-logo.png', '/shell-common.css']
    });
  });
}

3. 关键注意事项

  • 作用域与跨域配置:
    • 若Shell与MFE部署在同一域名下,确保SW文件放在根路径,且配置scope: '/'。
    • 若为不同域名,需在MFE的服务器上添加响应头:Service-Worker-Allowed: /,同时Shell需部署在HTTPS环境(localhost除外)。
  • 缓存冲突避免:统一缓存命名规则,比如给Shell和MFE的缓存名称加前缀,避免互相覆盖。
  • Module Federation版本兼容:确保Shell与MFE使用的MF插件版本一致,共享依赖(React、ReactDOM)的版本范围兼容。
  • HTTPS要求:生产环境必须使用HTTPS,否则Service Worker无法注册。

4. 排查常见问题

  • 注册失败:检查SW文件路径是否正确,服务器是否返回200,作用域配置是否覆盖Shell路径。
  • 缓存不生效:打开浏览器DevTools → Application → Cache Storage,查看缓存是否正确添加;检查fetch事件逻辑是否有误。
  • MF导入失败:确认remoteEntry地址可访问,Shell与MFE的MF配置中name和exposes名称匹配。

内容的提问来源于stack exchange,提问作者vaisakh raveendran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:36:03