字节前端面试提问:微应用的实现方式有哪些?

前端面试提问:常见的微应用实现方式有哪些?

字节三面面试官问到公司项目,我讲了下公司项目使用了qiankun集成vue2和vue3新老框架,带来的一系列问题,以及后续如何重构优化的。

面试官接着问,你还知道哪些框架?与qiankun有什么不同?我提到了wujie,就简单讲了讲。掘金有本前端小册专门讲微应用的原理,可惜我买了只看了三分之一,所以这个问题回答的不够深。现在简单总结下。

一、iframe 嵌套

原理 :利用 <iframe> 标签加载子应用页面,通过原生浏览器隔离特性实现沙箱环境。
优点

• 天然隔离性:样式和 JavaScript 完全隔离,避免全局污染。

• 技术栈无关:子应用可独立使用任何技术栈。
缺点

• 通信困难:需通过 postMessage 或 URL 参数传递数据,跨域处理复杂。

• 用户体验差:页面刷新导致状态丢失,加载性能较低。
适用场景:简单嵌入独立子页面,对交互要求低的场景(如报表展示)。

示例代码

  1. 主应用加载子应用
html 复制代码
<iframe id="subApp" src="http://child-app.com"></iframe>
  1. 跨iframe通信
javascript 复制代码
// 主应用发送消息
document.getElementById('subApp').contentWindow.postMessage({ type: 'UPDATE_DATA' }, '*');
// 子应用接收消息
window.addEventListener('message', (event) => {
  if (event.data.type === 'UPDATE_DATA') {
    // 处理数据
  }
});

二、Web Components 技术

原理 :基于浏览器原生支持的 CustomElementShadow DOM,将子应用封装为独立组件。
优点

• 原生隔离:通过 Shadow DOM 实现样式和 DOM 隔离。

• 标准化:无需依赖框架,浏览器原生支持。
缺点

• 生态不足:社区工具链较少,复杂功能需自行实现。

• 兼容性:部分旧浏览器不支持。
适用场景:轻量级跨技术栈集成(如 Vue + React 混合项目)。

示例代码

  1. 定义自定义元素
javascript 复制代码
class MicroApp extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.innerHTML = `<style>:host { display: block; }</style>
                         <div>子应用内容</div>`;
  }
}
customElements.define('micro-app', MicroApp);
  1. 主应用中使用
html 复制代码
<micro-app></micro-app>

三、路由分发式(Nginx 反向代理/前端路由)

原理 :通过服务端路由(Nginx)或前端路由将不同路径映射到独立子应用。
优点

  • 简单易用:无需复杂配置,子应用完全独立。
  • 独立部署:每个子应用可单独发布。
  • 可以轻松添加或移除子应用,适应业务的快速变化。

缺点

  • 状态管理难:页面跳转导致全局状态丢失。
  • 重复加载:公共依赖无法共享,资源浪费。
  • 部署复杂:涉及到多个服务器和路由配置,增加了部署的复杂性。
  • 跨域问题:如果子应用与主应用不在同一个服务器上,需要处理跨域请求。

适用场景:多团队维护的简单项目,技术栈统一(如全 Vue应用)。

示例代码

  1. Nginx配置反向代理
nginx 复制代码
# 子应用1路由配置
location /app1 {
    proxy_pass http://app1-server;
}
# 子应用2路由配置
location /app2 {
    proxy_pass http://app2-server;
}
  1. 前端路由动态加载(Vue示例)
javascript 复制代码
import Vue from 'vue';
import VueRouter from 'vue-router';
import Layout from '../views/Layout.vue'; // 主应用的布局组件

Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView,
  },
  {
    path: '/subapp',
    name: 'subapp',
    component: Layout,
    children: [
      {
        path: 'app1',
        name: 'app1',
        component: () => import('http://subapp-server-url/subapp/app1.vue'), // 子应用的组件
      },
      {
        path: 'app2',
        name: 'app2',
        component: () => import('http://subapp-server-url/subapp/app2.vue'), // 子应用的组件
      },
    ],
  },
];

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
});

export default router;

四、框架化方案(Single-SPA/Qiankun/Garfish)

Single-SPA

原理 :通过路由劫持动态加载子应用,提供生命周期管理。
优点

• 技术栈自由:支持 React、Vue、Angular 混合开发。

• 生态丰富:插件支持状态管理、依赖共享等。
缺点:配置复杂,需手动处理沙箱和样式隔离。

示例代码
  1. 主应用配置
javascript 复制代码
// 主应用入口文件
import { registerApplication, start } from 'single-spa';

// 注册子应用(React 示例)
registerApplication({
  name: 'react-app',
  app: () => System.import('react-app'), // 加载子应用入口
  activeWhen: '/react', // 路由匹配
  customProps: { user: 'admin' } // 传递参数
});

start();
  1. 子应用配置(React 示例)
javascript 复制代码
// 子应用入口文件
import singleSpaReact from 'single-spa-react';
import React from 'react';
import App from './App';

const lifecycles = singleSpaReact({
  React,
  ReactDOM,
  rootComponent: App,
  domElementGetter: () => document.getElementById('react-app')
});

export const { bootstrap, mount, unmount } = lifecycles;

Qiankun

原理 :基于 Single-SPA 封装,内置沙箱和样式隔离。
优点

• 开箱即用:简化配置,支持自动沙箱隔离。

• 企业级支持:阿里生态成熟,适合复杂项目。
缺点:依赖冲突需手动解决(如多版本 React)。

示例代码
  1. 主应用配置(Vue 示例)
javascript 复制代码
// src/main.js(主应用)
import { createApp } from 'vue';
import { registerMicroApps, start } from 'qiankun';
import App from './App.vue';

const app = createApp(App);

// 注册子应用
registerMicroApps([
  {
    name: 'sub-app',
    entry: '//localhost:3001', // 子应用入口地址
    container: '#subapp-container', // 挂载容器
    activeRule: '/sub-app', // 路由匹配规则
    props: { store: mainStore } // 传递主应用状态
  }
]);

start(); // 启动 qiankun
app.mount('#main-app');
  1. 子应用配置(Vue 示例)
javascript 复制代码
// src/main.js(子应用)
let router = null;
let instance = null;

function render(props = {}) {
  const { container } = props;
  router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? '/sub-app' : '/',
    mode: 'history',
    routes
  });

  instance = new Vue({ router, store, render: h => h(App) })
    .$mount(container ? container.querySelector('#app') : '#app');
}

// 导出生命周期
export async function bootstrap() { /* 初始化逻辑 */ }
export async function mount(props) { render(props); }
export async function unmount() { instance.$destroy(); }
  1. 主-子应用通信
javascript 复制代码
// 主应用初始化全局状态
import { initGlobalState } from 'qiankun';
const actions = initGlobalState({ theme: 'light' });

// 子应用监听状态变化
export async function mount(props) {
  props.onGlobalStateChange((state, prev) => {
    console.log('主应用状态变更:', state);
  });
}

Garfish

原理 :字节跳动推出的轻量级框架,支持零配置接入。
优点

• 高性能:资源加载优化,首屏速度快。

• 低侵入性:子应用无需改造。
适用场景:快速集成多团队子应用(如中后台系统)。

示例代码
  1. 主应用配置
javascript 复制代码
// 主应用入口文件
import Garfish from '@garfish/core';

Garfish.run({
  apps: [
    {
      name: 'vue-app',
      entry: '//localhost:8081', // 子应用入口
      activeRule: '/vue-app', // 路由规则
      props: { token: 'xxx' } // 传递参数
    }
  ],
  sandbox: { strictIsolation: true } // 沙箱隔离
});
  1. 子应用配置(Vue 示例)
javascript 复制代码
// 子应用入口文件
import { bootstrap, mount, unmount } from '@garfish/runtime-vue';
import App from './App.vue';

bootstrap(App).then(() => {
  mount(App, { dom: '#vue-app' });
});

// 导出生命周期
window.unmount = unmount;

五、EMP(基于 Module Federation 优化)

原理 :对 Webpack 5 Module Federation 二次封装,优化 ESM 模块支持。
优点

• 性能更优:减少模块解析开销,动态加载更快。

• 配置简化:提供预设规则,降低使用门槛。
缺点 :依赖 Webpack 5,技术栈受限。
适用场景:需高频共享模块的大型项目(如电商平台)。

示例代码

  1. 子应用暴露模块(webpack配置)
javascript 复制代码
new ModuleFederationPlugin({
  name: 'app1',
  filename: 'remoteEntry.js',
  exposes: { './Button': './src/Button.js' },
  shared: ['react', 'react-dom']
});
  1. 主应用消费模块
javascript 复制代码
const RemoteButton = React.lazy(() => import('app1/Button'));
function App() {
  return (
    <React.Suspense fallback="Loading...">
      <RemoteButton />
    </React.Suspense>
  );
}

六、无界(腾讯方案)

原理 :通过 iframe 沙箱 + 代理机制实现子应用隔离。
优点

• 极致隔离:安全性高,适合金融、政务场景。

• 多团队协作:支持独立开发部署。
缺点:通信效率较低,需通过代理层中转数据。

示例代码

  1. 主应用配置
javascript 复制代码
import Wujie from 'wujie';
new Wujie({
  container: '#app',
  apps: [
    { name: 'app1', entry: '//localhost:3001', activeRule: '/app1' }
  ]
});
  1. 子应用适配
javascript 复制代码
if (window.__WUJIE__) {
  window.__WUJIE_MOUNT = () => {
    Vue.createApp(App).mount('#app');
  };
  window.__WUJIE_UNMOUNT = () => {
    app.unmount();
  };
}

总结与选型建议

方案 技术栈 隔离性 适用规模 典型场景
iframe 任意 小型 独立页面嵌入
Web Components 原生 中小型 跨框架组件集成
Qiankun 主流框架 中高 中大型 企业级复杂系统
Module Federation Webpack 5 大型 模块共享密集型项目
Garfish 主流框架 中小型 快速集成多团队应用
Nginx反向代理 Nginx+任意前端框架 中大型 企业级应用、统一入口管理、跨域问题解决
相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端