@micro-zoe/micro-app 库的源码分析,主要围绕其核心功能、架构设计、关键模块实现展开。该库是一个轻量级微前端框架,旨在简化子应用的接入和管理。
一、核心功能与设计理念
-
核心功能:
- 应用加载:动态加载子应用的 HTML、JS、CSS 资源。
- 沙箱隔离:实现 JS 隔离(通过 Proxy)和样式隔离(通过 Shadow DOM 或 Scoped CSS)。
- 路由管理:基于 URL 自动匹配子应用。
- 通信机制:父子应用间通过
data属性和事件通信。 - 生命周期:提供
created、mounted、unmount等钩子。
-
设计理念:
- 轻量化:无依赖,核心代码约 2000 行。
- 侵入性低:子应用无需修改构建配置。
- 类 Web Components:通过自定义标签
<micro-app>加载子应用。
二、源码结构概览
src/
├── apis/ # 全局 API(如 start、prefetch)
├── sandbox/ # 沙箱实现(JS 隔离、样式隔离)
├── router/ # 路由处理逻辑
├── source/ # 资源加载与执行(HTML/JS/CSS)
├── interfaces/ # 通信机制(事件总线、数据传递)
├── scoped_css/ # 样式作用域处理
├── micro_app_element.ts # 自定义元素 `<micro-app>` 的实现
└── index.ts # 入口文件
三、关键模块分析
1. 自定义元素 <micro-app>
- 实现方式:基于
CustomElement定义 Web Components。 - 核心逻辑:
class MicroAppElement extends HTMLElement { connectedCallback() { // 创建微应用实例 this.app = new MicroApp(this.name, this.getAttribute('url'), this) // 加载资源并渲染 this.app.mount() } disconnectedCallback() { this.app.unmount() // 卸载应用,清理沙箱 } }
2. 沙箱隔离
-
JS 沙箱:
- 通过 Proxy 代理全局对象(如
window),隔离全局变量。 - 记录子应用对全局对象的修改,卸载时恢复。
class ProxySandbox { constructor(name: string) { const rawWindow = window const fakeWindow = {} this.proxy = new Proxy(fakeWindow, { get(target, key) { return target[key] || rawWindow[key] }, set(target, key, value) { target[key] = value // 修改仅作用于 fakeWindow return true } }) } } - 通过 Proxy 代理全局对象(如
-
样式隔离:
- Shadow DOM:默认将子应用包裹在 ShadowRoot 中,实现样式隔离。
- Scoped CSS:通过添加
[micro-app-name]属性选择器改写 CSS 规则。
3. 资源加载与执行
- HTML 解析:
fetchSource(url).then(html => { const { scripts, styles, html: processedHtml } = extractScriptsAndStyles(html) this.processStyles(styles) // 插入样式 this.processScripts(scripts) // 执行脚本 }) - 动态脚本执行:
- 通过
eval或new Function执行 JS 代码,包裹在沙箱上下文中。 - 支持模块化脚本(如 SystemJS)。
- 通过
4. 通信机制
- 基于 CustomEvent:
// 父应用发送数据 microApp.setData('app-name', { data: 'value' }) // 子应用监听 window.addEventListener('micro-app-data', (e) => { console.log(e.detail.data) }) - 数据序列化:通过
JSON.parse(JSON.stringify(data))深拷贝避免副作用。
四、路由管理
- URL 监听:监听
popstate和hashchange事件。 - 应用匹配:
function getActiveApps() { return apps.filter(app => { return isMatch(currentPath, app.activeRule) // 匹配路由规则 }) }
五、性能优化
- 资源缓存:通过
localStorage或IndexedDB缓存子应用资源。 - 预加载:
microApp.preload(['app-name'])提前加载资源。 - 并行加载:使用
Promise.all并行加载 JS 和 CSS。
六、错误处理
- 全局错误捕获:
window.addEventListener('error', (e) => { if (e.target?.tagName === 'SCRIPT' && e.target.src.includes('micro-app')) { console.error('子应用脚本加载失败:', e.target.src) } }) - 重试机制:资源加载失败时自动重试(默认 3 次)。
七、总结与评价
- 优点:
- 轻量简洁,学习成本低。
- 沙箱隔离实现较为彻底。
- 对子应用侵入性极低。
- 潜在问题:
- 样式隔离在非 Shadow DOM 模式下可能不彻底。
- Proxy 兼容性(需注意 IE 支持)。
- 适用场景:中小型项目快速接入微前端,无需复杂配置。
建议结合官方文档(micro-zoe.github.io/micro-app)进一步理解设计细节。