微前端架构实战:qiankun与Module Federation方案对比与选型

微前端架构解决什么问题

微前端将大型单体前端应用拆分为多个独立开发、独立部署的子应用,每个子应用可以使用不同的框架和技术栈。这种架构解决的核心问题是大型团队协作中的代码冲突、构建缓慢和部署耦合。当前端代码量达到百万行级别时,单仓库的构建时间可能超过30分钟,任何子功能的修改都需要全量构建部署,微前端将构建和部署拆解为独立单元。

微前端方案主要分为两类:基于运行时隔离的qiankun和基于构建时集成的Module Federation。两者的设计理念不同,适用场景也有差异。

qiankun运行时隔离方案

qiankun基于single-spa封装,通过HTML Entry方式加载子应用。主应用通过fetch获取子应用的HTML文件,解析出JS和CSS资源,在沙箱环境中执行子应用代码。

// 主应用 - 注册子应用
import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'user-app',
    entry: '//localhost:8081',
    container: '#subapp-container',
    activeRule: '/user',
  },
  {
    name: 'order-app',
    entry: '//localhost:8082',
    container: '#subapp-container',
    activeRule: '/order',
  },
]);

start({
  prefetch: true,           // 预加载子应用
  sandbox: {
    strictStyleIsolation: true,  // Shadow DOM样式隔离
    experimentalStyleIsolation: true,
  },
});

// 子应用 - 导出生命周期函数
export async function mount(props) {
  ReactDOM.render(
    ,
    props.container
      ? props.container.querySelector('#root')
      : document.getElementById('root')
  );
}

export async function unmount(props) {
  ReactDOM.unmountComponentAtNode(
    props.container
      ? props.container.querySelector('#root')
      : document.getElementById('root')
  );
}

qiankun的JS沙箱通过Proxy代理window对象实现隔离,子应用对window的修改不会影响主应用和其他子应用。strictStyleIsolation使用Shadow DOM隔离样式,experimentalStyleIsolation通过CSS Scope规则给子应用样式添加前缀。两者各有取舍:Shadow DOM隔离更彻底但可能导致弹窗组件样式失效,Scope方式兼容性更好但隔离不完整。

Module Federation构建时集成方案

Module Federation是Webpack 5原生支持的模块联邦功能,允许不同构建产物之间在运行时共享模块。与qiankun不同,Module Federation不依赖HTML Entry,而是直接共享JS模块。

// 子应用 webpack.config.js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'userApp',
      filename: 'remoteEntry.js',
      exposes: {
        './UserModule': './src/components/UserModule',
        './UserService': './src/services/UserService',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true },
        'react-router-dom': { singleton: true },
      },
    }),
  ],
};

// 主应用 webpack.config.js
new ModuleFederationPlugin({
  name: 'shell',
  remotes: {
    userApp: 'userApp@//localhost:8081/remoteEntry.js',
    orderApp: 'orderApp@//localhost:8082/remoteEntry.js',
  },
  shared: {
    react: { singleton: true, requiredVersion: '^18.0.0' },
    'react-dom': { singleton: true },
  },
})

// 主应用 - 动态加载子应用模块
const UserModule = React.lazy(() => 
  import('userApp/UserModule')
);
const OrderModule = React.lazy(() => 
  import('orderApp/OrderModule')
);

function App() {
  return (
    }>
      
        
          } />
          } />
        
      
    
  );
}

shared配置中的singleton: true确保React、ReactDOM等公共依赖只加载一次,避免多个子应用各自加载一份导致内存浪费和Hook失效问题。requiredVersion指定版本要求,当子应用的依赖版本不满足时Webpack会发出警告。

两种方案的对比与选型

qiankun和Module Federation在架构层面有本质区别:

| 维度         | qiankun                  | Module Federation       |
|-------------|--------------------------|------------------------|
| 隔离机制     | JS沙箱+Shadow DOM        | 共享模块+单例依赖       |
| 加载方式     | HTML Entry fetch         | JS模块动态import        |
| 框架兼容     | 支持不同框架混用          | 需要Webpack 5+          |
| 样式隔离     | Shadow DOM/Scope         | 需要CSS Modules手动处理  |
| 通信方式     | props传递/全局状态       | 直接import共享模块       |
| 公共依赖     | 各自加载                 | shared配置共享单例       |
| 改造成本     | 子应用需导出生命周期     | 需升级Webpack 5并配置   |
| 适用场景     | 跨技术栈/遗留系统集成     | 同技术栈/新项目微前端   |

实际选型需要考虑团队现状。如果团队中存在Vue、React甚至Angular混用的场景,qiankun的框架无关性是决定性优势。如果所有子应用统一使用React+Webpack技术栈,Module Federation的模块级共享更加高效,公共依赖只加载一份,页面体积更小。

微前端通信机制设计

微前端架构中子应用之间的通信是核心难点。常见的方案包括:

// 方案1:基于CustomEvent的发布订阅
// 主应用
window.dispatchEvent(new CustomEvent('user-updated', {
  detail: { userId: 123, name: '张三' }
}));

// 子应用
window.addEventListener('user-updated', (e) => {
  console.log('收到用户更新:', e.detail);
});

// 方案2:基于全局状态管理(qiankun props传递)
// 主应用
registerMicroApps([{
  name: 'user-app',
  entry: '//localhost:8081',
  container: '#subapp-container',
  activeRule: '/user',
  props: {
    getToken: () => localStorage.getItem('token'),
    onUserChange: (user) => sharedStore.setUser(user),
  },
}]);

// 方案3:Module Federation共享Service
// shared/service/store.ts(共享模块)
import { createStore } from 'zustand';
export const useSharedStore = createStore((set) => ({
  user: null,
  setUser: (user) => set({ user }),
  cart: [],
  addToCart: (item) => set((s) => ({ cart: [...s.cart, item] })),
}));

// 各子应用直接import使用
import { useSharedStore } from 'shell/sharedStore';
const user = useSharedStore((s) => s.user);

CustomEvent方案最简单但缺乏类型安全。props传递方案在qiankun中官方支持但通信能力有限。Module Federation的共享模块方案类型安全且最灵活,但要求所有子应用使用相同的状态管理库。

部署策略与路由管理

微前端的部署需要处理路由分发和资源加载。Nginx配置根据路径将请求代理到不同的子应用服务器:

server {
    listen 80;
    server_name app.example.com;
    
    # 主应用
    location / {
        proxy_pass http://127.0.0.1:8000;
    }
    
    # 子应用静态资源
    location /user/ {
        proxy_pass http://127.0.0.1:8081;
        try_files $uri $uri/ /user/index.html;
    }
    
    location /order/ {
        proxy_pass http://127.0.0.1:8082;
        try_files $uri $uri/ /order/index.html;
    }
    
    # API网关
    location /api/ {
        proxy_pass http://127.0.0.1:3000;
    }
}

路由管理需要处理子应用切换时的状态保持和页面刷新。qiankun通过activeRule匹配URL前缀激活对应子应用,Module Federation通过React Router的嵌套路由实现。页面刷新时确保子应用资源能正确加载,Nginx的try_files配置将未匹配的路径回退到子应用的index.html。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/wei-qian-duan-jia-gou-shi-zhan-qiankun-yu-modulefederation/

(0)
小编小编
上一篇 9小时前
下一篇 9小时前

相关推荐