您现在的位置是:网站首页 > 微前端架构中的设计模式应用文章详情

微前端架构中的设计模式应用

微前端架构通过将大型前端应用拆分为多个独立、松耦合的子应用,解决了单体架构的扩展性和维护性问题。设计模式在这一架构中扮演着关键角色,帮助开发者处理模块通信、状态管理和依赖隔离等复杂场景。

组合模式与微应用集成

组合模式在微前端中常用于构建层次化的应用结构。主应用作为容器,通过统一接口管理子应用的挂载与卸载。以下是一个典型的组合模式实现:

class MicroFrontend {
  constructor(name) {
    this.name = name;
    this.children = [];
  }

  add(child) {
    this.children.push(child);
  }

  mount(container) {
    console.log(`Mounting ${this.name}`);
    this.children.forEach(child => {
      child.mount(container);
    });
  }
}

// 子应用实现
class ProductApp extends MicroFrontend {
  mount(container) {
    super.mount(container);
    container.innerHTML += `<div>Product Module Content</div>`;
  }
}

// 主应用组合子应用
const mainApp = new MicroFrontend('Main Container');
mainApp.add(new ProductApp('Product'));
mainApp.mount(document.getElementById('root'));

这种模式允许主应用无需了解子应用内部实现,只需调用统一接口即可完成集成。实际项目中,Web Components 常被用作组合模式的物理载体。

观察者模式实现跨应用通信

微前端中常见的通信需求可以通过观察者模式解决。以下是基于 CustomEvent 的跨应用事件总线实现:

// 事件中心
class EventBus {
  constructor() {
    this.listeners = {};
  }

  on(event, callback) {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event].push(callback);
  }

  emit(event, data) {
    const eventListeners = this.listeners[event];
    if (eventListeners) {
      eventListeners.forEach(callback => callback(data));
    }
  }
}

// 主应用初始化总线
window.globalEventBus = new EventBus();

// 子应用A发布事件
window.globalEventBus.emit('cart-updated', { items: 5 });

// 子应用B订阅事件
window.globalEventBus.on('cart-updated', data => {
  console.log('Cart items:', data.items);
});

更复杂的场景可以使用 Redux 或 Zustand 等状态管理库,其本质上也是观察者模式的变体。

适配器模式处理环境差异

不同子应用可能需要适配不同的运行环境。适配器模式在此场景中非常有用:

// 不同框架的生命周期适配
class ReactAdapter {
  constructor(reactApp) {
    this.app = reactApp;
  }

  mount(container) {
    ReactDOM.render(this.app, container);
  }

  unmount(container) {
    ReactDOM.unmountComponentAtNode(container);
  }
}

class VueAdapter {
  constructor(vueApp) {
    this.app = vueApp;
  }

  mount(container) {
    this.app.$mount(container);
  }

  unmount() {
    this.app.$destroy();
  }
}

// 统一接口调用
function mountApp(app, container) {
  if (app instanceof ReactAdapter || app instanceof VueAdapter) {
    app.mount(container);
  } else {
    throw new Error('Unsupported app type');
  }
}

代理模式实现沙箱隔离

微前端需要确保子应用间的样式和全局变量隔离。代理模式可以创建安全的执行环境:

class SandboxProxy {
  constructor(app, context) {
    this.app = app;
    this.context = context;
    this.originalWindow = {...window};
  }

  execute() {
    // 创建代理窗口
    const fakeWindow = new Proxy(window, {
      get(target, prop) {
        return prop in this.context ? 
          this.context[prop] : target[prop];
      },
      set(target, prop, value) {
        this.context[prop] = value;
        return true;
      }
    });

    // 在沙箱中执行
    with (fakeWindow) {
      this.app.init();
    }
  }

  cleanup() {
    // 还原原始环境
    Object.keys(this.context).forEach(key => {
      delete window[key];
    });
    Object.assign(window, this.originalWindow);
  }
}

// 使用示例
const subApp = {
  init() {
    window.customVar = 'isolated'; // 不会污染全局
  }
};

const proxy = new SandboxProxy(subApp, {});
proxy.execute();

策略模式实现动态加载

不同环境下可能需要不同的子应用加载策略:

const loadStrategies = {
  local: (appName) => {
    console.log(`Loading ${appName} from local`);
    return import(`/apps/${appName}/index.js`);
  },

  cdn: (appName) => {
    console.log(`Loading ${appName} from CDN`);
    return new Promise((resolve) => {
      const script = document.createElement('script');
      script.src = `https://cdn.example.com/${appName}.js`;
      script.onload = resolve;
      document.head.appendChild(script);
    });
  }
};

class MicroAppLoader {
  constructor(strategy = 'local') {
    this.strategy = loadStrategies[strategy];
  }

  loadApp(appName) {
    return this.strategy(appName);
  }
}

// 根据环境切换策略
const loader = new MicroAppLoader(process.env.NODE_ENV === 'production' ? 'cdn' : 'local');
loader.loadApp('product');

装饰器模式增强子应用功能

在不修改子应用源码的情况下扩展功能:

function withAnalytics(app) {
  return {
    ...app,
    mount(container) {
      console.time('mount-' + app.name);
      app.mount(container);
      console.timeEnd('mount-' + app.name);
      trackEvent('APP_MOUNTED', { name: app.name });
    }
  };
}

// 原始应用
const baseApp = {
  name: 'checkout',
  mount(container) {
    container.innerHTML = '<div>Checkout App</div>';
  }
};

// 增强后的应用
const enhancedApp = withAnalytics(baseApp);
enhancedApp.mount(document.getElementById('app'));

单例模式管理共享依赖

确保公共库在微前端环境中只加载一次:

class SharedDepsManager {
  constructor() {
    this.loadedLibs = new Map();
  }

  load(libName) {
    if (!this.loadedLibs.has(libName)) {
      this.loadedLibs.set(libName, this._loadLib(libName));
    }
    return this.loadedLibs.get(libName);
  }

  _loadLib(libName) {
    switch (libName) {
      case 'lodash':
        return import('lodash');
      case 'moment':
        return import('moment');
      default:
        throw new Error(`Unknown lib: ${libName}`);
    }
  }
}

// 主应用初始化单例
window.sharedDeps = new SharedDepsManager();

// 子应用使用
window.sharedDeps.load('lodash').then(_ => {
  _.debounce(() => {}, 300);
});

工厂模式创建微应用实例

根据配置动态创建不同类型的子应用:

class MicroAppFactory {
  static createApp(config) {
    switch (config.framework) {
      case 'react':
        return new ReactMicroApp(config);
      case 'vue':
        return new VueMicroApp(config);
      case 'angular':
        return new AngularMicroApp(config);
      default:
        throw new Error(`Unsupported framework: ${config.framework}`);
    }
  }
}

// 使用示例
const appConfigs = [
  { name: 'product', framework: 'react' },
  { name: 'checkout', framework: 'vue' }
];

const apps = appConfigs.map(config => 
  MicroAppFactory.createApp(config)
);

apps.forEach(app => app.mount());

中介者模式协调应用交互

通过中介者避免子应用直接相互引用:

class MicroFrontendMediator {
  constructor() {
    this.apps = {};
  }

  register(appName, app) {
    this.apps[appName] = app;
  }

  notify(sender, event, data) {
    Object.entries(this.apps).forEach(([name, app]) => {
      if (name !== sender && app.handleEvent) {
        app.handleEvent(event, data);
      }
    });
  }
}

// 主应用初始化
const mediator = new MicroFrontendMediator();

// 子应用A注册
mediator.register('product', {
  handleEvent(event, data) {
    if (event === 'CART_UPDATE') {
      this.updateCartBadge(data.count);
    }
  }
});

// 子应用B触发事件
mediator.notify('checkout', 'CART_UPDATE', { count: 3 });

状态模式处理应用生命周期

管理微应用的不同状态及其转换:

class MicroAppState {
  constructor(app) {
    this.app = app;
  }

  mount() {}
  unmount() {}
  update() {}
}

class MountedState extends MicroAppState {
  unmount() {
    this.app.container.innerHTML = '';
    this.app.setState(new UnmountedState(this.app));
  }
}

class UnmountedState extends MicroAppState {
  mount() {
    this.app.render();
    this.app.setState(new MountedState(this.app));
  }
}

class MicroApp {
  constructor() {
    this.setState(new UnmountedState(this));
  }

  setState(state) {
    this.state = state;
  }

  render() {
    console.log('Rendering app');
  }
}

// 使用
const app = new MicroApp();
app.state.mount();  // 从卸载状态转为挂载状态
app.state.unmount(); // 回到卸载状态

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步