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

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

字节三面面试官问到公司项目,我讲了下公司项目使用了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+任意前端框架 中大型 企业级应用、统一入口管理、跨域问题解决
相关推荐
9ilk3 分钟前
【前端基础】--- HTML
前端·html
Lafar5 分钟前
Dart单线程怎么保证UI运行流畅
前端·面试
uhakadotcom7 分钟前
BentoML远程代码执行漏洞(CVE-2025-27520)详解与防护指南
后端·算法·面试
_一条咸鱼_10 分钟前
大厂AI 大模型面试:监督微调(SFT)与强化微调(RFT)原理
人工智能·深度学习·面试
不和乔治玩的佩奇11 分钟前
【 设计模式】常见前端设计模式
前端
bloxed17 分钟前
vue+vite 减缓首屏加载压力和性能优化
前端·vue.js·性能优化
曼陀罗28 分钟前
自动找空闲端口再启动 mock-server」的脚本
前端框架
打野赵怀真29 分钟前
React Hooks 的优势和使用场景
前端·javascript
HaushoLin33 分钟前
ERR_PNPM_DLX_NO_BIN No binaries found in tailwindcss
前端·vue.js·css3·html5
Lafar34 分钟前
Widget 树和 Element 树和RenderObject树是一一 对应的吗
前端