微前端之样式隔离、JS隔离、公共依赖、路由状态更新、通信方式对比
1. 样式隔离解决方案对比
样式隔离是微前端架构中的核心问题,不同框架采用了不同的技术方案来解决样式冲突。
1.1 主流隔离方案
Shadow DOM隔离
Shadow DOM提供了原生的样式隔离能力,创建完全封闭的样式作用域。
javascript
// Shadow DOM样式隔离实现
class ShadowDOMStyleIsolation {
constructor(container, appName) {
this.container = container;
this.appName = appName;
this.shadowRoot = null;
this.init();
}
init() {
// 创建Shadow DOM
this.shadowRoot = this.container.attachShadow({ mode: 'open' });
// 创建应用容器
const appContainer = document.createElement('div');
appContainer.id = `${this.appName}-root`;
this.shadowRoot.appendChild(appContainer);
}
// 注入样式到Shadow DOM
injectStyles(cssText) {
const style = document.createElement('style');
style.textContent = cssText;
this.shadowRoot.appendChild(style);
}
// 处理外部样式文件
async loadExternalStyles(styleUrls) {
const loadPromises = styleUrls.map(async (url) => {
const response = await fetch(url);
const cssText = await response.text();
this.injectStyles(cssText);
});
await Promise.all(loadPromises);
}
// 获取应用容器
getAppContainer() {
return this.shadowRoot.querySelector(`#${this.appName}-root`);
}
}
// 使用示例
const styleIsolation = new ShadowDOMStyleIsolation(
document.getElementById('app-container'),
'micro-app'
);
// 加载应用样式
await styleIsolation.loadExternalStyles([
'http://localhost:3001/static/css/main.css',
'http://localhost:3001/static/css/components.css'
]);
CSS Scoped隔离
通过添加唯一前缀或后缀来实现样式作用域隔离。
javascript
// CSS Scoped样式隔离
class ScopedStyleIsolation {
constructor(appName, scopeId) {
this.appName = appName;
this.scopeId = scopeId || `micro-app-${appName}-${Date.now()}`;
this.processedStyles = new Set();
}
// 处理CSS规则,添加作用域
processCSSRules(cssText) {
// 处理选择器,添加作用域前缀
const processedCSS = cssText.replace(
/([^{}]+)\{/g,
(match, selector) => {
// 过滤掉一些全局选择器
if (this.isGlobalSelector(selector.trim())) {
return match;
}
// 添加作用域前缀
const scopedSelector = selector
.split(',')
.map(s => `[data-micro-app="${this.scopeId}"] ${s.trim()}`)
.join(', ');
return `${scopedSelector} {`;
}
);
return processedCSS;
}
// 判断是否为全局选择器
isGlobalSelector(selector) {
const globalSelectors = [
'html', 'body', '*',
/^@/, // @media, @keyframes等
/^:root/,
/^:before/, /^:after/
];
return globalSelectors.some(pattern => {
if (typeof pattern === 'string') {
return selector === pattern;
}
return pattern.test(selector);
});
}
// 动态插入作用域样式
injectScopedStyles(cssText, containerId) {
if (this.processedStyles.has(cssText)) {
return;
}
const processedCSS = this.processCSSRules(cssText);
const styleElement = document.createElement('style');
styleElement.setAttribute('data-app', this.appName);
styleElement.textContent = processedCSS;
document.head.appendChild(styleElement);
this.processedStyles.add(cssText);
// 为容器添加作用域标识
const container = document.getElementById(containerId);
if (container) {
container.setAttribute('data-micro-app', this.scopeId);
}
}
// 清理应用样式
cleanup() {
const appStyles = document.querySelectorAll(`style[data-app="${this.appName}"]`);
appStyles.forEach(style => style.remove());
this.processedStyles.clear();
}
}
// 使用示例
const scopedIsolation = new ScopedStyleIsolation('react-app');
// 处理和注入样式
const cssContent = `
.header { background: blue; }
.content { padding: 20px; }
body { margin: 0; }
`;
scopedIsolation.injectScopedStyles(cssContent, 'react-app-container');
CSS Modules隔离
通过构建时的CSS Modules技术实现样式模块化。
javascript
// CSS Modules构建配置
const webpackConfig = {
module: {
rules: [
{
test: /\.module\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]',
// 自定义类名生成函数
getLocalIdent: (context, localIdentName, localName) => {
const appName = context.resourcePath.includes('micro-app')
? 'micro-app'
: 'main-app';
return `${appName}__${localName}__${generateHash()}`;
}
}
}
}
]
}
]
}
};
// 运行时CSS Modules处理
class CSSModulesIsolation {
constructor(appName) {
this.appName = appName;
this.moduleMap = new Map();
this.classNameGenerator = new ClassNameGenerator(appName);
}
// 处理CSS Modules
processCSSModules(cssText, modulePath) {
const classMap = {};
// 提取类名并生成映射
const processedCSS = cssText.replace(
/\.([a-zA-Z][\w-]*)/g,
(match, className) => {
const scopedName = this.classNameGenerator.generate(className, modulePath);
classMap[className] = scopedName;
return `.${scopedName}`;
}
);
this.moduleMap.set(modulePath, classMap);
return { processedCSS, classMap };
}
// 获取作用域类名
getClassName(modulePath, className) {
const classMap = this.moduleMap.get(modulePath);
return classMap ? classMap[className] : className;
}
}
// 类名生成器
class ClassNameGenerator {
constructor(appName) {
this.appName = appName;
this.counter = 0;
}
generate(className, filePath) {
const fileHash = this.generateFileHash(filePath);
const uniqueId = this.counter++;
return `${this.appName}__${className}__${fileHash}__${uniqueId}`;
}
generateFileHash(filePath) {
// 简单哈希算法
let hash = 0;
for (let i = 0; i < filePath.length; i++) {
const char = filePath.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // 转换为32位整数
}
return Math.abs(hash).toString(36).substr(0, 5);
}
}
1.2 各框架样式隔离对比
javascript
// 不同微前端框架的样式隔离对比
const styleIsolationComparison = {
'single-spa': {
method: 'Manual Scoping',
implementation: `
// 手动作用域处理
const styles = getCSSText();
const scopedStyles = addScopeToCSS(styles, appName);
injectStyles(scopedStyles);
`,
pros: ['灵活度高', '性能较好'],
cons: ['需要手动处理', '容易遗漏']
},
'qiankun': {
method: 'Dynamic Stylesheet',
implementation: `
// 动态样式表管理
sandbox.patchStrictSandbox = () => {
// 劫持样式插入
const originalAppendChild = HTMLHeadElement.prototype.appendChild;
HTMLHeadElement.prototype.appendChild = function(element) {
if (element.tagName === 'STYLE') {
element.setAttribute('data-qiankun', appName);
}
return originalAppendChild.call(this, element);
};
};
`,
pros: ['自动处理', '兼容性好'],
cons: ['运行时开销', '可能影响性能']
},
'micro-app': {
method: 'ScopedCSS + Shadow DOM',
implementation: `
// 样式作用域 + Shadow DOM
class MicroAppStyleIsolation {
processCSSText(cssText) {
return cssText.replace(/\\b([^{}]+){/g, (all, selector) => {
return \`micro-app[name="\${this.appName}"] \${selector}{\`;
});
}
}
`,
pros: ['隔离彻底', '性能较好'],
cons: ['兼容性限制', '调试困难']
},
'wujie': {
method: 'Iframe + CSS Proxy',
implementation: `
// iframe天然隔离 + CSS代理
const iframeDocument = iframe.contentDocument;
const style = iframeDocument.createElement('style');
style.textContent = cssText;
iframeDocument.head.appendChild(style);
`,
pros: ['天然隔离', '兼容性好'],
cons: ['通信复杂', '性能开销大']
},
'garfish': {
method: 'Scoped CSS + VM Sandbox',
implementation: `
// 作用域CSS + 虚拟机沙箱
const sandbox = new VMSandbox();
sandbox.execScript(\`
const originalCreateElement = document.createElement;
document.createElement = function(tagName) {
const element = originalCreateElement.call(this, tagName);
if (tagName === 'style') {
element.scoped = true;
}
return element;
};
\`);
`,
pros: ['隔离完善', '性能均衡'],
cons: ['复杂度高', '学习成本大']
}
};
1.3 样式隔离方案选择流程图
graph TD
A[开始选择样式隔离方案] --> B{是否需要完全隔离?}
B -->|是| C{浏览器支持Shadow DOM?}
B -->|否| D[CSS Scoped方案]
C -->|是| E[Shadow DOM隔离]
C -->|否| F{构建时处理?}
F -->|是| G[CSS Modules]
F -->|否| H[动态作用域]
D --> I[添加唯一前缀]
E --> J[创建Shadow Root]
G --> K[构建时类名转换]
H --> L[运行时样式处理]
I --> M[样式隔离完成]
J --> M
K --> M
L --> M
style E fill:#e8f5e8
style G fill:#e3f2fd
style H fill:#fff3e0
style D fill:#fce4ec
2. JS隔离解决方案对比
JavaScript隔离确保不同微应用之间的全局变量、原型链、事件监听器等不会相互干扰。
2.1 沙箱隔离技术
Proxy沙箱
基于ES6 Proxy实现的JavaScript沙箱隔离。
javascript
// Proxy沙箱实现
class ProxySandbox {
constructor(appName) {
this.appName = appName;
this.isRunning = false;
this.modifiedPropsMap = new Map();
this.addedPropsMap = new Map();
this.currentUpdatedPropsValueMap = new Map();
// 创建代理对象
this.proxyWindow = this.createProxyWindow();
}
createProxyWindow() {
const rawWindow = window;
const fakeWindow = Object.create(null);
return new Proxy(fakeWindow, {
set: (target, property, value, receiver) => {
if (this.isRunning) {
// 记录属性变更
if (!rawWindow.hasOwnProperty(property)) {
this.addedPropsMap.set(property, value);
} else if (!this.modifiedPropsMap.has(property)) {
this.modifiedPropsMap.set(property, rawWindow[property]);
}
this.currentUpdatedPropsValueMap.set(property, value);
// 设置到目标对象
target[property] = value;
return true;
}
console.warn(`[${this.appName}] 沙箱未激活,无法设置属性 ${property}`);
return true;
},
get: (target, property, receiver) => {
// 优先从代理对象获取
if (target.hasOwnProperty(property)) {
return target[property];
}
// 从原始window获取
const rawValue = rawWindow[property];
// 绑定函数上下文
if (typeof rawValue === 'function' && !this.isConstructor(rawValue)) {
return rawValue.bind(rawWindow);
}
return rawValue;
},
has: (target, property) => {
return property in target || property in rawWindow;
},
ownKeys: (target) => {
return [...Reflect.ownKeys(rawWindow), ...Reflect.ownKeys(target)];
}
});
}
// 判断是否为构造函数
isConstructor(fn) {
const functionStr = fn.toString();
return /^class\s/.test(functionStr) || /^function\s+[A-Z]/.test(functionStr);
}
// 激活沙箱
active() {
if (!this.isRunning) {
this.isRunning = true;
// 恢复之前的状态
this.currentUpdatedPropsValueMap.forEach((value, property) => {
this.proxyWindow[property] = value;
});
console.log(`[${this.appName}] 沙箱已激活`);
}
}
// 失活沙箱
inactive() {
if (this.isRunning) {
this.isRunning = false;
// 清理添加的属性
this.addedPropsMap.forEach((_, property) => {
delete window[property];
});
// 恢复修改的属性
this.modifiedPropsMap.forEach((originalValue, property) => {
window[property] = originalValue;
});
console.log(`[${this.appName}] 沙箱已失活`);
}
}
// 执行代码
execScript(script) {
if (!this.isRunning) {
console.warn(`[${this.appName}] 沙箱未激活,无法执行脚本`);
return;
}
try {
// 创建执行上下文
const execFunction = new Function('window', 'self', 'globalThis', script);
return execFunction(this.proxyWindow, this.proxyWindow, this.proxyWindow);
} catch (error) {
console.error(`[${this.appName}] 脚本执行失败:`, error);
throw error;
}
}
}
// 使用示例
const sandbox = new ProxySandbox('micro-app');
sandbox.active();
// 执行子应用代码
sandbox.execScript(`
window.myAppData = { name: 'micro-app' };
console.log('子应用初始化完成');
// 不会污染全局window
window.setTimeout = function() {
console.log('自定义setTimeout');
};
`);
sandbox.inactive();
快照沙箱
通过记录和恢复全局状态快照实现隔离。
javascript
// 快照沙箱实现
class SnapshotSandbox {
constructor(appName) {
this.appName = appName;
this.isRunning = false;
this.windowSnapshot = {};
this.modifyPropsMap = {};
}
// 激活沙箱
active() {
if (this.isRunning) return;
// 记录当前window状态快照
this.windowSnapshot = {};
for (const prop in window) {
this.windowSnapshot[prop] = window[prop];
}
// 恢复之前的修改
Object.keys(this.modifyPropsMap).forEach(property => {
window[property] = this.modifyPropsMap[property];
});
this.isRunning = true;
console.log(`[${this.appName}] 快照沙箱已激活`);
}
// 失活沙箱
inactive() {
if (!this.isRunning) return;
// 记录修改的属性
this.modifyPropsMap = {};
for (const prop in window) {
if (window[prop] !== this.windowSnapshot[prop]) {
this.modifyPropsMap[prop] = window[prop];
// 恢复原始值
window[prop] = this.windowSnapshot[prop];
}
}
// 清理新增的属性
for (const prop in window) {
if (!(prop in this.windowSnapshot)) {
delete window[prop];
}
}
this.isRunning = false;
console.log(`[${this.appName}] 快照沙箱已失活`);
}
// 执行脚本
execScript(script) {
if (!this.isRunning) {
console.warn(`[${this.appName}] 沙箱未激活`);
return;
}
try {
// 直接在全局作用域执行
(0, eval)(script);
} catch (error) {
console.error(`[${this.appName}] 脚本执行失败:`, error);
throw error;
}
}
}
// 使用示例
const snapshotSandbox = new SnapshotSandbox('legacy-app');
snapshotSandbox.active();
snapshotSandbox.execScript(`
window.legacyData = { version: '1.0' };
var globalVar = 'legacy app variable';
`);
snapshotSandbox.inactive();
iframe沙箱
利用iframe的天然隔离特性实现完全的JavaScript隔离。
javascript
// iframe沙箱实现
class IframeSandbox {
constructor(appName, container) {
this.appName = appName;
this.container = container;
this.iframe = null;
this.iframeWindow = null;
this.communicationBridge = null;
this.init();
}
init() {
// 创建iframe
this.iframe = document.createElement('iframe');
this.iframe.style.cssText = `
width: 100%;
height: 100%;
border: none;
`;
// 设置iframe src为空白页面
this.iframe.src = 'about:blank';
this.container.appendChild(this.iframe);
this.iframeWindow = this.iframe.contentWindow;
// 建立通信桥梁
this.setupCommunicationBridge();
// 初始化iframe环境
this.setupIframeEnvironment();
}
// 设置iframe环境
setupIframeEnvironment() {
const iframeDoc = this.iframe.contentDocument;
// 写入基础HTML结构
iframeDoc.open();
iframeDoc.write(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>${this.appName}</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
`);
iframeDoc.close();
// 同步主应用的基础能力
this.syncMainAppCapabilities();
}
// 同步主应用能力
syncMainAppCapabilities() {
const iframeWindow = this.iframeWindow;
// 同步fetch
iframeWindow.fetch = window.fetch.bind(window);
// 同步XMLHttpRequest
iframeWindow.XMLHttpRequest = window.XMLHttpRequest;
// 同步localStorage(可选)
Object.defineProperty(iframeWindow, 'localStorage', {
get: () => window.localStorage,
configurable: true
});
// 同步sessionStorage(可选)
Object.defineProperty(iframeWindow, 'sessionStorage', {
get: () => window.sessionStorage,
configurable: true
});
// 代理console
iframeWindow.console = new Proxy(window.console, {
get: (target, property) => {
const method = target[property];
if (typeof method === 'function') {
return method.bind(target);
}
return method;
}
});
}
// 建立通信桥梁
setupCommunicationBridge() {
this.communicationBridge = {
// 向iframe发送消息
postMessage: (data) => {
this.iframeWindow.postMessage({
type: 'main-to-iframe',
data,
appName: this.appName
}, '*');
},
// 监听iframe消息
onMessage: (callback) => {
window.addEventListener('message', (event) => {
if (event.source === this.iframeWindow &&
event.data.type === 'iframe-to-main' &&
event.data.appName === this.appName) {
callback(event.data.data);
}
});
}
};
// 在iframe中设置通信代理
this.iframeWindow.addEventListener('load', () => {
this.execScript(`
window.parent.postMessage = function(data) {
parent.postMessage({
type: 'iframe-to-main',
data: data,
appName: '${this.appName}'
}, '*');
};
window.addEventListener('message', function(event) {
if (event.data.type === 'main-to-iframe' &&
event.data.appName === '${this.appName}') {
// 触发iframe内的消息处理
window.dispatchEvent(new CustomEvent('mainMessage', {
detail: event.data.data
}));
}
});
`);
});
}
// 在iframe中执行脚本
execScript(script) {
try {
const scriptElement = this.iframe.contentDocument.createElement('script');
scriptElement.textContent = script;
this.iframe.contentDocument.head.appendChild(scriptElement);
} catch (error) {
console.error(`[${this.appName}] iframe脚本执行失败:`, error);
throw error;
}
}
// 加载外部脚本
async loadScript(src) {
return new Promise((resolve, reject) => {
const script = this.iframe.contentDocument.createElement('script');
script.src = src;
script.onload = resolve;
script.onerror = reject;
this.iframe.contentDocument.head.appendChild(script);
});
}
// 销毁沙箱
destroy() {
if (this.iframe && this.iframe.parentNode) {
this.iframe.parentNode.removeChild(this.iframe);
}
this.iframe = null;
this.iframeWindow = null;
this.communicationBridge = null;
}
}
// 使用示例
const iframeSandbox = new IframeSandbox('isolated-app', document.getElementById('app-container'));
// 加载应用脚本
await iframeSandbox.loadScript('http://localhost:3001/static/js/app.js');
// 执行初始化代码
iframeSandbox.execScript(`
// 在完全隔离的iframe环境中执行
window.myAppConfig = { isolated: true };
console.log('iframe应用初始化完成');
`);
// 建立通信
iframeSandbox.communicationBridge.onMessage((data) => {
console.log('收到iframe消息:', data);
});
iframeSandbox.communicationBridge.postMessage({
type: 'init',
config: { theme: 'dark' }
});
2.2 各框架JS隔离对比
javascript
// JS隔离方案对比表
const jsIsolationComparison = {
frameworks: {
'single-spa': {
isolation: 'None',
description: '无隔离,依赖应用自身管理',
implementation: '手动命名空间管理',
performance: '★★★★★',
compatibility: '★★★★★',
security: '★★☆☆☆'
},
'qiankun': {
isolation: 'Proxy Sandbox',
description: '基于Proxy的多实例沙箱',
implementation: `
// Proxy沙箱核心实现
const sandbox = new ProxySandbox(appName);
sandbox.active();
execScript(code, sandbox.proxy);
sandbox.inactive();
`,
performance: '★★★★☆',
compatibility: '★★★★☆',
security: '★★★★☆'
},
'micro-app': {
isolation: 'with + Proxy',
description: 'with语句 + Proxy劫持',
implementation: `
// with + Proxy实现
const sandbox = new Proxy(window, {
get: (target, key) => {
return key in appScope ? appScope[key] : target[key];
},
set: (target, key, value) => {
appScope[key] = value;
return true;
}
});
with(sandbox) { eval(code); }
`,
performance: '★★★☆☆',
compatibility: '★★★☆☆',
security: '★★★☆☆'
},
'wujie': {
isolation: 'Iframe Sandbox',
description: 'iframe天然隔离',
implementation: `
// iframe沙箱
const iframe = document.createElement('iframe');
iframe.src = 'about:blank';
const iframeWindow = iframe.contentWindow;
iframeWindow.eval(code);
`,
performance: '★★★☆☆',
compatibility: '★★★★★',
security: '★★★★★'
},
'garfish': {
isolation: 'VM Sandbox',
description: '虚拟机沙箱隔离',
implementation: `
// VM沙箱实现
const vm = new VMSandbox({
globalContext: createFakeWindow(),
strictMode: true
});
vm.execScript(code);
`,
performance: '★★★★☆',
compatibility: '★★★★☆',
security: '★★★★☆'
}
}
};
// 性能对比测试
class JSIsolationPerformanceTest {
constructor() {
this.testResults = {};
}
// 测试沙箱创建性能
async testSandboxCreation(SandboxClass, iterations = 1000) {
const startTime = performance.now();
for (let i = 0; i < iterations; i++) {
const sandbox = new SandboxClass(`test-app-${i}`);
sandbox.active && sandbox.active();
sandbox.inactive && sandbox.inactive();
}
const endTime = performance.now();
return endTime - startTime;
}
// 测试脚本执行性能
async testScriptExecution(sandbox, script, iterations = 100) {
const startTime = performance.now();
for (let i = 0; i < iterations; i++) {
sandbox.execScript(script);
}
const endTime = performance.now();
return endTime - startTime;
}
// 运行完整性能测试
async runFullTest() {
const testScript = `
window.testVar = Math.random();
for (let i = 0; i < 1000; i++) {
window['prop' + i] = i;
}
`;
// 测试Proxy沙箱
const proxyTime = await this.testSandboxCreation(ProxySandbox);
console.log('Proxy沙箱创建时间:', proxyTime + 'ms');
// 测试快照沙箱
const snapshotTime = await this.testSandboxCreation(SnapshotSandbox);
console.log('快照沙箱创建时间:', snapshotTime + 'ms');
return {
proxy: proxyTime,
snapshot: snapshotTime
};
}
}
2.3 JS隔离技术选择流程图
graph TD
A[开始选择JS隔离方案] --> B{性能要求}
B -->|高性能| C{兼容性要求}
B -->|一般| D{安全要求}
C -->|现代浏览器| E[Proxy沙箱]
C -->|兼容IE| F[快照沙箱]
D -->|高安全| G[iframe沙箱]
D -->|一般| H{代码复杂度}
H -->|简单| I[with + Proxy]
H -->|复杂| J[VM沙箱]
E --> K[实现Proxy代理]
F --> L[记录全局状态快照]
G --> M[创建iframe隔离]
I --> N[with语句劫持]
J --> O[虚拟机执行]
K --> P[JS隔离完成]
L --> P
M --> P
N --> P
O --> P
style E fill:#e8f5e8
style G fill:#e3f2fd
style J fill:#fff3e0
style F fill:#fce4ec
3. 公共依赖管理方案对比
公共依赖管理是微前端架构中提升性能和减少重复加载的关键技术。
3.1 依赖共享策略
模块联邦(Module Federation)
Webpack 5的模块联邦提供了运行时的依赖共享能力。
javascript
// 主应用的webpack配置
const ModuleFederationPlugin = require('@module-federation/webpack');
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'main_app',
remotes: {
micro_app_1: 'micro_app_1@http://localhost:3001/remoteEntry.js',
micro_app_2: 'micro_app_2@http://localhost:3002/remoteEntry.js'
},
shared: {
react: {
singleton: true,
requiredVersion: '^18.2.0',
eager: true
},
'react-dom': {
singleton: true,
requiredVersion: '^18.2.0',
eager: true
},
'react-router-dom': {
singleton: true,
version: '^6.0.0'
},
lodash: {
singleton: false,
version: '^4.17.21'
}
}
})
]
};
// 微应用的webpack配置
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'micro_app_1',
filename: 'remoteEntry.js',
exposes: {
'./App': './src/App',
'./utils': './src/utils'
},
shared: {
react: {
singleton: true,
requiredVersion: '^18.2.0'
},
'react-dom': {
singleton: true,
requiredVersion: '^18.2.0'
}
}
})
]
};
// 运行时动态加载管理
class ModuleFederationManager {
constructor() {
this.loadedRemotes = new Map();
this.sharedModules = new Map();
this.loadingPromises = new Map();
}
// 动态加载远程模块
async loadRemoteModule(remoteName, moduleName) {
const remoteKey = `${remoteName}/${moduleName}`;
if (this.loadedRemotes.has(remoteKey)) {
return this.loadedRemotes.get(remoteKey);
}
if (this.loadingPromises.has(remoteKey)) {
return this.loadingPromises.get(remoteKey);
}
const loadingPromise = this.performRemoteLoad(remoteName, moduleName);
this.loadingPromises.set(remoteKey, loadingPromise);
try {
const module = await loadingPromise;
this.loadedRemotes.set(remoteKey, module);
return module;
} finally {
this.loadingPromises.delete(remoteKey);
}
}
async performRemoteLoad(remoteName, moduleName) {
try {
// 动态导入远程模块
const container = window[remoteName];
if (!container) {
throw new Error(`Remote container ${remoteName} not found`);
}
// 初始化容器
await container.init(__webpack_share_scopes__.default);
// 获取模块工厂
const factory = await container.get(moduleName);
// 执行模块
const module = factory();
return module;
} catch (error) {
console.error(`Failed to load remote module ${remoteName}/${moduleName}:`, error);
throw error;
}
}
// 注册共享模块
registerSharedModule(name, module, version) {
this.sharedModules.set(name, {
module,
version,
timestamp: Date.now()
});
}
// 获取共享模块
getSharedModule(name, requiredVersion) {
const shared = this.sharedModules.get(name);
if (!shared) {
return null;
}
// 版本兼容性检查
if (requiredVersion && !this.isVersionCompatible(shared.version, requiredVersion)) {
console.warn(`Version mismatch for ${name}: required ${requiredVersion}, got ${shared.version}`);
return null;
}
return shared.module;
}
// 版本兼容性检查
isVersionCompatible(currentVersion, requiredVersion) {
// 简单的语义版本检查
const parseVersion = (version) => {
const cleaned = version.replace(/[^\d.]/g, '');
return cleaned.split('.').map(num => parseInt(num, 10));
};
const current = parseVersion(currentVersion);
const required = parseVersion(requiredVersion);
// 主版本号必须匹配
return current[0] === required[0];
}
}
// 使用示例
const federationManager = new ModuleFederationManager();
// 加载远程组件
async function loadMicroApp() {
try {
const MicroApp = await federationManager.loadRemoteModule('micro_app_1', './App');
// 渲染组件
const element = React.createElement(MicroApp.default);
ReactDOM.render(element, document.getElementById('micro-app-container'));
} catch (error) {
console.error('Failed to load micro app:', error);
}
}
SystemJS依赖管理
基于SystemJS的运行时依赖管理和模块加载。
javascript
// SystemJS依赖管理器
class SystemJSDependencyManager {
constructor() {
this.sharedDependencies = new Map();
this.moduleCache = new Map();
this.importMap = new Map();
this.init();
}
init() {
// 配置SystemJS
System.config({
map: {
'react': '/shared/react@18.2.0/index.js',
'react-dom': '/shared/react-dom@18.2.0/index.js',
'lodash': '/shared/lodash@4.17.21/lodash.min.js',
'axios': '/shared/axios@1.3.0/dist/axios.min.js'
}
});
// 预加载共享依赖
this.preloadSharedDependencies();
}
// 预加载共享依赖
async preloadSharedDependencies() {
const sharedDeps = [
{ name: 'react', version: '18.2.0' },
{ name: 'react-dom', version: '18.2.0' },
{ name: 'lodash', version: '4.17.21' }
];
const loadPromises = sharedDeps.map(dep => this.loadSharedDependency(dep));
try {
await Promise.all(loadPromises);
console.log('共享依赖预加载完成');
} catch (error) {
console.error('共享依赖预加载失败:', error);
}
}
// 加载共享依赖
async loadSharedDependency({ name, version }) {
const cacheKey = `${name}@${version}`;
if (this.sharedDependencies.has(cacheKey)) {
return this.sharedDependencies.get(cacheKey);
}
try {
const module = await System.import(name);
this.sharedDependencies.set(cacheKey, {
module,
version,
loadTime: Date.now()
});
console.log(`共享依赖加载成功: ${cacheKey}`);
return module;
} catch (error) {
console.error(`共享依赖加载失败: ${cacheKey}`, error);
throw error;
}
}
// 动态导入模块
async importModule(modulePath, dependencies = []) {
// 确保依赖已加载
await this.ensureDependencies(dependencies);
try {
const module = await System.import(modulePath);
// 缓存模块
this.moduleCache.set(modulePath, module);
return module;
} catch (error) {
console.error(`模块导入失败: ${modulePath}`, error);
throw error;
}
}
// 确保依赖已加载
async ensureDependencies(dependencies) {
const loadPromises = dependencies.map(dep => {
if (typeof dep === 'string') {
return this.loadSharedDependency({ name: dep, version: 'latest' });
}
return this.loadSharedDependency(dep);
});
await Promise.all(loadPromises);
}
// 获取依赖统计信息
getDependencyStats() {
const stats = {
totalShared: this.sharedDependencies.size,
totalCached: this.moduleCache.size,
sharedDetails: [],
memoryUsage: 0
};
this.sharedDependencies.forEach((dep, key) => {
stats.sharedDetails.push({
name: key,
version: dep.version,
loadTime: dep.loadTime,
size: this.estimateModuleSize(dep.module)
});
});
return stats;
}
// 估算模块大小
estimateModuleSize(module) {
try {
return JSON.stringify(module).length;
} catch {
return 0;
}
}
// 清理无用模块
cleanup() {
const now = Date.now();
const maxAge = 30 * 60 * 1000; // 30分钟
this.sharedDependencies.forEach((dep, key) => {
if (now - dep.loadTime > maxAge) {
this.sharedDependencies.delete(key);
console.log(`清理过期依赖: ${key}`);
}
});
}
}
// 使用示例
const dependencyManager = new SystemJSDependencyManager();
// 加载微应用
async function loadMicroAppWithDependencies() {
try {
// 确保React相关依赖已加载
await dependencyManager.ensureDependencies([
{ name: 'react', version: '18.2.0' },
{ name: 'react-dom', version: '18.2.0' }
]);
// 导入微应用模块
const MicroApp = await dependencyManager.importModule(
'http://localhost:3001/micro-app.js',
['react', 'react-dom']
);
// 渲染微应用
MicroApp.render('#micro-app-container');
} catch (error) {
console.error('微应用加载失败:', error);
}
}
// 定期清理
setInterval(() => {
dependencyManager.cleanup();
}, 10 * 60 * 1000); // 每10分钟清理一次
外部化依赖(Externals)
通过Webpack externals配置实现依赖外部化。
javascript
// 外部化依赖管理
class ExternalDependencyManager {
constructor() {
this.externalLibs = new Map();
this.cdnBaseUrl = 'https://cdn.jsdelivr.net/npm/';
this.localLibs = new Map();
this.init();
}
init() {
// 配置外部化库
this.registerExternalLib('react', {
version: '18.2.0',
global: 'React',
cdn: `${this.cdnBaseUrl}react@18.2.0/umd/react.production.min.js`,
local: '/libs/react.min.js'
});
this.registerExternalLib('react-dom', {
version: '18.2.0',
global: 'ReactDOM',
cdn: `${this.cdnBaseUrl}react-dom@18.2.0/umd/react-dom.production.min.js`,
local: '/libs/react-dom.min.js',
dependencies: ['react']
});
this.registerExternalLib('lodash', {
version: '4.17.21',
global: '_',
cdn: `${this.cdnBaseUrl}lodash@4.17.21/lodash.min.js`,
local: '/libs/lodash.min.js'
});
}
// 注册外部化库
registerExternalLib(name, config) {
this.externalLibs.set(name, {
...config,
loaded: false,
loading: false
});
}
// 加载外部化依赖
async loadExternalDependency(name, useLocal = false) {
const libConfig = this.externalLibs.get(name);
if (!libConfig) {
throw new Error(`未知的外部依赖: ${name}`);
}
if (libConfig.loaded) {
return window[libConfig.global];
}
if (libConfig.loading) {
// 等待加载完成
return new Promise((resolve) => {
const checkLoaded = () => {
if (libConfig.loaded) {
resolve(window[libConfig.global]);
} else {
setTimeout(checkLoaded, 100);
}
};
checkLoaded();
});
}
libConfig.loading = true;
try {
// 先加载依赖
if (libConfig.dependencies) {
await Promise.all(
libConfig.dependencies.map(dep => this.loadExternalDependency(dep, useLocal))
);
}
// 加载主库
const url = useLocal ? libConfig.local : libConfig.cdn;
await this.loadScript(url);
// 验证全局变量
if (!window[libConfig.global]) {
throw new Error(`全局变量 ${libConfig.global} 未找到`);
}
libConfig.loaded = true;
libConfig.loading = false;
console.log(`外部依赖加载成功: ${name}`);
return window[libConfig.global];
} catch (error) {
libConfig.loading = false;
console.error(`外部依赖加载失败: ${name}`, error);
throw error;
}
}
// 加载脚本
loadScript(src) {
return new Promise((resolve, reject) => {
// 检查是否已经加载
const existingScript = document.querySelector(`script[src="${src}"]`);
if (existingScript) {
resolve();
return;
}
const script = document.createElement('script');
script.src = src;
script.async = true;
script.onload = () => {
console.log(`脚本加载成功: ${src}`);
resolve();
};
script.onerror = () => {
console.error(`脚本加载失败: ${src}`);
reject(new Error(`Failed to load script: ${src}`));
};
document.head.appendChild(script);
});
}
// 批量加载依赖
async loadDependencies(dependencies) {
const loadPromises = dependencies.map(dep => {
const config = typeof dep === 'string' ? { name: dep } : dep;
return this.loadExternalDependency(config.name, config.useLocal);
});
return Promise.all(loadPromises);
}
// 获取Webpack externals配置
getWebpackExternals() {
const externals = {};
this.externalLibs.forEach((config, name) => {
externals[name] = config.global;
});
return externals;
}
// 生成HTML模板中的依赖标签
generateDependencyTags(dependencies, useLocal = false) {
const tags = [];
const processed = new Set();
const addDependency = (name) => {
if (processed.has(name)) return;
const config = this.externalLibs.get(name);
if (!config) return;
// 先添加依赖的依赖
if (config.dependencies) {
config.dependencies.forEach(addDependency);
}
const src = useLocal ? config.local : config.cdn;
tags.push(`<script src="${src}"></script>`);
processed.add(name);
};
dependencies.forEach(addDependency);
return tags.join('\n');
}
// 依赖分析
analyzeDependencies() {
const analysis = {
total: this.externalLibs.size,
loaded: 0,
failed: 0,
dependencies: []
};
this.externalLibs.forEach((config, name) => {
const depInfo = {
name,
version: config.version,
global: config.global,
loaded: config.loaded,
size: 0,
dependencies: config.dependencies || []
};
if (config.loaded) {
analysis.loaded++;
depInfo.size = this.estimateLibSize(window[config.global]);
}
analysis.dependencies.push(depInfo);
});
return analysis;
}
// 估算库大小
estimateLibSize(lib) {
if (!lib) return 0;
try {
// 简单的大小估算
const keys = Object.keys(lib);
return keys.length * 100; // 粗略估算
} catch {
return 0;
}
}
}
// Webpack配置生成
function generateWebpackConfig(dependencyManager) {
return {
externals: dependencyManager.getWebpackExternals(),
plugins: [
new (class DependencyInjectionPlugin {
apply(compiler) {
compiler.hooks.compilation.tap('DependencyInjectionPlugin', (compilation) => {
compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration.tapAsync(
'DependencyInjectionPlugin',
(data, cb) => {
const dependencies = ['react', 'react-dom', 'lodash'];
const dependencyTags = dependencyManager.generateDependencyTags(dependencies);
data.assets.js.unshift(...dependencyTags.split('\n'));
cb(null, data);
}
);
});
}
})()
]
};
}
// 使用示例
const externalManager = new ExternalDependencyManager();
// 在应用启动前加载依赖
async function initializeApp() {
try {
await externalManager.loadDependencies(['react', 'react-dom']);
// 现在可以安全使用React
const { createElement } = window.React;
const { render } = window.ReactDOM;
const app = createElement('div', null, 'Hello from external React!');
render(app, document.getElementById('root'));
} catch (error) {
console.error('应用初始化失败:', error);
}
}
3.2 依赖管理方案对比
javascript
// 依赖管理方案对比
const dependencyManagementComparison = {
'Module Federation': {
description: 'Webpack 5原生模块联邦',
advantages: [
'运行时共享',
'版本协商',
'类型安全',
'构建时优化'
],
disadvantages: [
'仅支持Webpack 5',
'配置复杂',
'学习成本高'
],
implementation: `
// 主应用配置
new ModuleFederationPlugin({
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
`,
performance: '★★★★☆',
complexity: '★★★★☆',
compatibility: '★★★☆☆'
},
'SystemJS': {
description: '动态模块加载器',
advantages: [
'运行时加载',
'框架无关',
'灵活配置',
'良好兼容性'
],
disadvantages: [
'运行时开销',
'调试困难',
'类型推断差'
],
implementation: `
System.config({
map: {
'react': '/shared/react.js'
}
});
await System.import('react');
`,
performance: '★★★☆☆',
complexity: '★★★☆☆',
compatibility: '★★★★★'
},
'Externals': {
description: 'Webpack外部化依赖',
advantages: [
'简单配置',
'CDN支持',
'缓存友好',
'体积优化'
],
disadvantages: [
'版本管理复杂',
'运行时风险',
'依赖顺序'
],
implementation: `
// webpack.config.js
module.exports = {
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
};
`,
performance: '★★★★★',
complexity: '★★☆☆☆',
compatibility: '★★★★☆'
},
'UMD Bundle': {
description: 'UMD格式依赖包',
advantages: [
'通用格式',
'简单使用',
'良好兼容',
'调试友好'
],
disadvantages: [
'体积较大',
'版本冲突',
'重复加载'
],
implementation: `
// 直接引入UMD包
<script src="/libs/react.umd.js"></script>
<script src="/libs/react-dom.umd.js"></script>
`,
performance: '★★★☆☆',
complexity: '★★☆☆☆',
compatibility: '★★★★★'
}
};
3.3 依赖管理最佳实践
javascript
// 依赖管理最佳实践实现
class BestPracticeDependencyManager {
constructor() {
this.dependencyStrategy = this.determineBestStrategy();
this.manager = this.createManager();
this.monitor = new DependencyMonitor();
}
// 确定最佳策略
determineBestStrategy() {
const environment = {
webpackVersion: this.getWebpackVersion(),
browserSupport: this.getBrowserSupport(),
projectComplexity: this.getProjectComplexity(),
performanceRequirement: this.getPerformanceRequirement()
};
// 策略选择逻辑
if (environment.webpackVersion >= 5 && environment.projectComplexity === 'high') {
return 'module-federation';
} else if (environment.performanceRequirement === 'high') {
return 'externals';
} else if (environment.browserSupport === 'legacy') {
return 'systemjs';
} else {
return 'hybrid'; // 混合策略
}
}
// 创建对应的管理器
createManager() {
switch (this.dependencyStrategy) {
case 'module-federation':
return new ModuleFederationManager();
case 'externals':
return new ExternalDependencyManager();
case 'systemjs':
return new SystemJSDependencyManager();
case 'hybrid':
return new HybridDependencyManager();
default:
throw new Error(`Unsupported strategy: ${this.dependencyStrategy}`);
}
}
// 统一的依赖加载接口
async loadDependencies(dependencies) {
const startTime = performance.now();
try {
const result = await this.manager.loadDependencies(dependencies);
// 记录性能指标
const loadTime = performance.now() - startTime;
this.monitor.recordLoad(dependencies, loadTime, true);
return result;
} catch (error) {
const loadTime = performance.now() - startTime;
this.monitor.recordLoad(dependencies, loadTime, false);
throw error;
}
}
// 获取依赖分析报告
getDependencyReport() {
return {
strategy: this.dependencyStrategy,
metrics: this.monitor.getMetrics(),
recommendations: this.generateRecommendations()
};
}
generateRecommendations() {
const metrics = this.monitor.getMetrics();
const recommendations = [];
if (metrics.averageLoadTime > 2000) {
recommendations.push('考虑使用CDN加速依赖加载');
}
if (metrics.failureRate > 0.1) {
recommendations.push('检查依赖的可用性和版本兼容性');
}
if (metrics.duplicateLoads > 5) {
recommendations.push('优化依赖加载策略,减少重复加载');
}
return recommendations;
}
}
// 依赖监控器
class DependencyMonitor {
constructor() {
this.loadHistory = [];
this.metrics = {
totalLoads: 0,
successfulLoads: 0,
failedLoads: 0,
totalLoadTime: 0,
duplicateLoads: 0
};
}
recordLoad(dependencies, loadTime, success) {
const record = {
dependencies,
loadTime,
success,
timestamp: Date.now()
};
this.loadHistory.push(record);
this.updateMetrics(record);
}
updateMetrics(record) {
this.metrics.totalLoads++;
this.metrics.totalLoadTime += record.loadTime;
if (record.success) {
this.metrics.successfulLoads++;
} else {
this.metrics.failedLoads++;
}
// 检测重复加载
const similarLoads = this.loadHistory.filter(h =>
h !== record &&
JSON.stringify(h.dependencies) === JSON.stringify(record.dependencies) &&
Math.abs(h.timestamp - record.timestamp) < 60000 // 1分钟内
);
if (similarLoads.length > 0) {
this.metrics.duplicateLoads++;
}
}
getMetrics() {
return {
...this.metrics,
averageLoadTime: this.metrics.totalLoadTime / this.metrics.totalLoads,
successRate: this.metrics.successfulLoads / this.metrics.totalLoads,
failureRate: this.metrics.failedLoads / this.metrics.totalLoads
};
}
}
3.4 依赖管理流程图
graph TD
A[开始依赖管理] --> B[分析项目需求]
B --> C{Webpack版本}
C -->|5.x| D{项目复杂度}
C -->|4.x及以下| E{性能要求}
D -->|高| F[Module Federation]
D -->|中低| G{兼容性需求}
E -->|高| H[Externals方案]
E -->|一般| I[SystemJS方案]
G -->|现代浏览器| J[ES Modules]
G -->|兼容IE| K[UMD方案]
F --> L[配置模块联邦]
H --> M[配置外部化依赖]
I --> N[配置SystemJS]
J --> O[配置ES模块]
K --> P[配置UMD包]
L --> Q[依赖版本协商]
M --> R[CDN资源管理]
N --> S[动态模块加载]
O --> T[原生模块导入]
P --> U[全局变量管理]
Q --> V[依赖管理完成]
R --> V
S --> V
T --> V
U --> V
style F fill:#e8f5e8
style H fill:#e3f2fd
style I fill:#fff3e0
style J fill:#f3e5f5
style K fill:#fce4ec
4. 路由状态更新机制对比
路由状态同步是微前端架构中确保用户体验一致性的关键环节。
4.1 路由同步策略
主从路由模式
主应用控制整体路由,子应用遵循主应用的路由规则。
javascript
// 主从路由管理器
class MasterSlaveRouterManager {
constructor() {
this.masterRouter = null;
this.slaveRouters = new Map();
this.routeListeners = new Set();
this.currentRoute = null;
this.routeHistory = [];
this.init();
}
init() {
// 监听浏览器路由变化
window.addEventListener('popstate', this.handlePopState.bind(this));
window.addEventListener('pushstate', this.handlePushState.bind(this));
window.addEventListener('replacestate', this.handleReplaceState.bind(this));
// 劫持原生路由方法
this.hijackNativeRouter();
}
// 劫持原生路由方法
hijackNativeRouter() {
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = (...args) => {
originalPushState.apply(history, args);
this.handleRouteChange('push', args[2]);
};
history.replaceState = (...args) => {
originalReplaceState.apply(history, args);
this.handleRouteChange('replace', args[2]);
};
}
// 注册主路由器
registerMasterRouter(router) {
this.masterRouter = router;
console.log('主路由器已注册');
}
// 注册从路由器
registerSlaveRouter(appName, router) {
this.slaveRouters.set(appName, {
router,
active: false,
basePath: this.getAppBasePath(appName),
routes: this.extractRoutes(router)
});
console.log(`从路由器已注册: ${appName}`);
}
// 处理路由变化
handleRouteChange(type, url) {
const newRoute = {
path: url || location.pathname,
search: location.search,
hash: location.hash,
fullPath: location.href,
timestamp: Date.now(),
type
};
// 更新当前路由
this.currentRoute = newRoute;
this.routeHistory.push(newRoute);
// 确定目标应用
const targetApp = this.getTargetApp(newRoute.path);
// 同步到子应用
this.syncToSlaveRouters(newRoute, targetApp);
// 通知监听器
this.notifyRouteChange(newRoute);
}
// 获取目标应用
getTargetApp(path) {
for (const [appName, slaveRouter] of this.slaveRouters) {
if (path.startsWith(slaveRouter.basePath)) {
return appName;
}
}
return null;
}
// 同步到从路由器
syncToSlaveRouters(route, activeApp) {
this.slaveRouters.forEach((slaveRouter, appName) => {
const shouldActivate = appName === activeApp;
if (shouldActivate && !slaveRouter.active) {
// 激活应用路由
this.activateSlaveRouter(appName, route);
} else if (!shouldActivate && slaveRouter.active) {
// 失活应用路由
this.deactivateSlaveRouter(appName);
} else if (shouldActivate && slaveRouter.active) {
// 更新应用路由
this.updateSlaveRouter(appName, route);
}
});
}
// 激活从路由器
activateSlaveRouter(appName, route) {
const slaveRouter = this.slaveRouters.get(appName);
if (!slaveRouter) return;
slaveRouter.active = true;
// 计算应用内路由路径
const appPath = route.path.replace(slaveRouter.basePath, '') || '/';
// 通知应用路由变化
if (slaveRouter.router && slaveRouter.router.push) {
slaveRouter.router.push({
path: appPath,
search: route.search,
hash: route.hash
});
}
console.log(`激活从路由器: ${appName}, 路径: ${appPath}`);
}
// 失活从路由器
deactivateSlaveRouter(appName) {
const slaveRouter = this.slaveRouters.get(appName);
if (!slaveRouter) return;
slaveRouter.active = false;
// 通知应用路由失活
if (slaveRouter.router && slaveRouter.router.onDeactivate) {
slaveRouter.router.onDeactivate();
}
console.log(`失活从路由器: ${appName}`);
}
// 更新从路由器
updateSlaveRouter(appName, route) {
const slaveRouter = this.slaveRouters.get(appName);
if (!slaveRouter) return;
const appPath = route.path.replace(slaveRouter.basePath, '') || '/';
// 检查路由是否真的发生了变化
if (slaveRouter.currentPath !== appPath) {
slaveRouter.currentPath = appPath;
if (slaveRouter.router && slaveRouter.router.replace) {
slaveRouter.router.replace({
path: appPath,
search: route.search,
hash: route.hash
});
}
}
}
// 从子应用触发路由跳转
navigateFromSlave(appName, path, options = {}) {
const slaveRouter = this.slaveRouters.get(appName);
if (!slaveRouter) {
console.warn(`未找到从路由器: ${appName}`);
return;
}
// 构造完整路径
const fullPath = slaveRouter.basePath + path.replace(/^\//, '');
// 使用主路由器进行导航
if (options.replace) {
history.replaceState(null, '', fullPath);
} else {
history.pushState(null, '', fullPath);
}
}
// 添加路由监听器
addRouteListener(listener) {
this.routeListeners.add(listener);
return () => {
this.routeListeners.delete(listener);
};
}
// 通知路由变化
notifyRouteChange(route) {
this.routeListeners.forEach(listener => {
try {
listener(route);
} catch (error) {
console.error('路由监听器执行失败:', error);
}
});
}
// 获取应用基础路径
getAppBasePath(appName) {
// 根据应用名生成基础路径
return `/${appName}`;
}
// 提取路由配置
extractRoutes(router) {
// 这里需要根据具体的路由器实现来提取路由信息
if (router && router.getRoutes) {
return router.getRoutes();
}
return [];
}
// 处理浏览器后退/前进
handlePopState(event) {
this.handleRouteChange('pop', location.pathname);
}
handlePushState(event) {
this.handleRouteChange('push', event.detail?.url);
}
handleReplaceState(event) {
this.handleRouteChange('replace', event.detail?.url);
}
// 获取路由统计信息
getRouteStats() {
return {
totalRoutes: this.routeHistory.length,
activeApps: Array.from(this.slaveRouters.entries())
.filter(([name, router]) => router.active)
.map(([name]) => name),
currentRoute: this.currentRoute,
registeredApps: Array.from(this.slaveRouters.keys())
};
}
}
// 使用示例
const routerManager = new MasterSlaveRouterManager();
// 在主应用中注册
const mainRouter = new VueRouter({
routes: [
{ path: '/home', component: Home },
{ path: '/micro-app-1/*', component: MicroAppContainer }
]
});
routerManager.registerMasterRouter(mainRouter);
// 在子应用中注册
const microAppRouter = new VueRouter({
routes: [
{ path: '/', component: MicroHome },
{ path: '/detail', component: MicroDetail }
]
});
routerManager.registerSlaveRouter('micro-app-1', microAppRouter);
// 监听路由变化
routerManager.addRouteListener((route) => {
console.log('路由变化:', route);
updateBreadcrumb(route);
trackPageView(route);
});
事件驱动路由
通过事件机制实现路由状态的双向同步。
javascript
// 事件驱动路由管理器
class EventDrivenRouterManager {
constructor() {
this.eventBus = new EventTarget();
this.routerInstances = new Map();
this.routeState = {
current: null,
previous: null,
pending: null
};
this.navigationGuards = [];
this.init();
}
init() {
// 监听浏览器路由事件
window.addEventListener('popstate', this.handleBrowserNavigation.bind(this));
// 设置全局路由事件监听
this.setupGlobalRouteEvents();
}
// 设置全局路由事件
setupGlobalRouteEvents() {
// 监听路由导航请求
this.eventBus.addEventListener('route:navigate', this.handleNavigationRequest.bind(this));
// 监听路由状态更新
this.eventBus.addEventListener('route:update', this.handleRouteUpdate.bind(this));
// 监听应用路由注册
this.eventBus.addEventListener('app:register-router', this.handleRouterRegistration.bind(this));
}
// 注册应用路由器
registerRouter(appName, router, config = {}) {
const routerInstance = {
name: appName,
router,
config: {
basePath: config.basePath || `/${appName}`,
mode: config.mode || 'history',
beforeEach: config.beforeEach,
afterEach: config.afterEach,
...config
},
active: false,
lastRoute: null
};
this.routerInstances.set(appName, routerInstance);
// 包装路由器的导航方法
this.wrapRouterMethods(routerInstance);
// 触发注册事件
this.eventBus.dispatchEvent(new CustomEvent('app:register-router', {
detail: { appName, config: routerInstance.config }
}));
console.log(`路由器注册成功: ${appName}`);
}
// 包装路由器方法
wrapRouterMethods(routerInstance) {
const { router, name } = routerInstance;
// 包装push方法
if (router.push) {
const originalPush = router.push.bind(router);
router.push = (location) => {
this.beforeRouterNavigation(name, location, 'push');
return originalPush(location).then(() => {
this.afterRouterNavigation(name, location, 'push');
});
};
}
// 包装replace方法
if (router.replace) {
const originalReplace = router.replace.bind(router);
router.replace = (location) => {
this.beforeRouterNavigation(name, location, 'replace');
return originalReplace(location).then(() => {
this.afterRouterNavigation(name, location, 'replace');
});
};
}
// 监听路由变化
if (router.beforeEach) {
router.beforeEach((to, from, next) => {
this.handleAppRouteChange(name, to, from, next);
});
}
}
// 路由导航前处理
beforeRouterNavigation(appName, location, type) {
const event = new CustomEvent('route:before-navigate', {
detail: { appName, location, type }
});
this.eventBus.dispatchEvent(event);
}
// 路由导航后处理
afterRouterNavigation(appName, location, type) {
const event = new CustomEvent('route:after-navigate', {
detail: { appName, location, type }
});
this.eventBus.dispatchEvent(event);
}
// 处理应用内路由变化
handleAppRouteChange(appName, to, from, next) {
const routerInstance = this.routerInstances.get(appName);
if (!routerInstance) {
next();
return;
}
// 构造全局路由路径
const globalPath = routerInstance.config.basePath + to.path.replace(/^\//, '');
// 更新浏览器URL
if (window.location.pathname !== globalPath) {
history.pushState(null, '', globalPath + (to.query ? '?' + new URLSearchParams(to.query).toString() : ''));
}
// 更新路由状态
this.updateRouteState({
path: globalPath,
appName,
appRoute: to,
fullPath: globalPath + (location.search || '') + (location.hash || '')
});
next();
}
// 处理导航请求
async handleNavigationRequest(event) {
const { path, options = {} } = event.detail;
try {
// 执行导航守卫
await this.executeNavigationGuards(path, options);
// 执行导航
await this.performNavigation(path, options);
} catch (error) {
console.error('导航失败:', error);
// 触发导航失败事件
this.eventBus.dispatchEvent(new CustomEvent('route:navigate-failed', {
detail: { path, options, error }
}));
}
}
// 执行导航守卫
async executeNavigationGuards(path, options) {
for (const guard of this.navigationGuards) {
const result = await guard(path, this.routeState.current, options);
if (result === false) {
throw new Error('Navigation cancelled by guard');
} else if (typeof result === 'string') {
// 重定向
throw new Error(`Redirect to: ${result}`);
}
}
}
// 执行导航
async performNavigation(path, options) {
// 找到目标应用
const targetApp = this.findTargetApp(path);
if (!targetApp) {
throw new Error(`No app found for path: ${path}`);
}
const routerInstance = this.routerInstances.get(targetApp);
const appPath = path.replace(routerInstance.config.basePath, '') || '/';
// 激活目标应用
await this.activateApp(targetApp);
// 在应用内导航
if (routerInstance.router.push) {
if (options.replace) {
await routerInstance.router.replace(appPath);
} else {
await routerInstance.router.push(appPath);
}
}
}
// 激活应用
async activateApp(appName) {
// 失活其他应用
for (const [name, instance] of this.routerInstances) {
if (name !== appName && instance.active) {
instance.active = false;
// 触发应用失活事件
this.eventBus.dispatchEvent(new CustomEvent('app:deactivated', {
detail: { appName: name }
}));
}
}
// 激活目标应用
const targetInstance = this.routerInstances.get(appName);
if (targetInstance) {
targetInstance.active = true;
// 触发应用激活事件
this.eventBus.dispatchEvent(new CustomEvent('app:activated', {
detail: { appName }
}));
}
}
// 查找目标应用
findTargetApp(path) {
for (const [appName, instance] of this.routerInstances) {
if (path.startsWith(instance.config.basePath)) {
return appName;
}
}
return null;
}
// 更新路由状态
updateRouteState(newRoute) {
this.routeState.previous = this.routeState.current;
this.routeState.current = newRoute;
// 触发路由状态更新事件
this.eventBus.dispatchEvent(new CustomEvent('route:state-updated', {
detail: {
current: this.routeState.current,
previous: this.routeState.previous
}
}));
}
// 添加导航守卫
addNavigationGuard(guard) {
this.navigationGuards.push(guard);
return () => {
const index = this.navigationGuards.indexOf(guard);
if (index > -1) {
this.navigationGuards.splice(index, 1);
}
};
}
// 程序化导航
push(path, options = {}) {
this.eventBus.dispatchEvent(new CustomEvent('route:navigate', {
detail: { path, options: { ...options, replace: false } }
}));
}
replace(path, options = {}) {
this.eventBus.dispatchEvent(new CustomEvent('route:navigate', {
detail: { path, options: { ...options, replace: true } }
}));
}
// 处理浏览器导航
handleBrowserNavigation(event) {
const path = location.pathname;
const targetApp = this.findTargetApp(path);
if (targetApp) {
this.performNavigation(path, { fromBrowser: true });
}
}
// 获取路由状态
getRouteState() {
return { ...this.routeState };
}
// 监听路由事件
onRouteChange(callback) {
this.eventBus.addEventListener('route:state-updated', callback);
return () => {
this.eventBus.removeEventListener('route:state-updated', callback);
};
}
}
// 使用示例
const eventRouterManager = new EventDrivenRouterManager();
// 注册导航守卫
eventRouterManager.addNavigationGuard(async (to, from, options) => {
console.log('导航守卫:', { to, from, options });
// 权限检查
if (to.includes('/admin') && !isAdmin()) {
return '/login';
}
// 数据预加载
if (to.includes('/dashboard')) {
await preloadDashboardData();
}
return true;
});
// 监听路由变化
eventRouterManager.onRouteChange((event) => {
const { current, previous } = event.detail;
console.log('路由状态更新:', { current, previous });
// 更新面包屑
updateBreadcrumb(current);
// 页面统计
trackPageView(current);
});
// 注册应用路由器
eventRouterManager.registerRouter('micro-app-1', microAppRouter, {
basePath: '/micro-app-1',
beforeEach: (to, from, next) => {
console.log('micro-app-1 路由变化:', { to, from });
next();
}
});
// 程序化导航
eventRouterManager.push('/micro-app-1/dashboard');
4.2 路由状态同步流程图
graph TD
A[路由变化触发] --> B{变化来源}
B -->|浏览器| C[popstate事件]
B -->|应用内| D[路由器导航]
B -->|程序化| E[API调用]
C --> F[解析目标路径]
D --> F
E --> F
F --> G[确定目标应用]
G --> H{目标应用存在?}
H -->|否| I[404处理]
H -->|是| J[执行导航守卫]
J --> K{守卫通过?}
K -->|否| L[阻止导航]
K -->|是| M[应用切换处理]
M --> N[失活当前应用]
N --> O[激活目标应用]
O --> P[同步应用路由]
P --> Q[更新浏览器URL]
Q --> R[触发状态更新事件]
R --> S[路由同步完成]
I --> T[显示错误页面]
L --> U[保持当前状态]
style J fill:#e8f5e8
style M fill:#e3f2fd
style R fill:#fff3e0
style I fill:#ffcdd2
style L fill:#ffcdd2
5. 通信方式全面对比
微前端应用间的通信是确保系统协调工作的核心机制。
5.1 通信方式分类对比
基于事件的通信
javascript
// 事件通信对比实现
const eventCommunicationComparison = {
// 自定义事件
'Custom Events': {
description: '基于DOM自定义事件的通信',
implementation: `
// 发送方
window.dispatchEvent(new CustomEvent('micro:userLogin', {
detail: { userId: 123, username: 'john' }
}));
// 接收方
window.addEventListener('micro:userLogin', (event) => {
console.log('用户登录:', event.detail);
});
`,
pros: ['原生支持', '简单易用', '无依赖'],
cons: ['全局污染', '难以管理', '无类型检查'],
scenario: '简单的事件通知',
performance: '★★★★★'
},
// EventBus
'Event Bus': {
description: '专用的事件总线系统',
implementation: `
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);
}
}
}
const eventBus = new EventBus();
eventBus.on('userLogin', handleUserLogin);
eventBus.emit('userLogin', userData);
`,
pros: ['集中管理', '支持取消监听', '可扩展'],
cons: ['需要实现', '内存泄漏风险', '调试困难'],
scenario: '复杂的事件交互',
performance: '★★★★☆'
},
// Pub/Sub
'Pub/Sub Pattern': {
description: '发布订阅模式通信',
implementation: `
class PubSub {
constructor() {
this.subscribers = new Map();
}
subscribe(topic, callback) {
if (!this.subscribers.has(topic)) {
this.subscribers.set(topic, new Set());
}
this.subscribers.get(topic).add(callback);
return () => this.subscribers.get(topic).delete(callback);
}
publish(topic, data) {
const callbacks = this.subscribers.get(topic);
if (callbacks) {
callbacks.forEach(callback => {
try {
callback(data);
} catch (error) {
console.error('Pub/Sub callback error:', error);
}
});
}
}
}
`,
pros: ['解耦性好', '支持多订阅', '错误隔离'],
cons: ['复杂度高', '调试困难', '性能开销'],
scenario: '松耦合的系统通信',
performance: '★★★☆☆'
}
};
基于状态的通信
javascript
// 状态通信对比实现
const stateCommunicationComparison = {
// 全局状态
'Global State': {
description: '全局状态管理器',
implementation: `
class GlobalStateManager {
constructor() {
this.state = {};
this.listeners = new Map();
}
setState(key, value) {
const oldValue = this.state[key];
this.state[key] = value;
const keyListeners = this.listeners.get(key);
if (keyListeners) {
keyListeners.forEach(callback => callback(value, oldValue));
}
}
getState(key) {
return this.state[key];
}
subscribe(key, callback) {
if (!this.listeners.has(key)) {
this.listeners.set(key, new Set());
}
this.listeners.get(key).add(callback);
// 立即调用一次
callback(this.state[key], undefined);
return () => this.listeners.get(key).delete(callback);
}
}
const globalState = new GlobalStateManager();
// 应用A
globalState.setState('user', { id: 1, name: 'John' });
// 应用B
const unsubscribe = globalState.subscribe('user', (user) => {
console.log('用户状态更新:', user);
});
`,
pros: ['状态持久', '自动通知', '类型安全'],
cons: ['全局污染', '状态冲突', '难以调试'],
scenario: '需要持久化状态的场景',
performance: '★★★★☆'
},
// Redux/Vuex
'Store Pattern': {
description: '基于Store模式的状态管理',
implementation: `
// 简化的Store实现
class MicroFrontendStore {
constructor() {
this.state = {};
this.reducers = {};
this.middlewares = [];
this.subscribers = new Set();
}
registerReducer(namespace, reducer) {
this.reducers[namespace] = reducer;
if (!this.state[namespace]) {
this.state[namespace] = {};
}
}
dispatch(action) {
const newState = { ...this.state };
Object.keys(this.reducers).forEach(namespace => {
newState[namespace] = this.reducers[namespace](
this.state[namespace],
action
);
});
// 应用中间件
this.middlewares.forEach(middleware => {
middleware(action, this.state, newState);
});
this.state = newState;
// 通知订阅者
this.subscribers.forEach(callback => callback(this.state));
}
subscribe(callback) {
this.subscribers.add(callback);
return () => this.subscribers.delete(callback);
}
getState() {
return this.state;
}
}
const store = new MicroFrontendStore();
// 注册reducer
store.registerReducer('user', (state = {}, action) => {
switch (action.type) {
case 'SET_USER':
return { ...state, ...action.payload };
default:
return state;
}
});
// 订阅状态变化
store.subscribe((state) => {
console.log('Store状态更新:', state);
});
// 分发action
store.dispatch({
type: 'SET_USER',
payload: { id: 1, name: 'John' }
});
`,
pros: ['可预测性', '时间旅行', '中间件支持'],
cons: ['学习成本', '样板代码', '性能开销'],
scenario: '复杂的状态管理需求',
performance: '★★★☆☆'
},
// 响应式状态
'Reactive State': {
description: '基于响应式编程的状态管理',
implementation: `
class ReactiveState {
constructor() {
this.state = this.createReactiveState({});
this.effects = new Set();
}
createReactiveState(target) {
return new Proxy(target, {
set: (obj, prop, value) => {
const oldValue = obj[prop];
obj[prop] = value;
// 触发副作用
this.effects.forEach(effect => {
if (effect.dependencies.has(prop)) {
effect.callback(value, oldValue, prop);
}
});
return true;
},
get: (obj, prop) => {
// 收集依赖
if (this.currentEffect) {
this.currentEffect.dependencies.add(prop);
}
return obj[prop];
}
});
}
effect(callback) {
const effect = {
callback,
dependencies: new Set()
};
this.currentEffect = effect;
callback(); // 首次执行收集依赖
this.currentEffect = null;
this.effects.add(effect);
return () => this.effects.delete(effect);
}
computed(fn) {
let cached = null;
let dirty = true;
const computedEffect = {
callback: () => {
dirty = true;
},
dependencies: new Set()
};
this.effects.add(computedEffect);
return () => {
if (dirty) {
this.currentEffect = computedEffect;
cached = fn();
this.currentEffect = null;
dirty = false;
}
return cached;
};
}
}
const reactiveState = new ReactiveState();
// 定义响应式状态
reactiveState.state.user = { name: 'John', age: 25 };
// 创建副作用
reactiveState.effect(() => {
console.log('用户姓名:', reactiveState.state.user.name);
});
// 创建计算属性
const userDisplayName = reactiveState.computed(() => {
return \`\${reactiveState.state.user.name} (\${reactiveState.state.user.age})\`;
});
// 状态变更会自动触发副作用
reactiveState.state.user.name = 'Jane';
`,
pros: ['自动依赖收集', '细粒度更新', '直观易用'],
cons: ['实现复杂', '调试困难', '内存开销'],
scenario: '需要细粒度响应的应用',
performance: '★★★★☆'
}
};
基于消息的通信
javascript
// 消息通信对比实现
const messageCommunicationComparison = {
// PostMessage
'PostMessage': {
description: '浏览器原生的跨域消息通信',
implementation: `
// 主应用
class PostMessageCommunicator {
constructor() {
this.messageHandlers = new Map();
this.init();
}
init() {
window.addEventListener('message', this.handleMessage.bind(this));
}
sendToApp(appName, data) {
const iframe = document.querySelector(\`iframe[data-app="\${appName}"]\`);
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage({
type: 'main-to-app',
appName,
data,
timestamp: Date.now()
}, '*');
}
}
handleMessage(event) {
const { type, appName, data } = event.data;
if (type === 'app-to-main') {
const handler = this.messageHandlers.get(appName);
if (handler) {
handler(data);
}
}
}
onMessage(appName, handler) {
this.messageHandlers.set(appName, handler);
}
}
// 子应用
class IframeAppCommunicator {
constructor(appName) {
this.appName = appName;
this.messageHandlers = new Map();
this.init();
}
init() {
window.addEventListener('message', this.handleMessage.bind(this));
}
sendToMain(data) {
window.parent.postMessage({
type: 'app-to-main',
appName: this.appName,
data,
timestamp: Date.now()
}, '*');
}
handleMessage(event) {
const { type, appName, data } = event.data;
if (type === 'main-to-app' && appName === this.appName) {
this.messageHandlers.forEach(handler => handler(data));
}
}
onMessage(handler) {
this.messageHandlers.set(Date.now(), handler);
}
}
`,
pros: ['原生支持', '跨域安全', '简单可靠'],
cons: ['仅限iframe', '序列化限制', '单向通信'],
scenario: 'iframe架构的微前端',
performance: '★★★★☆'
},
// WebSocket
'WebSocket': {
description: '基于WebSocket的实时通信',
implementation: `
class WebSocketCommunicator {
constructor(url) {
this.url = url;
this.ws = null;
this.reconnectInterval = 5000;
this.messageHandlers = new Map();
this.connect();
}
connect() {
try {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket连接已建立');
};
this.ws.onmessage = (event) => {
try {
const message = JSON.parse(event.data);
this.handleMessage(message);
} catch (error) {
console.error('消息解析失败:', error);
}
};
this.ws.onclose = () => {
console.log('WebSocket连接已关闭');
setTimeout(() => this.connect(), this.reconnectInterval);
};
this.ws.onerror = (error) => {
console.error('WebSocket错误:', error);
};
} catch (error) {
console.error('WebSocket连接失败:', error);
setTimeout(() => this.connect(), this.reconnectInterval);
}
}
send(type, data) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({
type,
data,
timestamp: Date.now(),
sender: window.location.href
}));
} else {
console.warn('WebSocket未连接');
}
}
handleMessage(message) {
const { type, data } = message;
const handler = this.messageHandlers.get(type);
if (handler) {
handler(data);
}
}
on(type, handler) {
this.messageHandlers.set(type, handler);
}
broadcast(type, data) {
this.send('broadcast', { type, data });
}
close() {
if (this.ws) {
this.ws.close();
}
}
}
// 使用示例
const wsCommunicator = new WebSocketCommunicator('ws://localhost:8080');
// 监听消息
wsCommunicator.on('userStatusChange', (data) => {
console.log('用户状态变化:', data);
});
// 发送消息
wsCommunicator.send('userLogin', { userId: 123 });
// 广播消息
wsCommunicator.broadcast('globalNotification', {
message: '系统维护通知'
});
`,
pros: ['实时通信', '双向通信', '服务端支持'],
cons: ['需要服务端', '连接管理', '资源消耗'],
scenario: '需要实时同步的应用',
performance: '★★★☆☆'
},
// SharedWorker
'SharedWorker': {
description: '基于SharedWorker的多标签页通信',
implementation: `
// SharedWorker脚本 (shared-worker.js)
const connections = new Set();
const messageQueues = new Map();
self.addEventListener('connect', (event) => {
const port = event.ports[0];
connections.add(port);
port.onmessage = (e) => {
const { type, data, target } = e.data;
switch (type) {
case 'broadcast':
// 广播给所有连接
connections.forEach(conn => {
if (conn !== port) {
conn.postMessage({ type: 'broadcast', data });
}
});
break;
case 'direct':
// 直接发送给特定目标
const targetPort = findPortByTarget(target);
if (targetPort) {
targetPort.postMessage({ type: 'direct', data });
}
break;
case 'register':
// 注册端口标识
port._identifier = data.identifier;
break;
}
};
port.onclose = () => {
connections.delete(port);
};
port.start();
});
function findPortByTarget(target) {
for (const port of connections) {
if (port._identifier === target) {
return port;
}
}
return null;
}
// 应用中的使用
class SharedWorkerCommunicator {
constructor(appName) {
this.appName = appName;
this.worker = new SharedWorker('/shared-worker.js');
this.port = this.worker.port;
this.messageHandlers = new Map();
this.init();
}
init() {
this.port.onmessage = (event) => {
const { type, data } = event.data;
const handler = this.messageHandlers.get(type);
if (handler) {
handler(data);
}
};
// 注册应用标识
this.port.postMessage({
type: 'register',
data: { identifier: this.appName }
});
this.port.start();
}
broadcast(data) {
this.port.postMessage({
type: 'broadcast',
data: { ...data, from: this.appName }
});
}
sendTo(target, data) {
this.port.postMessage({
type: 'direct',
target,
data: { ...data, from: this.appName }
});
}
on(type, handler) {
this.messageHandlers.set(type, handler);
}
}
// 使用示例
const sharedCommunicator = new SharedWorkerCommunicator('main-app');
// 监听广播消息
sharedCommunicator.on('broadcast', (data) => {
console.log('收到广播:', data);
});
// 发送广播
sharedCommunicator.broadcast({
type: 'userLogin',
userId: 123
});
// 发送给特定应用
sharedCommunicator.sendTo('micro-app-1', {
type: 'themeChange',
theme: 'dark'
});
`,
pros: ['多标签页通信', '持久连接', '共享状态'],
cons: ['浏览器支持限制', '调试困难', '资源共享'],
scenario: '多标签页协作的应用',
performance: '★★★☆☆'
}
};
5.2 通信方式选择决策树
graph TD
A[开始选择通信方式] --> B{通信场景}
B -->|简单事件通知| C[自定义事件]
B -->|复杂状态管理| D{状态持久化需求}
B -->|跨域通信| E[PostMessage]
B -->|实时通信| F[WebSocket]
B -->|多标签页| G[SharedWorker]
D -->|需要持久化| H{状态复杂度}
D -->|无需持久化| I[EventBus]
H -->|简单| J[全局状态]
H -->|复杂| K{框架偏好}
K -->|Redux系| L[Store模式]
K -->|Vue系| M[响应式状态]
K -->|无偏好| N[自定义Store]
C --> O[实现完成]
I --> O
E --> O
F --> O
G --> O
J --> O
L --> O
M --> O
N --> O
style C fill:#e8f5e8
style I fill:#e3f2fd
style J fill:#fff3e0
style L fill:#f3e5f5
style M fill:#fce4ec
5.3 通信性能对比测试
javascript
// 通信性能测试套件
class CommunicationPerformanceTest {
constructor() {
this.testResults = new Map();
this.testIterations = 1000;
}
// 测试自定义事件性能
async testCustomEvents() {
const startTime = performance.now();
for (let i = 0; i < this.testIterations; i++) {
const event = new CustomEvent('test-event', {
detail: { iteration: i, data: 'test data' }
});
window.dispatchEvent(event);
}
const endTime = performance.now();
return endTime - startTime;
}
// 测试EventBus性能
async testEventBus() {
const eventBus = new EventBus();
const startTime = performance.now();
eventBus.on('test-event', () => {});
for (let i = 0; i < this.testIterations; i++) {
eventBus.emit('test-event', { iteration: i, data: 'test data' });
}
const endTime = performance.now();
return endTime - startTime;
}
// 测试状态管理性能
async testStateManager() {
const stateManager = new GlobalStateManager();
const startTime = performance.now();
stateManager.subscribe('testKey', () => {});
for (let i = 0; i < this.testIterations; i++) {
stateManager.setState('testKey', { iteration: i, data: 'test data' });
}
const endTime = performance.now();
return endTime - startTime;
}
// 测试PostMessage性能
async testPostMessage() {
const iframe = document.createElement('iframe');
iframe.src = 'about:blank';
document.body.appendChild(iframe);
const startTime = performance.now();
for (let i = 0; i < this.testIterations; i++) {
iframe.contentWindow.postMessage({
iteration: i,
data: 'test data'
}, '*');
}
const endTime = performance.now();
document.body.removeChild(iframe);
return endTime - startTime;
}
// 运行完整性能测试
async runFullPerformanceTest() {
console.log('开始通信性能测试...');
const results = {
customEvents: await this.testCustomEvents(),
eventBus: await this.testEventBus(),
stateManager: await this.testStateManager(),
postMessage: await this.testPostMessage()
};
// 计算相对性能
const baseline = Math.min(...Object.values(results));
const relativeResults = {};
Object.entries(results).forEach(([method, time]) => {
relativeResults[method] = {
absoluteTime: time,
relativePerformance: (baseline / time * 100).toFixed(2) + '%',
throughput: (this.testIterations / time * 1000).toFixed(0) + ' ops/sec'
};
});
return relativeResults;
}
// 内存使用测试
async testMemoryUsage() {
const initialMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
// 创建大量通信实例
const instances = [];
for (let i = 0; i < 100; i++) {
instances.push({
eventBus: new EventBus(),
stateManager: new GlobalStateManager(),
customEventListeners: []
});
}
// 注册监听器
instances.forEach((instance, index) => {
instance.eventBus.on('test', () => {});
instance.stateManager.subscribe('test', () => {});
const listener = () => {};
window.addEventListener(`test-${index}`, listener);
instance.customEventListeners.push(listener);
});
const peakMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
// 清理
instances.forEach((instance, index) => {
instance.customEventListeners.forEach(listener => {
window.removeEventListener(`test-${index}`, listener);
});
});
const finalMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
return {
initialMemory,
peakMemory,
finalMemory,
memoryIncrease: peakMemory - initialMemory,
memoryLeakage: finalMemory - initialMemory
};
}
// 生成测试报告
generateReport(performanceResults, memoryResults) {
return `
## 微前端通信方式性能测试报告
### 性能测试结果 (${this.testIterations} 次操作)
| 通信方式 | 绝对时间(ms) | 相对性能 | 吞吐量 |
|---------|-------------|---------|--------|
${Object.entries(performanceResults).map(([method, result]) =>
`| ${method} | ${result.absoluteTime.toFixed(2)} | ${result.relativePerformance} | ${result.throughput} |`
).join('\n')}
### 内存使用测试
- 初始内存: ${(memoryResults.initialMemory / 1024 / 1024).toFixed(2)} MB
- 峰值内存: ${(memoryResults.peakMemory / 1024 / 1024).toFixed(2)} MB
- 最终内存: ${(memoryResults.finalMemory / 1024 / 1024).toFixed(2)} MB
- 内存增长: ${(memoryResults.memoryIncrease / 1024 / 1024).toFixed(2)} MB
- 内存泄漏: ${(memoryResults.memoryLeakage / 1024 / 1024).toFixed(2)} MB
### 推荐建议
${this.generateRecommendations(performanceResults, memoryResults)}
`;
}
generateRecommendations(performanceResults, memoryResults) {
const recommendations = [];
// 性能推荐
const fastestMethod = Object.entries(performanceResults).reduce((a, b) =>
a[1].absoluteTime < b[1].absoluteTime ? a : b
)[0];
recommendations.push(`- 性能最优: ${fastestMethod}`);
// 内存推荐
if (memoryResults.memoryLeakage > 1024 * 1024) { // 1MB
recommendations.push('- 注意内存泄漏,及时清理事件监听器');
}
if (memoryResults.memoryIncrease > 10 * 1024 * 1024) { // 10MB
recommendations.push('- 考虑使用更轻量级的通信方案');
}
return recommendations.join('\n');
}
}
// 运行性能测试
async function runCommunicationTests() {
const testSuite = new CommunicationPerformanceTest();
const performanceResults = await testSuite.runFullPerformanceTest();
const memoryResults = await testSuite.testMemoryUsage();
const report = testSuite.generateReport(performanceResults, memoryResults);
console.log(report);
return { performanceResults, memoryResults, report };
}
5.4 通信方案最佳实践
javascript
// 通信方案最佳实践
class CommunicationBestPractices {
static getRecommendation(scenario) {
const recommendations = {
'simple-events': {
solution: 'Custom Events',
reason: '简单直接,无额外依赖',
implementation: 'window.dispatchEvent + addEventListener'
},
'complex-interaction': {
solution: 'Event Bus',
reason: '支持复杂的事件管理和取消监听',
implementation: '自定义EventBus类'
},
'state-sharing': {
solution: 'Global State Manager',
reason: '状态持久化和自动同步',
implementation: 'Proxy + Subscription模式'
},
'cross-origin': {
solution: 'PostMessage',
reason: '安全的跨域通信',
implementation: 'iframe + postMessage API'
},
'real-time': {
solution: 'WebSocket',
reason: '实时双向通信',
implementation: 'WebSocket + 消息路由'
},
'multi-tab': {
solution: 'SharedWorker',
reason: '多标签页状态同步',
implementation: 'SharedWorker + MessagePort'
}
};
return recommendations[scenario] || recommendations['simple-events'];
}
static createOptimalCommunicator(scenarios) {
// 根据多个场景创建最优的通信器组合
const communicators = [];
scenarios.forEach(scenario => {
const recommendation = this.getRecommendation(scenario);
communicators.push(recommendation);
});
return new HybridCommunicator(communicators);
}
}
// 混合通信器
class HybridCommunicator {
constructor(communicators) {
this.communicators = new Map();
this.init(communicators);
}
init(communicators) {
communicators.forEach((config, index) => {
let communicator;
switch (config.solution) {
case 'Custom Events':
communicator = new CustomEventCommunicator();
break;
case 'Event Bus':
communicator = new EventBusCommunicator();
break;
case 'Global State Manager':
communicator = new StateCommunicator();
break;
case 'PostMessage':
communicator = new PostMessageCommunicator();
break;
case 'WebSocket':
communicator = new WebSocketCommunicator();
break;
case 'SharedWorker':
communicator = new SharedWorkerCommunicator();
break;
}
this.communicators.set(config.solution, communicator);
});
}
// 智能路由消息到最适合的通信器
send(message, options = {}) {
const { type, target, data, priority = 'normal' } = options;
let communicator;
// 根据消息特征选择通信器
if (target && target.includes('iframe')) {
communicator = this.communicators.get('PostMessage');
} else if (type === 'state-change') {
communicator = this.communicators.get('Global State Manager');
} else if (priority === 'real-time') {
communicator = this.communicators.get('WebSocket');
} else {
communicator = this.communicators.get('Event Bus') ||
this.communicators.get('Custom Events');
}
if (communicator && communicator.send) {
return communicator.send(message, options);
} else {
console.warn('No suitable communicator found for message:', message);
}
}
// 统一的监听接口
on(event, handler, options = {}) {
const communicators = options.communicators || Array.from(this.communicators.values());
const unsubscribers = communicators.map(communicator => {
if (communicator.on) {
return communicator.on(event, handler, options);
}
}).filter(Boolean);
return () => {
unsubscribers.forEach(unsubscribe => unsubscribe());
};
}
// 获取通信统计
getStats() {
const stats = {};
this.communicators.forEach((communicator, name) => {
if (communicator.getStats) {
stats[name] = communicator.getStats();
}
});
return stats;
}
}
// 使用示例
const scenarios = ['simple-events', 'state-sharing', 'cross-origin'];
const communicator = CommunicationBestPractices.createOptimalCommunicator(scenarios);
// 发送不同类型的消息
communicator.send({ type: 'user-login', userId: 123 }, {
type: 'event',
priority: 'normal'
});
communicator.send({ user: { id: 123, name: 'John' } }, {
type: 'state-change'
});
communicator.send({ message: 'Hello iframe' }, {
target: 'iframe-app',
type: 'cross-origin'
});
// 统一监听
communicator.on('user-status-change', (data) => {
console.log('用户状态变化:', data);
});