@hhfenpm/micro-app 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -124
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hhfenpm/micro-app
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
基于 iframe + postMessage 的微前端工具:父子应用**通信桥接**、**Vuex 状态同步**、**生命周期**与**路由同步**。
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
@@ -10,202 +10,200 @@ npm install @hhfenpm/micro-app
|
|
|
10
10
|
yarn add @hhfenpm/micro-app
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## 能力概览
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
| 能力 | 说明 |
|
|
16
|
+
|------|------|
|
|
17
|
+
| **通信桥接** | 子应用通过 `vm.$base.命名空间.方法(params)` 调用父应用方法,支持 Promise |
|
|
18
|
+
| **状态同步** | 父子应用 Vuex `base` 模块双向同步 |
|
|
19
|
+
| **生命周期** | 父应用调用 `mount/update/unmount`,子应用通过 `window.__MICRO_APP_LIFECYCLE__` 响应 |
|
|
20
|
+
| **路由同步** | 子应用路由变化同步到父应用 URL(需子应用调用 `store.attachRouterSync(router)`) |
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
---
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
## 一、Bridge(通信桥接)
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
### 父应用
|
|
27
|
+
|
|
28
|
+
父应用需提供 `handlers`:`{ 命名空间: { 方法名: 函数 } }`。可使用内置 `createRegisterHandlers` 生成 `ui`(Element UI 等)和 `cs`(Electron)两个命名空间:
|
|
26
29
|
|
|
27
30
|
```javascript
|
|
28
|
-
import { initBridge } from '@hhfenpm/micro-app'
|
|
29
|
-
import Vue from 'vue'
|
|
31
|
+
import { initBridge, createRegisterHandlers } from '@hhfenpm/micro-app'
|
|
30
32
|
|
|
31
33
|
const vm = new Vue({ /* ... */ })
|
|
32
34
|
|
|
33
|
-
//
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
$message: (...args) => vm.$message(...args),
|
|
37
|
-
// ... 其他 Element UI 方法
|
|
38
|
-
},
|
|
39
|
-
electron: {
|
|
40
|
-
// ... Electron 方法
|
|
41
|
-
},
|
|
42
|
-
}
|
|
35
|
+
// getElectron:返回 electron 模块,无则 () => ({}) 或 () => require('@/utils/electron')
|
|
36
|
+
const getElectron = () => ({}) // 或 () => require('@/utils/electron')
|
|
37
|
+
const toHandlers = createRegisterHandlers(getElectron)
|
|
43
38
|
|
|
44
|
-
// 初始化桥接
|
|
45
39
|
initBridge({
|
|
46
40
|
isParent: true,
|
|
47
41
|
vm,
|
|
48
|
-
handlers,
|
|
42
|
+
handlers: toHandlers(vm),
|
|
49
43
|
iframeSelector: '#microApp', // 可选,默认 '#microApp'
|
|
50
44
|
})
|
|
51
45
|
```
|
|
52
46
|
|
|
53
|
-
|
|
47
|
+
`createRegisterHandlers(getElectron)` 返回 `(vm) => ({ ui, cs })`:
|
|
48
|
+
|
|
49
|
+
- **ui**:`$message`、`$success`、`$warning`、`$error`、`$notify`、`$confirm`、`$alert`、`$prompt`、`$loading`
|
|
50
|
+
- **cs**:Electron 能力(由 `getElectron()` 提供,缺失的方法为 noop)
|
|
51
|
+
|
|
52
|
+
### 子应用
|
|
54
53
|
|
|
55
54
|
```javascript
|
|
56
55
|
import { initBridge } from '@hhfenpm/micro-app'
|
|
57
|
-
import Vue from 'vue'
|
|
58
56
|
|
|
59
57
|
const vm = new Vue({ /* ... */ })
|
|
60
58
|
|
|
61
|
-
|
|
62
|
-
initBridge({
|
|
63
|
-
isParent: false,
|
|
64
|
-
vm,
|
|
65
|
-
})
|
|
59
|
+
initBridge({ isParent: false, vm })
|
|
66
60
|
|
|
67
|
-
//
|
|
68
|
-
vm.$base.
|
|
69
|
-
vm.$base.
|
|
61
|
+
// 调用父应用:vm.$base.命名空间.方法(params),返回 Promise
|
|
62
|
+
vm.$base.ui.$message('来自子应用')
|
|
63
|
+
vm.$base.ui.$confirm('确认?').then(ok => { /* ... */ })
|
|
64
|
+
vm.$base.cs.show()
|
|
70
65
|
```
|
|
71
66
|
|
|
72
|
-
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 二、Core(子应用 URL / 部署检测)
|
|
70
|
+
|
|
71
|
+
根据「路径 → 模块名」映射、以及「启用模块列表」,计算当前路由是否命中某子应用、其入口 URL、是否已部署。
|
|
73
72
|
|
|
74
73
|
```javascript
|
|
75
74
|
import { createMicroAppCore } from '@hhfenpm/micro-app'
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
'
|
|
80
|
-
'module2': ['/module2'],
|
|
76
|
+
const modelMap = () => ({
|
|
77
|
+
'disease-analysis': ['/disease-analysis', '/ds-consult'],
|
|
78
|
+
'health': ['/health-manage'],
|
|
81
79
|
})
|
|
82
80
|
|
|
83
|
-
// 创建核心功能实例
|
|
84
81
|
const core = createMicroAppCore({
|
|
85
|
-
modelMap
|
|
86
|
-
enabledModules: () => window.GLOBAL_CONFIG?.microApp || null,
|
|
82
|
+
modelMap,
|
|
83
|
+
enabledModules: () => window.GLOBAL_CONFIG?.microApp || null, // 可选,不传则用 GLOBAL_CONFIG.microApp
|
|
87
84
|
})
|
|
88
85
|
|
|
89
|
-
//
|
|
90
|
-
const module = core.microAppModule('/
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
// 根据路径得到模块名,未命中或未启用则为 null
|
|
87
|
+
const module = core.microAppModule('/disease-analysis') // 'disease-analysis'
|
|
88
|
+
|
|
89
|
+
// 子应用完整 URL(含 hash)
|
|
90
|
+
const src = core.microAppSrc('/disease-analysis')
|
|
91
|
+
|
|
92
|
+
// 是否已部署(HEAD /module 可访问)
|
|
93
|
+
const ok = await core.microAppDeployed('disease-analysis')
|
|
93
94
|
```
|
|
94
95
|
|
|
95
|
-
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 三、Store 插件(状态同步)
|
|
99
|
+
|
|
100
|
+
在 Vuex 中注册 `baseSyncPlugin`,并在**子应用**中调用 `store.attachRouterSync(router)` 以同步路由。
|
|
101
|
+
|
|
102
|
+
### 父应用
|
|
96
103
|
|
|
97
104
|
```javascript
|
|
98
105
|
import Vuex from 'vuex'
|
|
99
106
|
import { baseSyncPlugin } from '@hhfenpm/micro-app'
|
|
107
|
+
import base from './store/modules/base' // 需含 base/SYNC_STATE
|
|
108
|
+
|
|
109
|
+
const store = new Vuex.Store({
|
|
110
|
+
modules: { base },
|
|
111
|
+
plugins: [baseSyncPlugin({ isParent: true, iframeSelector: '#microApp' })],
|
|
112
|
+
})
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 子应用
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
import { baseSyncPlugin } from '@hhfenpm/micro-app'
|
|
119
|
+
import base from './store/modules/base'
|
|
100
120
|
|
|
101
|
-
// 创建 Vuex Store
|
|
102
121
|
const store = new Vuex.Store({
|
|
103
|
-
modules: {
|
|
104
|
-
|
|
105
|
-
namespaced: true,
|
|
106
|
-
state: {
|
|
107
|
-
patient_id: null,
|
|
108
|
-
},
|
|
109
|
-
mutations: {
|
|
110
|
-
SYNC_STATE(state, payload) {
|
|
111
|
-
Object.assign(state, payload)
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
plugins: [
|
|
117
|
-
baseSyncPlugin({
|
|
118
|
-
isParent: false, // 子应用设为 false
|
|
119
|
-
iframeSelector: '#microApp',
|
|
120
|
-
}),
|
|
121
|
-
],
|
|
122
|
+
modules: { base },
|
|
123
|
+
plugins: [baseSyncPlugin({ isParent: false, iframeSelector: '#microApp' })],
|
|
122
124
|
})
|
|
123
125
|
|
|
124
|
-
// 子应用附加路由同步
|
|
125
126
|
import router from './router'
|
|
126
|
-
store.attachRouterSync(router)
|
|
127
|
+
store.attachRouterSync(router) // 必调,用于把子应用路由同步到父应用
|
|
127
128
|
```
|
|
128
129
|
|
|
129
|
-
|
|
130
|
+
`base` 模块需提供 `base/SYNC_STATE` mutation,用于接收并合并同步过来的 state。
|
|
131
|
+
|
|
132
|
+
---
|
|
130
133
|
|
|
131
|
-
|
|
134
|
+
## 四、生命周期
|
|
135
|
+
|
|
136
|
+
### 子应用
|
|
137
|
+
|
|
138
|
+
在子应用入口注册:
|
|
132
139
|
|
|
133
140
|
```javascript
|
|
134
|
-
// 注册生命周期钩子
|
|
135
141
|
window.__MICRO_APP_LIFECYCLE__ = {
|
|
136
|
-
mount(payload) {
|
|
137
|
-
|
|
138
|
-
},
|
|
139
|
-
update(payload) {
|
|
140
|
-
console.log('微前端已更新', payload)
|
|
141
|
-
},
|
|
142
|
-
unmount(payload) {
|
|
143
|
-
console.log('微前端已卸载', payload)
|
|
144
|
-
},
|
|
142
|
+
mount(payload) { /* 挂载后 */ },
|
|
143
|
+
update(payload) { /* 更新时,如路由变化 */ },
|
|
144
|
+
unmount(payload) { /* 卸载前 */ },
|
|
145
145
|
}
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
### 父应用
|
|
149
|
+
|
|
150
|
+
由 `baseSyncPlugin` 在 store 上挂载 `callMicroAppLifeCycle`,在 iframe 加载完成、路由变化、子应用切换时调用:
|
|
149
151
|
|
|
150
152
|
```javascript
|
|
151
|
-
|
|
152
|
-
store.callMicroAppLifeCycle('
|
|
153
|
-
store.callMicroAppLifeCycle('
|
|
154
|
-
store.callMicroAppLifeCycle('unmount', { /* payload */ })
|
|
153
|
+
store.callMicroAppLifeCycle('mount', { route: '/xxx' })
|
|
154
|
+
store.callMicroAppLifeCycle('update', { route: '/yyy' })
|
|
155
|
+
store.callMicroAppLifeCycle('unmount')
|
|
155
156
|
```
|
|
156
157
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
### Bridge
|
|
158
|
+
---
|
|
160
159
|
|
|
161
|
-
|
|
160
|
+
## API 一览
|
|
162
161
|
|
|
163
|
-
|
|
162
|
+
| 接口 | 说明 |
|
|
163
|
+
|------|------|
|
|
164
|
+
| `initBridge({ isParent, vm, iframeSelector?, handlers? })` | 初始化桥接;父应用传 `handlers`,子应用可访问 `vm.$base` |
|
|
165
|
+
| `createRegisterHandlers(getElectron?)` | 返回 `(vm) => ({ ui, cs })`,用作 `handlers` |
|
|
166
|
+
| `createMicroAppCore({ modelMap, enabledModules? })` | 返回 `{ microAppModule, microAppSrc, microAppDeployed }` |
|
|
167
|
+
| `baseSyncPlugin({ isParent, iframeSelector? })` | Vuex 插件,并挂载 `store.attachRouterSync`、`store.callMicroAppLifeCycle` |
|
|
164
168
|
|
|
165
|
-
|
|
166
|
-
- `options.isParent` (boolean): 是否为父应用
|
|
167
|
-
- `options.vm` (Object): Vue 实例
|
|
168
|
-
- `options.iframeSelector` (string): iframe 选择器,默认 `'#microApp'`
|
|
169
|
-
- `options.handlers` (Object): 处理器对象(父应用需要)
|
|
169
|
+
### 参数说明
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
- **initBridge**
|
|
172
|
+
- `isParent`: 是否父应用
|
|
173
|
+
- `vm`: Vue 实例(子应用会在其上挂 `vm.$base`、`vm.$baseReady`)
|
|
174
|
+
- `iframeSelector`: 父应用 iframe 选择器,默认 `'#microApp'`
|
|
175
|
+
- `handlers`: 仅父应用需要,`{ [namespace]: { [method]: (params)=>any } }`
|
|
172
176
|
|
|
173
|
-
|
|
177
|
+
- **createRegisterHandlers**
|
|
178
|
+
- `getElectron`: `() => electronModule`,可选;异常或未传时 `cs` 使用 noop
|
|
174
179
|
|
|
175
|
-
|
|
180
|
+
- **createMicroAppCore**
|
|
181
|
+
- `modelMap`: `() => ({ [moduleName]: path[] })`,必填
|
|
182
|
+
- `enabledModules`: `() => string[]` 或 `string[]`,可选;缺省时从 `window.GLOBAL_CONFIG.microApp` 读取
|
|
176
183
|
|
|
177
|
-
|
|
178
|
-
- `
|
|
179
|
-
- `
|
|
184
|
+
- **baseSyncPlugin**
|
|
185
|
+
- `isParent`: 是否父应用
|
|
186
|
+
- `iframeSelector`: 默认 `'#microApp'`
|
|
180
187
|
|
|
181
|
-
|
|
182
|
-
- `microAppModule(path)`: 根据路径获取模块名
|
|
183
|
-
- `microAppSrc(path)`: 生成完整 URL
|
|
184
|
-
- `microAppDeployed(module)`: 检测模块是否已部署
|
|
188
|
+
---
|
|
185
189
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
#### `baseSyncPlugin(options)`
|
|
189
|
-
|
|
190
|
-
创建状态同步插件。
|
|
190
|
+
## 注意事项
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
192
|
+
1. **同源**:postMessage 仅在同源下使用,需校验 `event.origin`。
|
|
193
|
+
2. **base 模块**:`baseSyncPlugin` 通过 `base/SYNC_STATE` 同步;`base` 的 state 结构需与约定一致。
|
|
194
|
+
3. **子应用必调**:`store.attachRouterSync(router)`,否则子应用路由不会回写到父应用 URL。
|
|
195
|
+
4. **Proxy**:`vm.$base` 依赖 Proxy,不支持 IE11。
|
|
195
196
|
|
|
196
|
-
|
|
197
|
+
---
|
|
197
198
|
|
|
198
|
-
|
|
199
|
-
- 需要支持 `postMessage` API
|
|
200
|
-
- 需要支持 `Proxy` API(IE 11 不支持)
|
|
199
|
+
## 兼容性
|
|
201
200
|
|
|
202
|
-
|
|
201
|
+
- 现代浏览器(Chrome、Firefox、Safari、Edge)
|
|
202
|
+
- 依赖 `postMessage`、`Proxy`
|
|
203
|
+
- Vue 2.6+ / 3.x,Vuex 3.x / 4.x(peerDependencies)
|
|
203
204
|
|
|
204
|
-
|
|
205
|
-
2. **状态同步**:状态同步使用深拷贝,避免引用污染
|
|
206
|
-
3. **生命周期**:子应用需要注册 `window.__MICRO_APP_LIFECYCLE__` 对象
|
|
207
|
-
4. **路由同步**:子应用需要调用 `store.attachRouterSync(router)` 附加路由同步
|
|
205
|
+
---
|
|
208
206
|
|
|
209
|
-
##
|
|
207
|
+
## 许可
|
|
210
208
|
|
|
211
209
|
MIT
|