微前端使用指南
1. 微前端概述
1.1 什么是微前端
微前端是一种类似于微服务的架构,它将前端应用拆分为多个小型、独立的前端应用,这些应用可以独立开发、独立部署、独立运行。
javascript
// 微前端架构示例
const microApps = [
{
name: 'user-management',
entry: 'https://user.example.com',
container: '#user-container',
activeRule: '/user',
},
{
name: 'order-management',
entry: 'https://order.example.com',
container: '#order-container',
activeRule: '/order',
},
];
1.2 微前端的核心价值
技术栈无关
- 不同团队可以使用不同的技术栈(React、Vue、Angular)
- 渐进式迁移老项目
- 技术栈升级风险可控
独立开发部署
- 团队自治,减少协调成本
- 独立的开发、测试、部署流程
- 故障隔离,单个应用问题不影响整体
代码库隔离
- 避免单体应用代码库过大
- 更好的代码组织和维护
- 团队职责边界清晰
1.3 微前端的挑战
性能问题
- 重复加载相同依赖
- 应用切换的性能开销
- 首屏加载时间可能增加
用户体验
- 应用间切换的一致性
- 共享状态管理复杂
- 样式隔离和冲突
技术复杂度
- 基础设施复杂度增加
- 调试和监控难度提升
- 版本兼容性管理
2. 主流微前端方案对比
2.1 iframe 方案
优点
html
<!-- 最简单的微前端实现 -->
<iframe src="https://sub-app.example.com" style="width: 100%; height: 500px; border: none;"> </iframe>
- 实现简单,天然隔离
- 技术栈完全无关
- 安全性好
缺点
- 性能差,刷新重新加载
- 通信复杂,postMessage API
- SEO 不友好
- 移动端兼容性问题
2.2 Web Components 方案
实现示例
javascript
// 定义微前端组件
class MicroApp extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<div id="micro-app-container"></div>
`;
this.loadApp();
}
async loadApp() {
const { mount } = await import('https://micro-app.example.com/app.js');
mount(this.querySelector('#micro-app-container'));
}
}
customElements.define('micro-app', MicroApp);
优点
- 原生支持,无需额外框架
- 真正的组件化
- 样式和脚本天然隔离
缺点
- 浏览器兼容性有限
- 学习成本高
- 生态不够成熟
2.3 Module Federation (Webpack 5)
配置示例
javascript
// webpack.config.js - 主应用
const ModuleFederationPlugin = require('@module-federation/webpack');
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
userApp: 'userApp@http://localhost:3001/remoteEntry.js',
orderApp: 'orderApp@http://localhost:3002/remoteEntry.js',
},
}),
],
};
// 使用远程模块
const UserApp = React.lazy(() => import('userApp/App'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<UserApp />
</Suspense>
);
}
优点
- Webpack 原生支持
- 运行时动态加载
- 共享依赖优化
- 类型安全(TypeScript 支持)
缺点
- 绑定 Webpack 生态
- 配置复杂
- 版本兼容性要求高
2.4 single-spa
基础配置
javascript
// 注册微应用
import { registerApplication, start } from 'single-spa';
registerApplication({
name: 'vue-app',
app: () => import('./vue-app/main.js'),
activeWhen: (location) => location.pathname.startsWith('/vue'),
customProps: {
authToken: 'auth-token',
},
});
registerApplication({
name: 'react-app',
app: () => import('./react-app/main.js'),
activeWhen: ['/react'],
});
start();
微应用导出
javascript
// Vue 微应用
let instance = null;
export async function mount(props) {
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount('#vue-app');
}
export async function unmount() {
instance.$destroy();
instance = null;
}
优点
- 框架无关,灵活性高
- 生态成熟,插件丰富
- 轻量级,性能好
缺点
- 需要改造现有应用
- 样式隔离需要额外处理
- 学习成本相对较高
2.5 qiankun (基于 single-spa)
主应用配置
javascript
// main.js
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'vue-app',
entry: '//localhost:8081',
container: '#vue-container',
activeRule: '/vue',
props: {
data: { name: 'qiankun' },
},
},
{
name: 'react-app',
entry: {
scripts: ['//localhost:8082/static/js/bundle.js'],
styles: ['//localhost:8082/static/css/main.css'],
},
container: '#react-container',
activeRule: '/react',
},
]);
// 启动微前端
start({
sandbox: {
strictStyleIsolation: true,
experimentalStyleIsolation: true,
},
prefetch: 'all',
});
微应用改造
javascript
// Vue 微应用 main.js
let instance = null;
function render(props = {}) {
const { container } = props;
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
}
优点
- 开箱即用,配置简单
- 强大的沙箱隔离
- 完善的生态和文档
- 阿里团队维护,稳定性好
缺点
- 主要面向 React/Vue 生态
- 自定义程度不如 single-spa
- 部分高级特性学习成本较高
3. qiankun 深度使用指南
3.1 项目初始化
主应用搭建
bash
# 创建主应用
npx create-react-app main-app
cd main-app
npm install qiankun --save
javascript
// src/App.js
import React from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';
function App() {
return (
<Router>
<div className="App">
<nav>
<Link to="/vue">Vue应用</Link>
<Link to="/react">React应用</Link>
</nav>
{/* 微应用容器 */}
<div id="vue-container"></div>
<div id="react-container"></div>
</div>
</Router>
);
}
export default App;
微应用改造要点
javascript
// 1. 修改 webpack publicPath
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// 2. 导出生命周期函数
export async function bootstrap() {
// 应用启动前的准备工作
}
export async function mount(props) {
// 应用挂载
ReactDOM.render(<App />, props.container ? props.container.querySelector('#root') : document.querySelector('#root'));
}
export async function unmount(props) {
// 应用卸载
ReactDOM.unmountComponentAtNode(
props.container ? props.container.querySelector('#root') : document.querySelector('#root')
);
}
3.2 沙箱机制详解
JS 沙箱
javascript
// qiankun 提供三种沙箱模式
// 1. SnapshotSandbox - 快照沙箱(兼容模式)
// 记录和恢复 window 对象的快照
// 2. LegacySandbox - 单例沙箱
// 使用 Proxy 代理 window 对象
// 3. ProxySandbox - 多例沙箱(推荐)
// 每个微应用都有独立的 window 代理对象
// 配置沙箱
start({
sandbox: {
strictStyleIsolation: true, // 严格样式隔离
experimentalStyleIsolation: true, // 实验性样式隔离
excludeAssetFilter: (assetUrl) => {
// 排除某些资源的沙箱处理
return assetUrl === '/some-special.js';
},
},
});
样式隔离
javascript
// 1. 严格样式隔离 - Shadow DOM
start({
sandbox: {
strictStyleIsolation: true
}
});
// 2. 实验性样式隔离 - 样式作用域
start({
sandbox: {
experimentalStyleIsolation: true
}
});
// 3. 手动样式隔离
// 微应用样式添加前缀
.vue-app {
.header { color: red; }
.content { background: blue; }
}
3.3 应用通信
1. 全局状态管理
javascript
// 主应用
import { initGlobalState } from 'qiankun';
const actions = initGlobalState({
user: { name: 'qiankun' },
theme: 'light',
});
// 监听全局状态变化
actions.onGlobalStateChange((state, prev) => {
console.log('主应用监听到状态变化', state, prev);
});
// 设置全局状态
actions.setGlobalState({
user: { name: 'updated' },
});
// 微应用中
export async function mount(props) {
// 监听全局状态
props.onGlobalStateChange((state, prev) => {
console.log('微应用监听到状态变化', state, prev);
});
// 设置全局状态
props.setGlobalState({
theme: 'dark',
});
}
2. 自定义通信机制
javascript
// 发布订阅模式
class EventBus {
constructor() {
this.events = {};
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach((callback) => callback(data));
}
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter((cb) => cb !== callback);
}
}
}
// 挂载到全局
window.eventBus = new EventBus();
// 微应用中使用
window.eventBus.on('userLogin', (user) => {
console.log('用户登录', user);
});
window.eventBus.emit('userLogin', { name: 'John' });
3.4 路由配置
主应用路由
javascript
// 使用 history 模式
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
// 监听路由变化
history.listen((location) => {
console.log('路由变化', location);
});
// 手动跳转
history.push('/vue/user/123');
微应用路由
javascript
// Vue Router 配置
const router = new VueRouter({
mode: 'history',
base: window.__POWERED_BY_QIANKUN__ ? '/vue' : '/',
routes: [
{ path: '/', component: Home },
{ path: '/user/:id', component: User },
],
});
// React Router 配置
function App() {
return (
<Router basename={window.__POWERED_BY_QIANKUN__ ? '/react' : '/'}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/order/:id" element={<Order />} />
</Routes>
</Router>
);
}
3.5 资源预加载
javascript
import { prefetchApps } from 'qiankun';
// 预加载微应用
prefetchApps([
{ name: 'vue-app', entry: '//localhost:8081' },
{ name: 'react-app', entry: '//localhost:8082' },
]);
// 或者在注册时配置
start({
prefetch: 'all', // 预加载所有微应用
// prefetch: ['vue-app'], // 预加载指定微应用
// prefetch: (apps) => apps.filter(app => app.name === 'critical'), // 自定义预加载逻辑
});
3.6 错误处理
javascript
import { addErrorHandler } from 'qiankun';
// 全局错误处理
addErrorHandler((error) => {
console.error('微前端加载出错', error);
// 可以进行错误上报
errorReporting(error);
// 显示降级页面
showFallbackUI();
});
// 微应用级别错误处理
registerMicroApps([
{
name: 'vue-app',
entry: '//localhost:8081',
container: '#vue-container',
activeRule: '/vue',
loader: (loading) => {
if (loading) {
showLoading();
} else {
hideLoading();
}
},
},
]);
4. 微前端底层原理
4.1 应用加载原理
HTML Entry 解析
javascript
// qiankun 的 HTML Entry 实现原理
async function importHTML(url) {
// 1. 获取 HTML 内容
const html = await fetch(url).then((res) => res.text());
// 2. 解析 HTML,提取 script 和 link 标签
const { scripts, styles, template } = parseHTML(html);
// 3. 动态执行脚本
const execScripts = async () => {
for (const script of scripts) {
if (script.src) {
// 外部脚本
await loadScript(script.src);
} else {
// 内联脚本
eval(script.innerHTML);
}
}
};
return {
template,
execScripts,
styles,
};
}
// 解析 HTML 的简化实现
function parseHTML(html) {
const template = document.createElement('div');
template.innerHTML = html;
const scripts = Array.from(template.querySelectorAll('script'));
const styles = Array.from(template.querySelectorAll('link[rel="stylesheet"], style'));
// 移除 script 标签,避免重复执行
scripts.forEach((script) => script.remove());
return {
scripts,
styles,
template: template.innerHTML,
};
}
模块加载机制
javascript
// SystemJS 风格的模块加载
class ModuleLoader {
constructor() {
this.modules = new Map();
}
async loadModule(url) {
if (this.modules.has(url)) {
return this.modules.get(url);
}
const moduleCode = await fetch(url).then((res) => res.text());
const module = this.executeModule(moduleCode, url);
this.modules.set(url, module);
return module;
}
executeModule(code, url) {
// 创建模块作用域
const moduleScope = {
exports: {},
module: { exports: {} },
require: (id) => this.loadModule(this.resolveModule(id, url)),
};
// 包装模块代码
const wrappedCode = `
(function(exports, module, require) {
${code}
})
`;
// 执行模块
const moduleFunction = eval(wrappedCode);
moduleFunction(moduleScope.exports, moduleScope.module, moduleScope.require);
return moduleScope.module.exports;
}
}
4.2 沙箱隔离原理
Proxy 沙箱实现
javascript
class ProxySandbox {
constructor(name) {
this.name = name;
this.proxy = null;
this.running = false;
// 沙箱期间新增的全局变量
this.addedPropsMapInSandbox = new Map();
// 沙箱期间更新的全局变量
this.modifiedPropsOriginalValueMapInSandbox = new Map();
// 持续记录更新的(新增和修改的)全局变量的 map,用于在任意时刻做 snapshot
this.currentUpdatedPropsValueMap = new Map();
this.createProxy();
}
createProxy() {
const fakeWindow = Object.create(null);
this.proxy = new Proxy(fakeWindow, {
get: (target, prop) => {
if (prop === Symbol.unscopables) return undefined;
// 优先从代理对象取值
if (target.hasOwnProperty(prop)) {
return target[prop];
}
// 从原始 window 对象取值
const value = window[prop];
// 如果是函数,绑定正确的 this
if (typeof value === 'function') {
const boundTarget = value.bind(window);
return boundTarget;
}
return value;
},
set: (target, prop, value) => {
if (this.running) {
if (!target.hasOwnProperty(prop)) {
// 新增属性
this.addedPropsMapInSandbox.set(prop, value);
} else if (!this.modifiedPropsOriginalValueMapInSandbox.has(prop)) {
// 记录原始值
this.modifiedPropsOriginalValueMapInSandbox.set(prop, window[prop]);
}
this.currentUpdatedPropsValueMap.set(prop, value);
target[prop] = value;
return true;
}
// 沙箱未激活时,直接设置到 window
window[prop] = value;
return true;
},
has: (target, prop) => {
return prop in target || prop in window;
},
});
}
active() {
if (!this.running) {
this.running = true;
// 恢复沙箱环境
this.currentUpdatedPropsValueMap.forEach((value, prop) => {
this.proxy[prop] = value;
});
}
}
inactive() {
if (this.running) {
this.running = false;
// 清理新增的全局变量
this.addedPropsMapInSandbox.forEach((_, prop) => {
delete window[prop];
});
// 还原被修改的全局变量
this.modifiedPropsOriginalValueMapInSandbox.forEach((value, prop) => {
window[prop] = value;
});
}
}
}
样式隔离实现
javascript
// Shadow DOM 样式隔离
class ShadowDOMStyleIsolation {
constructor(container) {
this.container = container;
this.shadowRoot = null;
}
enable() {
// 创建 Shadow DOM
this.shadowRoot = this.container.attachShadow({ mode: 'open' });
// 将微应用内容移入 Shadow DOM
while (this.container.firstChild) {
this.shadowRoot.appendChild(this.container.firstChild);
}
}
disable() {
if (this.shadowRoot) {
// 将内容移回普通 DOM
while (this.shadowRoot.firstChild) {
this.container.appendChild(this.shadowRoot.firstChild);
}
this.shadowRoot = null;
}
}
}
// CSS Scoped 样式隔离
class ScopedStyleIsolation {
constructor(appName) {
this.appName = appName;
this.styleElements = [];
}
enable() {
// 拦截样式插入
this.hijackDynamicStyles();
// 处理已有样式
this.scopeExistingStyles();
}
hijackDynamicStyles() {
const originalAppendChild = HTMLHeadElement.prototype.appendChild;
const originalInsertBefore = HTMLHeadElement.prototype.insertBefore;
HTMLHeadElement.prototype.appendChild = function (element) {
if (element.tagName === 'STYLE' || (element.tagName === 'LINK' && element.rel === 'stylesheet')) {
return this.scopeStyle(element);
}
return originalAppendChild.call(this, element);
};
HTMLHeadElement.prototype.insertBefore = function (element, before) {
if (element.tagName === 'STYLE' || (element.tagName === 'LINK' && element.rel === 'stylesheet')) {
return this.scopeStyle(element);
}
return originalInsertBefore.call(this, element, before);
};
}
scopeStyle(styleElement) {
const prefix = `[data-qiankun="${this.appName}"]`;
if (styleElement.tagName === 'STYLE') {
const css = styleElement.innerHTML;
styleElement.innerHTML = this.scopeCSS(css, prefix);
}
this.styleElements.push(styleElement);
return styleElement;
}
scopeCSS(css, prefix) {
// 简化的 CSS 作用域处理
return css.replace(/([^{}]+){/g, (match, selector) => {
const scopedSelector = selector
.split(',')
.map((s) => `${prefix} ${s.trim()}`)
.join(', ');
return `${scopedSelector} {`;
});
}
}
4.3 生命周期管理
javascript
class MicroAppManager {
constructor() {
this.apps = new Map();
this.currentApp = null;
}
async loadApp(appConfig) {
const { name, entry, container, activeRule } = appConfig;
// 1. 加载应用资源
const { template, execScripts } = await this.importHTML(entry);
// 2. 创建沙箱
const sandbox = new ProxySandbox(name);
// 3. 创建应用实例
const app = {
name,
sandbox,
template,
execScripts,
container: typeof container === 'string' ? document.querySelector(container) : container,
activeRule,
status: 'NOT_LOADED', // NOT_LOADED -> LOADING_SOURCE_CODE -> NOT_BOOTSTRAPPED -> BOOTSTRAPPING -> NOT_MOUNTED -> MOUNTING -> MOUNTED
lifecycle: {},
};
this.apps.set(name, app);
return app;
}
async mountApp(app) {
if (app.status !== 'NOT_MOUNTED') {
return;
}
app.status = 'MOUNTING';
try {
// 1. 激活沙箱
app.sandbox.active();
// 2. 渲染模板
app.container.innerHTML = app.template;
// 3. 执行脚本,获取生命周期函数
const lifecycle = await app.execScripts();
app.lifecycle = lifecycle;
// 4. 执行 bootstrap
if (app.lifecycle.bootstrap) {
await app.lifecycle.bootstrap();
}
// 5. 执行 mount
if (app.lifecycle.mount) {
await app.lifecycle.mount({
container: app.container,
});
}
app.status = 'MOUNTED';
this.currentApp = app;
} catch (error) {
console.error(`挂载应用 ${app.name} 失败:`, error);
app.status = 'LOAD_ERROR';
}
}
async unmountApp(app) {
if (app.status !== 'MOUNTED') {
return;
}
app.status = 'UNMOUNTING';
try {
// 1. 执行 unmount
if (app.lifecycle.unmount) {
await app.lifecycle.unmount();
}
// 2. 清理 DOM
app.container.innerHTML = '';
// 3. 停用沙箱
app.sandbox.inactive();
app.status = 'NOT_MOUNTED';
if (this.currentApp === app) {
this.currentApp = null;
}
} catch (error) {
console.error(`卸载应用 ${app.name} 失败:`, error);
}
}
// 路由变化处理
onRouteChange(location) {
const targetApp = this.findMatchingApp(location);
if (targetApp !== this.currentApp) {
// 卸载当前应用
if (this.currentApp) {
this.unmountApp(this.currentApp);
}
// 挂载目标应用
if (targetApp) {
this.mountApp(targetApp);
}
}
}
findMatchingApp(location) {
for (const [name, app] of this.apps) {
if (this.isActive(app.activeRule, location)) {
return app;
}
}
return null;
}
isActive(activeRule, location) {
if (typeof activeRule === 'string') {
return location.pathname.startsWith(activeRule);
}
if (typeof activeRule === 'function') {
return activeRule(location);
}
if (Array.isArray(activeRule)) {
return activeRule.some((rule) => this.isActive(rule, location));
}
return false;
}
}
5. 实际项目应用经验
5.1 技术选型建议
选择 qiankun 的场景
- 团队主要使用 React/Vue 技术栈
- 需要快速实施微前端架构
- 对沙箱隔离要求较高
- 希望有完善的社区支持
选择 Module Federation 的场景
- 已经使用 Webpack 5
- 需要更细粒度的模块共享
- 对构建时优化有较高要求
- 团队有较强的 Webpack 配置能力
选择 single-spa 的场景
- 需要更大的灵活性和自定义能力
- 多种技术栈混合使用
- 对框架侵入性要求较低
- 有充足的开发时间
5.2 常见问题和解决方案
1. 样式冲突
css
/* 解决方案1:CSS 命名空间 */
.micro-app-user {
.header {
color: red;
}
.content {
background: blue;
}
}
/* 解决方案2:CSS-in-JS */
const styles = {
header: {
color: 'red';
}
}
/* 解决方案3:CSS Modules */
.header {
composes: global-header;
color: red;
}
2. 状态共享
javascript
// 全局状态管理
class GlobalStore {
constructor() {
this.state = {};
this.listeners = [];
}
setState(newState) {
this.state = { ...this.state, ...newState };
this.listeners.forEach((listener) => listener(this.state));
}
getState() {
return this.state;
}
subscribe(listener) {
this.listeners.push(listener);
return () => {
this.listeners = this.listeners.filter((l) => l !== listener);
};
}
}
// 挂载到全局
window.globalStore = new GlobalStore();
3. 依赖共享
javascript
// webpack externals 配置
module.exports = {
externals: {
react: 'React',
'react-dom': 'ReactDOM',
lodash: '_',
},
};
// 主应用提供共享依赖
window.React = require('react');
window.ReactDOM = require('react-dom');
window._ = require('lodash');
5.3 性能优化策略
1. 预加载优化
javascript
// 智能预加载
const prefetchStrategy = {
// 根据用户行为预测
predictive: (userBehavior) => {
const likelyApps = predictNextApps(userBehavior);
return likelyApps.slice(0, 2); // 预加载前2个最可能访问的应用
},
// 空闲时间预加载
idle: () => {
if (window.requestIdleCallback) {
window.requestIdleCallback(() => {
prefetchApps(['low-priority-app']);
});
}
},
// 网络状态感知
networkAware: () => {
if (navigator.connection) {
const { effectiveType } = navigator.connection;
if (effectiveType === '4g') {
return ['all']; // 4G 网络预加载所有应用
} else {
return ['critical-app']; // 慢网络只预加载关键应用
}
}
return [];
},
};
2. 缓存策略
javascript
// Service Worker 缓存策略
self.addEventListener('fetch', (event) => {
const { request } = event;
// 微应用资源缓存
if (request.url.includes('/micro-apps/')) {
event.respondWith(
caches.open('micro-apps-cache').then((cache) => {
return cache.match(request).then((response) => {
if (response) {
// 缓存命中,同时更新缓存
fetch(request).then((fetchResponse) => {
cache.put(request, fetchResponse.clone());
});
return response;
}
// 缓存未命中,从网络获取
return fetch(request).then((fetchResponse) => {
cache.put(request, fetchResponse.clone());
return fetchResponse;
});
});
})
);
}
});
5.4 监控和调试
1. 错误监控
javascript
// 微前端错误收集
class MicroFrontendMonitor {
constructor() {
this.errors = [];
this.performance = [];
this.init();
}
init() {
// 全局错误捕获
window.addEventListener('error', (event) => {
this.collectError({
type: 'javascript',
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
stack: event.error?.stack,
timestamp: Date.now(),
});
});
// Promise 错误捕获
window.addEventListener('unhandledrejection', (event) => {
this.collectError({
type: 'promise',
message: event.reason?.message || event.reason,
stack: event.reason?.stack,
timestamp: Date.now(),
});
});
// 微应用加载性能监控
this.monitorMicroAppPerformance();
}
collectError(error) {
this.errors.push({
...error,
userAgent: navigator.userAgent,
url: location.href,
microApp: this.getCurrentMicroApp(),
});
// 上报错误
this.reportError(error);
}
monitorMicroAppPerformance() {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.name.includes('/micro-apps/')) {
this.performance.push({
name: entry.name,
duration: entry.duration,
startTime: entry.startTime,
timestamp: Date.now(),
});
}
}
});
observer.observe({ entryTypes: ['navigation', 'resource'] });
}
getCurrentMicroApp() {
// 获取当前激活的微应用名称
return window.__CURRENT_MICRO_APP__ || 'unknown';
}
reportError(error) {
// 发送到监控平台
fetch('/api/monitor/error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(error),
}).catch(() => {
// 上报失败,存储到本地
localStorage.setItem(
'pending_errors',
JSON.stringify([...JSON.parse(localStorage.getItem('pending_errors') || '[]'), error])
);
});
}
}
// 初始化监控
new MicroFrontendMonitor();
2. 调试工具
javascript
// 微前端调试面板
class MicroFrontendDevtools {
constructor() {
this.apps = new Map();
this.createDevPanel();
}
createDevPanel() {
if (process.env.NODE_ENV !== 'development') return;
const panel = document.createElement('div');
panel.id = 'micro-frontend-devtools';
panel.style.cssText = `
position: fixed;
top: 0;
right: 0;
width: 300px;
height: 100vh;
background: #f0f0f0;
border-left: 1px solid #ccc;
z-index: 9999;
overflow-y: auto;
font-family: monospace;
font-size: 12px;
`;
document.body.appendChild(panel);
this.panel = panel;
this.updatePanel();
}
updatePanel() {
if (!this.panel) return;
const appsInfo = Array.from(this.apps.values())
.map(
(app) => `
<div style="padding: 10px; border-bottom: 1px solid #ddd;">
<h4>${app.name}</h4>
<p>状态: ${app.status}</p>
<p>路由: ${app.activeRule}</p>
<p>容器: ${app.container?.id || 'unknown'}</p>
<button onclick="window.microDevtools.toggleApp('${app.name}')">
${app.status === 'MOUNTED' ? '卸载' : '挂载'}
</button>
</div>
`
)
.join('');
this.panel.innerHTML = `
<h3 style="padding: 10px; margin: 0; background: #333; color: white;">
微前端调试面板
</h3>
${appsInfo}
`;
}
addApp(app) {
this.apps.set(app.name, app);
this.updatePanel();
}
updateAppStatus(name, status) {
const app = this.apps.get(name);
if (app) {
app.status = status;
this.updatePanel();
}
}
toggleApp(name) {
const app = this.apps.get(name);
if (app) {
if (app.status === 'MOUNTED') {
window.microAppManager.unmountApp(app);
} else {
window.microAppManager.mountApp(app);
}
}
}
}
// 全局调试工具
window.microDevtools = new MicroFrontendDevtools();
6. 面试重点总结
6.1 核心概念
- 微前端定义: 将前端应用拆分为多个独立的子应用
- 主要价值: 技术栈无关、独立开发部署、代码库隔离
- 核心挑战: 性能问题、用户体验一致性、技术复杂度
6.2 技术原理
- 应用加载: HTML Entry、模块联邦、SystemJS
- 沙箱隔离: Proxy 沙箱、快照沙箱、样式隔离
- 生命周期: bootstrap、mount、unmount
- 通信机制: 全局状态、发布订阅、props 传递
6.3 方案对比
- qiankun: 易用性高、生态完善、适合 React/Vue
- Module Federation: 构建时优化、细粒度共享、需要 Webpack 5
- single-spa: 灵活性高、框架无关、学习成本较高
- iframe: 实现简单、隔离性好、体验较差
6.4 最佳实践
- 合理的应用拆分策略
- 统一的技术规范和开发流程
- 完善的监控和错误处理机制
- 性能优化和缓存策略
6.5 常见问题
- 如何解决样式冲突?
- 如何实现应用间通信?
- 如何处理路由同步?
- 如何优化加载性能?
- 如何进行错误监控?
通过这份指南,你应该能够全面了解微前端的核心概念、技术原理和实践经验,为面试做好充分准备。