npm package: @hhfenpm/micro-app
Description: 微前端通信桥接和状态同步工具，支持父子应用通信、状态同步、生命周期管理
Latest version: 1.0.15

# @hhfenpm/micro-app

基于 iframe + postMessage 的微前端工具：父子应用**通信桥接**、**Vuex 状态同步**、**生命周期**与**路由同步**。

**兼容 IE9+**

## 安装

```bash
npm install @hhfenpm/micro-app
# 或
yarn add @hhfenpm/micro-app
```

## 能力概览

| 能力         | 说明                                                                                |
| ------------ | ----------------------------------------------------------------------------------- |
| **通信桥接** | 子应用通过 `vm.$base.命名空间.方法(params)` 调用父应用方法，支持 Promise            |
| **状态同步** | 父子应用 Vuex `base` 模块双向同步                                                   |
| **生命周期** | 父应用调用 `mount/update/unmount`，子应用通过 `window.__MICRO_APP_LIFECYCLE__` 响应 |
| **路由同步** | 子应用路由变化同步到父应用 URL（需子应用调用 `store.attachRouterSync(router)`）     |

---

## 一、Bridge（通信桥接）

### 父应用

父应用需提供 `handlers`：`{ 命名空间: { 方法名: 函数 } }`。可使用内置 `createRegisterHandlers` 生成 `ui`（Element UI 等）和 `cs`（Electron）两个命名空间：

```javascript
import { initBridge, createRegisterHandlers } from '@hhfenpm/micro-app'

const vm = new Vue({
  /* ... */
})

// getElectron：返回 electron 模块，无则 () => ({}) 或 () => require('@/utils/electron')
const getElectron = () => ({}) // 或 () => require('@/utils/electron')
const toHandlers = createRegisterHandlers(getElectron)

initBridge({
  isBase: true,
  vm,
  handlers: toHandlers(vm),
  iframeSelector: '#microApp', // 可选，默认 '#microApp'
})
```

`createRegisterHandlers(getElectron)` 返回 `(vm) => ({ ui, cs })`：

- **ui**：`$message`、`$success`、`$warning`、`$error`、`$notify`、`$confirm`、`$alert`、`$prompt`、`$loading`
- **cs**：Electron 能力（由 `getElectron()` 提供，缺失的方法为 noop）

### 子应用

```javascript
import { initBridge } from '@hhfenpm/micro-app'

const vm = new Vue({
  /* ... */
})

initBridge({ isBase: false, vm })

// 调用父应用：vm.$base.命名空间.方法(params)，返回 Promise
vm.$base.ui.$message('来自子应用')
vm.$base.ui.$confirm('确认？').then(ok => {
  /* ... */
})
vm.$base.cs.show()
```

---

## 二、Core（子应用 URL / 部署检测）

根据「路径 → 模块名」映射、以及「启用模块列表」，计算当前路由是否命中某子应用、其入口 URL、是否已部署。

```javascript
import { createMicroAppCore } from '@hhfenpm/micro-app'

const modelMap = () => ({
  'disease-analysis': ['/disease-analysis', '/ds-consult'],
  health: ['/health-manage'],
})

const core = createMicroAppCore({
  modelMap,
  enabledModules: () => window.GLOBAL_CONFIG?.microApp || null, // 可选，不传则用 GLOBAL_CONFIG.microApp
})

// 根据路径得到模块名，未命中或未启用则为 null
const module = core.microAppModule('/disease-analysis') // 'disease-analysis'

// 子应用完整 URL（含 hash）
const src = core.microAppSrc('/disease-analysis')

// 是否已部署（HEAD /module 可访问）
const ok = await core.microAppDeployed('disease-analysis')
```

---

## 三、Store 插件（状态同步）

在 Vuex 中注册 `baseSyncPlugin`，并在**子应用**中调用 `store.attachRouterSync(router)` 以同步路由。

### 父应用

```javascript
import Vuex from 'vuex'
import { baseSyncPlugin } from '@hhfenpm/micro-app'
import base from './store/modules/base' // 需含 base/SYNC_STATE

const store = new Vuex.Store({
  modules: { base },
  plugins: [baseSyncPlugin({ isBase: true, iframeSelector: '#microApp' })],
})
```

### 子应用

```javascript
import { baseSyncPlugin } from '@hhfenpm/micro-app'
import base from './store/modules/base'

const store = new Vuex.Store({
  modules: { base },
  plugins: [baseSyncPlugin({ isBase: false, iframeSelector: '#microApp' })],
})

import router from './router'
store.attachRouterSync(router) // 必调，用于把子应用路由同步到父应用
```

`base` 模块需提供 `base/SYNC_STATE` mutation，用于接收并合并同步过来的 state。

---

## 四、生命周期

### 子应用

在子应用入口注册：

```javascript
window.__MICRO_APP_LIFECYCLE__ = {
  mount(payload) {
    /* 挂载后 */
  },
  update(payload) {
    /* 更新时，如路由变化 */
  },
  unmount(payload) {
    /* 卸载前 */
  },
}
```

### 父应用

由 `baseSyncPlugin` 在 store 上挂载 `callMicroAppLifeCycle`，在 iframe 加载完成、路由变化、子应用切换时调用：

```javascript
store.callMicroAppLifeCycle('mount', { route: '/xxx' })
store.callMicroAppLifeCycle('update', { route: '/yyy' })
store.callMicroAppLifeCycle('unmount')
```

---

## API 一览

| 接口                                                     | 说明                                                                      |
| -------------------------------------------------------- | ------------------------------------------------------------------------- |
| `initBridge({ isBase, vm, iframeSelector?, handlers? })` | 初始化桥接；父应用传 `handlers`，子应用可访问 `vm.$base`                  |
| `createRegisterHandlers(getElectron?)`                   | 返回 `(vm) => ({ ui, cs })`，用作 `handlers`                              |
| `createMicroAppCore({ modelMap, enabledModules? })`      | 返回 `{ microAppModule, microAppSrc, microAppDeployed }`                  |
| `baseSyncPlugin({ isBase, iframeSelector? })`            | Vuex 插件，并挂载 `store.attachRouterSync`、`store.callMicroAppLifeCycle` |

### 参数说明

- **initBridge**

  - `isBase`: 是否父应用
  - `vm`: Vue 实例（子应用会在其上挂 `vm.$base`、`vm.$baseReady`）
  - `iframeSelector`: 父应用 iframe 选择器，默认 `'#microApp'`
  - `handlers`: 仅父应用需要，`{ [namespace]: { [method]: (params)=>any } }`

- **createRegisterHandlers**

  - `getElectron`: `() => electronModule`，可选；异常或未传时 `cs` 使用 noop

- **createMicroAppCore**

  - `modelMap`: `() => ({ [moduleName]: path[] })`，必填
  - `enabledModules`: `() => string[]` 或 `string[]`，可选；缺省时从 `window.GLOBAL_CONFIG.microApp` 读取

- **baseSyncPlugin**
  - `isBase`: 是否父应用
  - `iframeSelector`: 默认 `'#microApp'`

---

## 注意事项

1. **同源**：postMessage 仅在同源下使用，需校验 `event.origin`。
2. **base 模块**：`baseSyncPlugin` 通过 `base/SYNC_STATE` 同步；`base` 的 state 结构需与约定一致。
3. **子应用必调**：`store.attachRouterSync(router)`，否则子应用路由不会回写到父应用 URL。
4. **IE9 兼容**：本包已针对 IE9 进行了兼容处理，需要确保项目配置了 Babel 转译和 core-js polyfill。

---

## 兼容性

- **浏览器支持**：IE9+、现代浏览器（Chrome、Firefox、Safari、Edge）
- **依赖要求**：
  - Vue 2.6+ / 3.x，Vuex 3.x / 4.x（peerDependencies）
- **项目配置要求**：
  - 需要配置 Babel 转译（`transpileDependencies: true`）
  - 需要配置 core-js polyfill（Promise、Object.fromEntries、Array.includes 等）

---

## 许可

MIT