返回笔记首页

Micro-App 轻量方案

主题配置

一、Micro-App 核心原理

1.1 技术架构

Micro-App 基于 Web Component 实现,是目前最轻量、最简单的微前端方案。

plain
Micro-App 架构
├── Web Component
│   ├── Custom Element(自定义元素)
│   ├── Shadow DOM(样式隔离)
│   └── 类 Vue 组件使用
│
├── 沙箱隔离
│   ├── with + Proxy 沙箱
│   ├── iframe 沙箱(可选)
│   └── 自动样式隔离
│
└── 数据通信
    ├── Props 传递
    ├── 数据绑定
    └── 事件通信

1.2 核心特点

1. 类组件化使用

vue
<!-- 就像使用普通 Vue 组件一样 -->
<template>
  <div>
    <micro-app
      name="app1"
      url="http://localhost:8081/"
      :data="appData"
      @datachange="handleDataChange"
    />
  </div>
</template>
2. 自动样式隔离
javascript
// Micro-App 自动处理样式隔离,无需配置
// 原理:利用 Web Component 的 Shadow DOM
3. 零改造接入
javascript
// 子应用几乎不需要改造
// 只需在 webpack 配置中设置 publicPath

// vue.config.js
module.exports = {
  publicPath: window.__MICRO_APP_BASE_ROUTE__ || '/'
}

1.3 与其他方案对比

特性 Micro-App qiankun Wujie
接入难度 极低
学习成本 极低
包体积 极小(46KB) 中(234KB) 中(180KB)
样式隔离 自动 需配置 天然
JS 隔离 with 沙箱 Proxy 沙箱 iframe 沙箱
子应用改造 几乎无 需要 零改造
适用场景 中小型项目 大型项目 强隔离需求

二、Micro-App 实战配置

2.1 主应用配置

安装

bash
npm install @micro-zoe/micro-app
# or
yarn add @micro-zoe/micro-app

完整代码示例

vue
<template>
  <div id="main-app">
    <!-- 导航菜单 -->
    <nav class="main-nav">
      <div class="logo">Micro-App 示例</div>
      <ul class="menu">
        <li
          v-for="app in apps"
          :key="app.name"
          @click="switchApp(app.name)"
          :class="{ active: currentApp === app.name }"
        >
          {{ app.title }}
        </li>
      </ul>
      <div class="user-info">
        <span>{{ userData.name }}</span>
        <button @click="logout">退出</button>
      </div>
    </nav>

    <!-- 主应用内容 -->
    <div class="main-content">
      <!-- 主应用首页 -->
      <div v-if="currentApp === 'home'" class="home-page">
        <h1>Micro-App 微前端示例</h1>
        <p>这是最简单、最轻量的微前端方案</p>

        <div class="features">
          <div class="feature-card">
            <h3>零学习成本</h3>
            <p>像使用组件一样使用微前端</p>
          </div>
          <div class="feature-card">
            <h3>自动样式隔离</h3>
            <p>无需任何配置</p>
          </div>
          <div class="feature-card">
            <h3>极小体积</h3>
            <p>仅 46KB</p>
          </div>
        </div>
      </div>

      <!-- 子应用容器 -->
      <micro-app
        v-else
        :name="currentApp"
        :url="getAppUrl(currentApp)"
        :data="microAppData"
        :baseroute="getBaseroute(currentApp)"
        @mounted="onAppMounted"
        @unmount="onAppUnmount"
        @datachange="onDataChange"
        @error="onError"
        inline
        disableScopecss
        disableSandbox
        keep-alive
      />
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, watch } from 'vue'
import microApp from '@micro-zoe/micro-app'

// 初始化 micro-app
onMounted(() => {
  microApp.start({
    // 全局配置
    plugins: {
      modules: {
        // 子应用列表
        'app1': [{
          loader(code) {
            // 可以对子应用代码进行处理
            console.log('处理 app1 代码')
            return code
          }
        }]
      }
    },

    // 生命周期
    lifeCycles: {
      created(e) {
        console.log('created', e)
      },
      beforemount(e) {
        console.log('beforemount', e)
      },
      mounted(e) {
        console.log('mounted', e)
      },
      unmount(e) {
        console.log('unmount', e)
      },
      error(e) {
        console.error('error', e)
      }
    },

    // 预加载
    preFetchApps: [
      { name: 'app1', url: 'http://localhost:8081/' }
    ],

    // 全局数据
    globalAssets: {
      js: ['https://cdn.jsdelivr.net/npm/vue@3'],
      css: []
    }
  })
})

const currentApp = ref('home')

const apps = [
  { name: 'home', title: '首页', url: '' },
  { name: 'app1', title: '子应用1', url: 'http://localhost:8081/' },
  { name: 'app2', title: '子应用2', url: 'http://localhost:8082/' },
  { name: 'app3', title: '子应用3', url: 'http://localhost:8083/' }
]

// 用户数据
const userData = reactive({
  name: 'Admin',
  role: 'admin',
  token: 'xxxx-xxxx'
})

// 传递给子应用的数据
const microAppData = ref({
  user: userData,
  theme: 'light',
  timestamp: Date.now()
})

// 切换应用
const switchApp = (appName) => {
  currentApp.value = appName
}

// 获取应用 URL
const getAppUrl = (appName) => {
  const app = apps.find(a => a.name === appName)
  return app ? app.url : ''
}

// 获取 baseroute
const getBaseroute = (appName) => {
  return `/${appName}`
}

// 子应用生命周期
const onAppMounted = (e) => {
  console.log('子应用挂载完成', e)
}

const onAppUnmount = (e) => {
  console.log('子应用卸载', e)
}

// 监听子应用数据变化
const onDataChange = (e) => {
  console.log('子应用数据变化', e.detail.data)

  // 处理子应用发来的数据
  const data = e.detail.data
  if (data.type === 'updateUser') {
    Object.assign(userData, data.user)
  }
}

const onError = (e) => {
  console.error('子应用加载错误', e)
}

// 更新传递给子应用的数据
const updateMicroAppData = () => {
  microAppData.value = {
    ...microAppData.value,
    timestamp: Date.now()
  }
}

// 监听用户数据变化,同步给子应用
watch(() => userData, (newVal) => {
  microAppData.value = {
    ...microAppData.value,
    user: { ...newVal }
  }
}, { deep: true })

const logout = () => {
  if (confirm('确定退出吗?')) {
    userData.name = ''
    userData.token = ''
    currentApp.value = 'home'
  }
}
</script>

<style scoped>
#main-app {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.main-nav {
  display: flex;
  align-items: center;
  padding: 0 24px;
  height: 64px;
  background: #001529;
  color: white;
  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}

.logo {
  font-size: 20px;
  font-weight: bold;
  margin-right: 50px;
}

.menu {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1;
  gap: 8px;
}

.menu li {
  padding: 8px 20px;
  cursor: pointer;
  border-radius: 4px;
  transition: all 0.3s;
}

.menu li:hover {
  background: rgba(255, 255, 255, 0.1);
}

.menu li.active {
  background: #1890ff;
}

.user-info {
  display: flex;
  align-items: center;
  gap: 16px;
}

.user-info button {
  padding: 8px 20px;
  background: #1890ff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s;
}

.user-info button:hover {
  background: #40a9ff;
}

.main-content {
  flex: 1;
  overflow: auto;
  background: #f0f2f5;
}

.home-page {
  padding: 40px;
  max-width: 1200px;
  margin: 0 auto;
}

.home-page h1 {
  font-size: 36px;
  color: #001529;
  margin-bottom: 16px;
}

.home-page p {
  font-size: 18px;
  color: #666;
  margin-bottom: 40px;
}

.features {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.feature-card {
  background: white;
  padding: 32px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  text-align: center;
  transition: all 0.3s;
}

.feature-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}

.feature-card h3 {
  font-size: 20px;
  color: #1890ff;
  margin-bottom: 12px;
}

.feature-card p {
  font-size: 14px;
  color: #666;
  margin: 0;
}
</style>

2.2 子应用配置

子应用改造(极少)

javascript
// 子应用 main.js
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import routes from './router'

// 获取应用基础路径
const baseroute = window.__MICRO_APP_BASE_ROUTE__ || '/'

const router = createRouter({
  history: createWebHistory(baseroute),
  routes
})

const app = createApp(App)
app.use(router)
app.mount('#app')

// 就这么简单!子应用几乎不需要改造

子应用通信

vue
<!-- 子应用组件 -->
<template>
  <div class="sub-app">
    <h2>子应用1</h2>

    <!-- 显示主应用传来的数据 -->
    <div class="data-panel">
      <h3>主应用数据:</h3>
      <pre>{{ mainAppData }}</pre>
    </div>

    <div class="actions">
      <button @click="sendDataToMain">发送数据给主应用</button>
      <button @click="updateUserInfo">更新用户信息</button>
    </div>

    <!-- 子应用自己的功能 -->
    <div class="feature-content">
      <h3>子应用功能列表</h3>
      <ul>
        <li v-for="item in features" :key="item.id">{{ item.name }}</li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const mainAppData = ref({})
const features = ref([
  { id: 1, name: '功能1' },
  { id: 2, name: '功能2' },
  { id: 3, name: '功能3' }
])

// 监听主应用数据变化
const dataListener = (data) => {
  console.log('收到主应用数据', data)
  mainAppData.value = data

  // 根据数据变化做相应处理
  if (data.theme) {
    document.body.setAttribute('data-theme', data.theme)
  }
}

onMounted(() => {
  // 方式1: 监听数据变化
  if (window.microApp) {
    // 获取主应用数据
    mainAppData.value = window.microApp.getData()

    // 监听数据变化
    window.microApp.addDataListener(dataListener)
  }
})

onUnmounted(() => {
  // 卸载时移除监听
  if (window.microApp) {
    window.microApp.removeDataListener(dataListener)
  }
})

// 发送数据给主应用
const sendDataToMain = () => {
  if (window.microApp) {
    window.microApp.dispatch({
      type: 'notification',
      message: '子应用发来的消息',
      timestamp: Date.now()
    })
  }
}

// 更新用户信息
const updateUserInfo = () => {
  if (window.microApp) {
    window.microApp.dispatch({
      type: 'updateUser',
      user: {
        name: 'Updated User',
        role: 'super-admin'
      }
    })
  }
}
</script>

<style scoped>
.sub-app {
  padding: 24px;
}

h2 {
  color: #001529;
  margin-bottom: 24px;
}

.data-panel,
.feature-content {
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  margin-bottom: 20px;
}

h3 {
  font-size: 16px;
  color: #333;
  margin-bottom: 12px;
}

pre {
  background: #f5f5f5;
  padding: 12px;
  border-radius: 4px;
  font-size: 13px;
  overflow-x: auto;
}

.actions {
  display: flex;
  gap: 12px;
  margin: 20px 0;
}

.actions button {
  padding: 10px 24px;
  background: #1890ff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s;
}

.actions button:hover {
  background: #40a9ff;
  transform: translateY(-2px);
}

.feature-content ul {
  list-style: none;
  padding: 0;
}

.feature-content li {
  padding: 12px;
  background: #f0f2f5;
  border-radius: 4px;
  margin-bottom: 8px;
}
</style>

Webpack 配置

javascript
// vue.config.js
module.exports = {
  devServer: {
    port: 8081,
    headers: {
      'Access-Control-Allow-Origin': '*'
    }
  },

  publicPath: window.__MICRO_APP_BASE_ROUTE__ || '/',

  configureWebpack: {
    output: {
      // Micro-App 不需要 UMD 格式
      // 直接使用默认配置即可
    }
  }
}

2.3 高级特性

2.3.1 预加载

javascript
// 主应用
import microApp from '@micro-zoe/micro-app'

microApp.start({
  preFetchApps: [
    {
      name: 'app1',
      url: 'http://localhost:8081/',
      // 预加载时机
      level: 2, // 1=空闲时间 2=立即加载
      // 是否默认开启沙箱
      'default-page': '/home',
      // 是否保活
      'keep-alive': true
    }
  ]
})

// 或手动预加载
microApp.preFetch([
  { name: 'app1', url: 'http://localhost:8081/' }
])

2.3.2 保活机制

vue
<template>
  <!-- keep-alive 属性开启保活 -->
  <micro-app
    name="app1"
    url="http://localhost:8081/"
    keep-alive
  />
</template>

<script setup>
// 保活模式下,应用切换不会销毁
// 再次显示时会快速恢复
// 适合需要保持状态的应用
</script>

2.3.3 样式隔离控制

vue
<template>
  <!-- disableScopecss: 关闭样式隔离 -->
  <micro-app
    name="app1"
    url="http://localhost:8081/"
    disableScopecss
  />

  <!-- 默认开启样式隔离,子应用样式不会泄露 -->
  <micro-app
    name="app2"
    url="http://localhost:8082/"
  />
</template>

2.3.4 JS 沙箱控制

vue
<template>
  <!-- disableSandbox: 关闭 JS 沙箱 -->
  <micro-app
    name="app1"
    url="http://localhost:8081/"
    disableSandbox
  />

  <!-- iframe: 使用 iframe 沙箱(更强隔离) -->
  <micro-app
    name="app2"
    url="http://localhost:8082/"
    iframe
  />
</template>

2.3.5 路由模式

vue
<template>
  <!-- 默认模式:子应用路由独立 -->
  <micro-app
    name="app1"
    url="http://localhost:8081/"
  />

  <!-- 路由同步模式:子应用路由同步到主应用 -->
  <micro-app
    name="app2"
    url="http://localhost:8082/"
    :baseroute="`/app2`"
  />
</template>

2.4 完整应用示例

多应用管理

vue
<template>
  <div class="multi-app-container">
    <div class="sidebar">
      <div
        v-for="app in apps"
        :key="app.name"
        class="app-item"
        :class="{ active: activeApps.includes(app.name) }"
        @click="toggleApp(app.name)"
      >
        <div class="app-icon">{{ app.icon }}</div>
        <div class="app-name">{{ app.title }}</div>
        <div v-if="activeApps.includes(app.name)" class="app-status">运行中</div>
      </div>
    </div>

    <div class="app-container">
      <div class="tabs">
        <div
          v-for="name in activeApps"
          :key="name"
          class="tab"
          :class="{ active: currentApp === name }"
          @click="switchToApp(name)"
        >
          {{ getAppTitle(name) }}
          <span class="close" @click.stop="closeApp(name)">×</span>
        </div>
      </div>

      <div class="app-content">
        <micro-app
          v-for="name in activeApps"
          :key="name"
          v-show="currentApp === name"
          :name="name"
          :url="getAppUrl(name)"
          :data="appData"
          keep-alive
          @mounted="onAppMounted(name)"
        />
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

const apps = [
  { name: 'app1', title: '应用1', icon: '📊', url: 'http://localhost:8081/' },
  { name: 'app2', title: '应用2', icon: '📈', url: 'http://localhost:8082/' },
  { name: 'app3', title: '应用3', icon: '📉', url: 'http://localhost:8083/' }
]

const activeApps = ref([])
const currentApp = ref('')

const appData = reactive({
  user: { name: 'Admin' },
  token: 'xxxx'
})

const toggleApp = (name) => {
  if (activeApps.value.includes(name)) {
    closeApp(name)
  } else {
    activeApps.value.push(name)
    currentApp.value = name
  }
}

const switchToApp = (name) => {
  currentApp.value = name
}

const closeApp = (name) => {
  const index = activeApps.value.indexOf(name)
  if (index > -1) {
    activeApps.value.splice(index, 1)

    if (currentApp.value === name) {
      currentApp.value = activeApps.value[activeApps.value.length - 1] || ''
    }
  }
}

const getAppTitle = (name) => {
  return apps.find(app => app.name === name)?.title || name
}

const getAppUrl = (name) => {
  return apps.find(app => app.name === name)?.url || ''
}

const onAppMounted = (name) => {
  console.log(`${name} 挂载完成`)
}
</script>

<style scoped>
.multi-app-container {
  display: flex;
  height: 100vh;
}

.sidebar {
  width: 240px;
  background: #001529;
  padding: 20px 0;
}

.app-item {
  padding: 16px 24px;
  color: rgba(255, 255, 255, 0.65);
  cursor: pointer;
  transition: all 0.3s;
  display: flex;
  align-items: center;
  gap: 12px;
}

.app-item:hover {
  background: rgba(255, 255, 255, 0.1);
  color: white;
}

.app-item.active {
  background: #1890ff;
  color: white;
}

.app-icon {
  font-size: 24px;
}

.app-name {
  flex: 1;
  font-size: 14px;
}

.app-status {
  font-size: 12px;
  padding: 2px 8px;
  background: rgba(82, 196, 26, 0.2);
  border-radius: 10px;
  color: #52c41a;
}

.app-container {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.tabs {
  display: flex;
  background: #f0f2f5;
  border-bottom: 1px solid #d9d9d9;
}

.tab {
  padding: 12px 24px;
  background: white;
  border-right: 1px solid #d9d9d9;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 12px;
  transition: all 0.3s;
}

.tab:hover {
  background: #fafafa;
}

.tab.active {
  background: white;
  border-bottom: 2px solid #1890ff;
  color: #1890ff;
}

.tab .close {
  font-size: 18px;
  opacity: 0.5;
  transition: all 0.2s;
}

.tab .close:hover {
  opacity: 1;
  color: #ff4d4f;
}

.app-content {
  flex: 1;
  overflow: hidden;
}
</style>

三、使用技巧

3.1 全局数据共享

javascript
// 主应用定义全局数据
import microApp from '@micro-zoe/micro-app'

microApp.setGlobalData({ token: 'xxxx' })

// 子应用获取全局数据
const globalData = window.microApp.getGlobalData()

3.2 路由守卫

javascript
// 主应用路由守卫
router.beforeEach((to, from, next) => {
  // 检查子应用权限
  if (to.path.startsWith('/app1')) {
    const hasPermission = checkPermission('app1')
    if (!hasPermission) {
      next('/403')
      return
    }
  }
  next()
})

3.3 错误处理

vue
<template>
  <micro-app
    name="app1"
    url="http://localhost:8081/"
    @error="handleError"
  />
</template>

<script setup>
const handleError = (e) => {
  console.error('子应用加载错误', e)

  // 可以显示错误页面或重试
  if (confirm('子应用加载失败,是否重试?')) {
    window.location.reload()
  }
}
</script>

四、简历撰写指南

4.1 项目经验描述模板

项目名称: Micro-App 轻量级微前端实践

项目时间: 2024.08 - 2024.11

项目描述: 负责中小型管理系统的微前端改造,采用 Micro-App 框架快速实现应用拆分。通过类组件化的使用方式,实现了零学习成本的微前端接入,显著提升了开发效率和系统可维护性。

核心职责

  1. 技术选型:综合考虑项目规模、团队能力、接入成本,选择 Micro-App 轻量方案
  2. 架构设计:设计主应用框架,实现子应用注册、数据通信、权限控制
  3. 快速接入:指导团队完成 5 个子应用的改造,平均接入时间仅 2 小时
  4. 性能优化:实现子应用预加载、保活机制,切换速度提升 70%

技术栈: Micro-App、Vue3、Web Component、Shadow DOM

项目成果
  • 接入时间从 qiankun 的 2 天缩短到 2 小时(降低 90%)
  • 包体积仅 46KB,比 qiankun 小 80%
  • 样式隔离自动处理,零配置
  • 子应用几乎零改造,开发体验极佳
  • 系统维护成本降低 50%

4.2 SOP 标准回答话术

面试官:为什么选择 Micro-App 而不是 qiankun?

回答话术: "我们项目选择 Micro-App 主要基于以下考虑:

首先是项目规模。我们是一个中型管理系统,不是特别复杂,不需要 qiankun 那么重的方案。Micro-App 只有 46KB,qiankun 有 234KB,对我们来说 Micro-App 更轻量。

第二是接入成本。Micro-App 的使用方式就像普通 Vue 组件,写个 标签就行了,学习成本几乎为零。qiankun 需要理解 single-spa、生命周期、沙箱机制等概念,学习曲线比较陡。我们团队成员水平参差不齐,Micro-App 更容易上手。

第三是子应用改造。Micro-App 子应用几乎不需要改造,只要改一下 publicPath 就可以了。qiankun 需要导出生命周期函数、改 webpack 配置等,改造成本高。我们有几个老项目,改动越少越好。

第四是样式隔离。Micro-App 基于 Web Component,样式隔离是自动的,不需要任何配置。qiankun 需要配置 Shadow DOM 或 Scoped CSS,还可能遇到组件库不兼容的问题。

当然 Micro-App 也有劣势,比如功能相对简单、社区较小、复杂场景支持不足。但对我们的场景来说,这些劣势影响不大。我们更看重简单、轻量、易用。

最终效果很好,5 个子应用平均接入时间只要 2 小时,团队反馈开发体验非常好。"

4.3 难点与亮点分析

难点1:子应用通信

虽然 Micro-App 提供了数据通信,但相比 qiankun 功能较弱。

解决方案
javascript
// 封装通信工具类
class MicroAppBridge {
  constructor(appName) {
    this.appName = appName
    this.listeners = {}
  }

  // 发送消息
  emit(event, data) {
    if (window.microApp) {
      window.microApp.dispatch({
        event,
        data,
        from: this.appName
      })
    }
  }

  // 监听消息
  on(event, handler) {
    if (!this.listeners[event]) {
      this.listeners[event] = []
    }
    this.listeners[event].push(handler)
  }

  // 处理消息
  handleMessage(message) {
    const { event, data } = message
    if (this.listeners[event]) {
      this.listeners[event].forEach(handler => handler(data))
    }
  }
}

// 使用
const bridge = new MicroAppBridge('app1')
bridge.on('user-updated', (user) => {
  console.log('用户更新', user)
})

亮点1:极简接入流程

开发了一键接入工具:

bash
# 一键生成子应用
micro-app create my-app

# 自动配置 publicPath
# 自动添加通信代码
# 自动生成文档

# 接入时间从 2 天降到 2 小时

亮点2:保活机制优化

针对频繁切换的应用,使用保活:

vue
<micro-app
  name="frequent-app"
  keep-alive
/>

<!-- 切换速度提升 70% -->

4.4 完整简历示例

plain
【Micro-App 轻量级微前端实践】2024.08 - 2024.11

项目背景:
中型管理系统需要拆分为独立模块,降低耦合度,提升开发效率。考虑团队规模和技术能力,需要简单易用的微前端方案。

技术选型:
对比 qiankun、Micro-App、Wujie 后选择 Micro-App,原因:
- 轻量级(46KB),适合中小型项目
- 接入简单,学习成本低
- 类组件化使用,开发体验好
- 自动样式隔离,零配置

核心工作:
1. 快速接入实践
   - 制定子应用接入规范(仅需改 publicPath)
   - 开发接入工具,一键生成子应用模板
   - 指导团队完成 5 个子应用接入,平均耗时 2 小时

2. 通信机制设计
   - 封装统一的通信工具类,简化主子应用数据传递
   - 实现全局数据共享机制
   - 开发事件总线,支持跨应用通信

3. 性能优化
   - 配置子应用预加载,首次访问速度提升 50%
   - 启用保活机制,应用切换速度提升 70%
   - 实现懒加载,减少初始加载时间

4. 工程化建设
   - 开发脚手架工具,标准化子应用创建流程
   - 编写最佳实践文档和示例代码
   - 建立代码审查规范

技术栈:
Micro-App、Vue3、Web Component、Shadow DOM

项目成果:
- 接入时间:从 2 天缩短到 2 小时(降低 90%)
- 包体积:仅 46KB,比 qiankun 小 80%
- 学习成本:零学习成本,团队满意度 95%
- 开发效率:各模块独立开发,效率提升 40%
- 维护成本:系统维护成本降低 50%

五、总结

Micro-App 是最简单、最轻量的微前端方案,非常适合:

  • 中小型项目
  • 追求快速接入
  • 团队技术能力一般
  • 不需要复杂功能

核心优势

  1. 零学习成本(类组件使用)
  2. 极小体积(46KB)
  3. 自动样式隔离
  4. 子应用几乎零改造

适用场景

  • 快速搭建微前端系统
  • 技术栈统一的项目
  • 对性能要求不是特别高
  • 追求简单易用