什么是微前端?有哪些实现方案?
微前端是将大型前端应用拆分为多个独立的小应用,各自开发、部署、运行。
为什么需要微前端
- 巨石应用难以维护:一个项目几百万行代码
- 独立部署:各团队独立发布
- 技术栈无关:不同子应用可以用不同框架
- 增量迁移:逐步从旧框架迁移到新框架
实现方案
1. qiankun(基于 single-spa)
// 主应用
import { registerMicroApps, start } from 'qiankun'
registerMicroApps([
{
name: 'react-app',
entry: '//localhost:7100',
container: '#sub-app',
activeRule: '/react'
},
{
name: 'vue-app',
entry: '//localhost:7101',
container: '#sub-app',
activeRule: '/vue'
}
])
start()原理:通过 JS 沙箱加载子应用,路由匹配时挂载子应用。
2. Module Federation(Webpack 5)
// 子应用 webpack.config.js
new ModuleFederationPlugin({
name: 'remoteApp',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/Button'
},
shared: ['react', 'react-dom']
})
// 主应用
new ModuleFederationPlugin({
name: 'hostApp',
remotes: {
remoteApp: 'remoteApp@http://localhost:7100/remoteEntry.js'
}
})
// 使用远程组件
const RemoteButton = React.lazy(() => import('remoteApp/Button'))3. iframe(最简单但最隔离)
<iframe src="http://localhost:7100" />- ✅ 完全隔离(JS、CSS、路由)
- ❌ 性能差、通信困难、UX 差(弹窗被限制在 iframe 内)
4. Web Components
class MyComponent extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({ mode: 'open' })
shadow.innerHTML = `<style>:host { color: red }</style><div>Custom</div>`
}
}
customElements.define('my-component', MyComponent)5. NPM 包(组件级微前端)
// 将组件发布为 npm 包
import SharedButton from '@team/button'- ✅ 简单、类型安全
- ❌ 需要重新构建发布、不能独立部署
方案对比
| 方案 | 隔离性 | 独立部署 | 通信 | 性能 | 复杂度 |
|---|---|---|---|---|---|
| qiankun | JS 沙箱 | ✅ | postMessage | 中 | 中 |
| Module Federation | 部分 | ✅ | 直接调用 | 好 | 中 |
| iframe | 完全 | ✅ | postMessage | 差 | 低 |
| Web Components | Shadow DOM | ✅ | 属性/事件 | 好 | 高 |
| NPM 包 | 无 | ❌ | 直接调用 | 最好 | 最低 |
什么场景用微前端
- ✅ 大型企业应用,多团队协作
- ✅ 需要技术栈迁移(Vue2 → Vue3)
- ✅ 多个独立产品需要整合为一个门户
- ❌ 中小型项目(过度设计)
- ❌ 简单的组件复用(用 NPM 包即可)
常见问题
- CSS 隔离:Shadow DOM 或 CSS Modules
- JS 沙箱:Proxy 代理 window
- 通信:CustomEvent、postMessage、全局状态
- 路由:基座应用统一管理路由