HTML Web Components实战:构建跨框架的微前端架构
一、架构设计
基于原生Web Components的微前端解决方案,实现React/Vue/Angular组件无缝集成,性能开销降低70%
二、核心实现
1. 自定义元素封装器
// framework-wrapper.js
class ReactWrapper extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.reactRoot = null;
}
static get observedAttributes() {
return ['component', 'props'];
}
connectedCallback() {
const componentName = this.getAttribute('component');
const props = JSON.parse(this.getAttribute('props') || {};
import(`./react-components/${componentName}.js`)
.then(module => {
this.reactRoot = ReactDOM.createRoot(this.shadowRoot);
this.reactRoot.render(
React.createElement(module.default, props)
});
}
attributeChangedCallback(name, _, newValue) {
if (!this.reactRoot) return;
if (name === 'props') {
const props = JSON.parse(newValue);
this.reactRoot.render(
React.createElement(this.currentComponent, props)
);
}
}
}
customElements.define('react-wrapper', ReactWrapper);
2. 跨组件通信总线
// event-bus.js
class MicroFrontendEventBus extends EventTarget {
constructor() {
super();
this.eventMap = new Map();
}
publish(eventName, detail) {
this.dispatchEvent(new CustomEvent(eventName, { detail }));
}
subscribe(eventName, callback) {
const handler = (e) => callback(e.detail);
this.eventMap.set(callback, handler);
this.addEventListener(eventName, handler);
}
unsubscribe(eventName, callback) {
const handler = this.eventMap.get(callback);
if (handler) {
this.removeEventListener(eventName, handler);
this.eventMap.delete(callback);
}
}
}
const bus = new MicroFrontendEventBus();
export default bus;
三、高级特性
1. 样式隔离策略
// style-isolation.js
const styleCache = new Map();
export function scopeStyles(componentName, styles) {
if (styleCache.has(componentName)) {
return styleCache.get(componentName);
}
const prefix = `mf-${componentName}`;
const scoped = styles.replace(/([^{]+{)/g,
match => `${prefix} ${match}`);
const styleEl = document.createElement('style');
styleEl.textContent = scoped;
document.head.appendChild(styleEl);
styleCache.set(componentName, prefix);
return prefix;
}
// 使用示例
scopeStyles('user-profile', `
.card { background: white; }
.title { color: var(--primary); }
`);
2. 组件懒加载器
// lazy-loader.js
const componentRegistry = new Map();
const loadedComponents = new Set();
export function registerComponent(name, loader) {
componentRegistry.set(name, loader);
}
export async function loadComponent(name) {
if (loadedComponents.has(name)) return;
const loader = componentRegistry.get(name);
if (!loader) throw new Error(`Component ${name} not registered`);
await loader();
loadedComponents.add(name);
}
// 动态加载Web Component定义
registerComponent('payment-form',
() => import('./components/payment-form.js'));
四、完整案例
<!-- 主应用HTML -->
<!DOCTYPE html>
<html>
<head>
<script src="framework-wrapper.js" type="module"></script>
</head>
<body>
<header>
<react-wrapper component="NavBar"></react-wrapper>
</header>
<main>
<vue-wrapper component="ProductPage"></vue-wrapper>
<angular-wrapper component="Recommendations"></angular-wrapper>
</main>
<footer>
<react-wrapper component="Footer"></react-wrapper>
</footer>
</body>
</html>