当应用功能越来越多、参与开发的团队规模越来越大时,传统的*单体(Monolithic)*前端方式,也就是将应用作为一个整体开发与部署,会遇到一些困难。
- 代码库过大,构建时间变长。
- 即使只上线一处小改动,也要测试和部署整个应用。
- 多个团队在同一代码库工作,容易发生代码冲突,技术栈的选型与升级也更困难。
- 局部问题,例如缺陷或性能下降,可能波及整个应用。
*微前端(Micro Frontend,MFE)
把最早出现在服务端开发领域的
微服务架构(MSA)*理念应用到前端,以解决这些问题。
本文将介绍什么是微前端、它有哪些优势、如何实现,以及采用时需要考虑哪些问题。
微前端是一种架构风格,将大型前端应用拆成多个
小型且可独立部署
的前端应用,也称微应用。
用户看到的仍然是一个统一的网站或应用,其内部则由多个独立部分共同运行。
独立开发与部署
每个微应用都有自己的代码库,可以独立开发、测试、构建和部署。
这样能加快开发和部署。
提高团队自主性
各开发团队负责特定业务功能或领域的微应用,在技术选型和开发方式上有更多自主权,同时仍需进行整体协调。
逐步升级与技术多样性
引入新技术或升级现有技术栈时,可以先在某个微应用中逐步试行,再推广到其他部分。
理论上,每个微应用也可以使用不同的技术栈,如 React、Vue 或 Angular。
管理代码复杂性
将一个庞大的代码库拆为多个规模可控的代码库,以降低复杂性。

单体架构与微应用架构
| 特点 | 单体前端 | 微前端 |
|---|
代码库 | 一个大型代码库 | 多个较小的代码库 |
|---|
开发 | 所有团队在同一代码库中工作 | 各团队在独立的代码库中工作 |
|---|
部署 | 以整个应用为单位部署 | 各微应用可独立部署 |
|---|
技术栈 | 单一技术栈,难以更换 | 可以使用不同技术栈,便于逐步更换 |
|---|
团队结构 | 按职能划分的团队,或一个大型团队 | 按业务领域或功能划分的自主团队 |
|---|
耦合程度 | 较高,改动影响范围大 | 较低,改动影响范围有限 |
|---|
复杂性 | 初期较低,规模扩大后迅速上升 | 初期配置较复杂,单个微应用较简单 |
|---|
如何让多个独立的微应用在用户看来像一个完整的应用?
这就是
集成(Integration)
。常见做法是在用户浏览器中进行
运行时集成(Runtime Integration)
。
iframe
最早也最简单的方法。将各微应用加载到 iframe 中,使它们彼此隔离。
这种方式容易实现,但应用间通信复杂,URL 管理和 UI/UX 也容易显得割裂,因此近年来较少采用。
Web Components
使用 Web Components 这一 Web 标准,将各微应用封装为自定义 HTML 元素。
这种方式不依赖特定框架,但需要考虑浏览器支持范围与技术成熟度。
JavaScript 集成
通过 JavaScript 将微应用动态加载并挂载到特定 DOM 元素中。
Single-SPA 和 Webpack Module Federation 等工具基于这种方式。
Single-SPA 是一个 JavaScript 框架,用于管理微前端应用的
路由
和
生命周期(加载、挂载、卸载)
。
- 根据 URL 路径决定激活哪个微应用,并处理路由。
- 管理各微应用的生命周期,决定何时加载、显示(挂载)及移除(卸载)。
- 支持将使用 React、Angular、Vue 等不同框架构建的微应用放在一起使用。
容器应用(根应用)
这是包含 Single-SPA 配置的主应用。
注册应用
在 Single-SPA 中注册各微应用,指定哪些 URL 路径会激活它,以及如何加载应用代码。
路由
URL 变化时,Single-SPA 根据注册信息激活匹配当前路径的微应用,并停用(卸载)不再需要的应用。

Single-SPA 架构
Webpack Module Federation 🔗
即使微应用彼此独立,也可能使用相同的库,例如 React、lodash,或设计系统中的按钮等公共组件。
如果每个微应用都包含一份共享资源,整个应用的体积会不必要地变大。
Webpack 5 引入的
Module Federation
可以解决这一问题。
Module Federation 允许多个独立构建的 JavaScript 应用(打包产物)在
运行时
动态共享代码。
Host
加载并使用其他应用(Remote)代码的应用。
在微前端中,通常由承载整个应用的容器(Shell)担任 Host。
Remote
将自身代码暴露(expose)给其他应用(Host)的应用。
各微应用都可以充当 Remote。
Shared Dependencies
多个应用(Host 和 Remote)之间共享的依赖库。
Module Federation 会考虑共享依赖的版本,避免重复加载,并有效管理这些依赖。
例如,Host 和 Remote 都使用 React v18 时,浏览器只需要加载一次 React v18。
Exposed Modules
Remote 应用决定提供给 Host 的特定模块,例如组件或函数。
在 Webpack 配置文件中设置 Module Federation。
Remote 앱의 webpack.config.js// Remote 앱 (예: 'profileApp')의 webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const deps = require('./package.json').dependencies; // 공유 의존성 버전 관리
module.exports = {
// ... 기타 설정 ...
plugins: [
new ModuleFederationPlugin({
name: 'profileApp', // Remote 앱의 고유 이름
filename: 'remoteEntry.js', // Host가 참조할 진입점 파일
exposes: {
// 외부에 노출할 모듈 경로 매핑 ('./UserProfile' 키로 접근)
'./UserProfile': './src/UserProfile',
},
shared: { // 공유할 의존성 설정
...deps, // package.json의 모든 의존성 공유 (간단 예시)
react: { singleton: true, requiredVersion: deps.react },
'react-dom': { singleton: true, requiredVersion: deps['react-dom'] },
},
}),
],
};
Host 앱의 webpack.config.js// Host 앱 (예: 'containerApp')의 webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const deps = require('./package.json').dependencies;
module.exports = {
// ... 기타 설정 ...
plugins: [
new ModuleFederationPlugin({
name: 'containerApp',
remotes: {
// 사용할 Remote 앱 정보 등록 (profileApp@http://localhost:3001/remoteEntry.js)
profileApp: 'profileApp@http://localhost:3001/remoteEntry.js',
},
shared: { // 공유할 의존성 설정 (Remote와 동일하게)
...deps,
react: { singleton: true, requiredVersion: deps.react },
'react-dom': { singleton: true, requiredVersion: deps['react-dom'] },
},
}),
],
};
Host 앱에서 Remote 컴포넌트 사용// Host 앱의 컴포넌트에서 Remote 컴포넌트 사용
import React, { lazy, Suspense } from 'react';
const RemoteUserProfile = lazy(() => import('profileApp/UserProfile'));
function App() {
return (
<div>
<h1>컨테이너 앱</h1>
<Suspense fallback="Loading Profile...">
<RemoteUserProfile />
</Suspense>
</div>
);
}
有了这些配置,containerApp 就能像使用自身代码一样加载 profileApp 暴露的 UserProfile 组件,同时避免重复加载 React 等共享库。
问:什么是 Webpack Module Federation?它解决了微前端中的哪些问题?
答:它允许多个独立构建的 Webpack 应用在运行时动态共享代码。在微前端中,可以用它在微应用之间共享组件,避免重复加载公共库。
微前端带来不少好处,同时也增加了接入与运营的复杂性。
初期配置复杂
配置 Module Federation、Single-SPA 等工具并搭建集成环境,需要投入前期工作。
管理技术栈
理论上可以使用多种技术栈,但差异过大可能影响开发体验,增加构建和部署的复杂性,也会使打包产物变大。因此需要在一定程度上统一技术栈,或制定相关规范。
管理共享依赖的版本
需要制定策略,统一管理多个微应用使用的共享库版本。Module Federation 可以提供帮助,版本仍需仔细维护。
保持 UI/UX 一致
多个团队独立开发时,整体 UI/UX 容易出现差异。应建立并使用共享设计系统,推荐以库的形式提供。
状态管理与应用间通信
如果微应用需要共享状态或互相通信,应明确接口和通信方式,例如使用 Custom Events、window 对象、路由状态或全局状态库。这可能是微前端中最难处理的部分之一。
划分团队边界
要慎重决定如何划分微应用和团队。可以依据业务领域、用户旅程或功能划分,并尽量减少团队间的依赖。
独立的部署流水线
需要建立 CI/CD 流水线,使各微应用可以独立构建、测试和部署。
运营与监控更复杂
需要管理和监控多个部署单元,因此运营可能更加复杂。
Module Federation 在内部利用依赖图管理共享模块与版本。Single-SPA 可以用类似哈希表的路由表,将 URL 映射到微应用。
今天介绍了微前端,这是一种用于应对大型前端应用开发复杂性的架构模式。
微前端并不适用于所有项目。
应综合考虑应用规模、团队结构和技术需求,再决定是否采用。
如果决定采用,可以结合本文介绍的技术与考虑事项制定计划,逐步推进。
下一篇将介绍如何在前端有效处理 API 通信与管理异步操作。从比较 Axios 与 Fetch,到 AbortController 和 GraphQL 客户端,一起看看不同的 API 通信方式。