@xingtukeji/micro 1.1.27 → 1.2.1
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 +172 -30
- package/dist/index.js +354 -271
- package/dist/types/api.d.ts +1 -0
- package/dist/types/components/XTMicroHost.vue.d.ts +5 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/parent.d.ts +20 -8
- package/dist/types/types.d.ts +6 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,55 +1,197 @@
|
|
|
1
|
-
|
|
1
|
+
# @xingtukeji/micro
|
|
2
|
+
|
|
3
|
+
基于 Vue 3 和 iframe 的微前端容器,支持应用注册、空闲预加载、保活切换、主子应用路由同步和生命周期通知。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @xingtukeji/micro
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 主应用接入
|
|
12
|
+
|
|
13
|
+
插件必须在 Pinia 等 token 依赖初始化完成后安装,并在 Host 挂载前注册所有子应用:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
// menu: [
|
|
17
|
+
// {
|
|
18
|
+
// title: "预加载子应用",
|
|
19
|
+
// type: "micro",
|
|
20
|
+
// microOptions: {
|
|
21
|
+
// url: "http://127.0.0.1:12001",
|
|
22
|
+
// name: "childapp",
|
|
23
|
+
// preload: true,
|
|
24
|
+
// keepAlive: true,
|
|
25
|
+
// },
|
|
26
|
+
// },
|
|
27
|
+
// ]
|
|
2
28
|
|
|
3
|
-
```javascript
|
|
4
|
-
//主微应用加载插件,注意一定要在 pinia 初始化之后
|
|
5
29
|
import xtMicro, { setupApp } from "@xingtukeji/micro";
|
|
30
|
+
|
|
6
31
|
app.use(xtMicro);
|
|
7
|
-
|
|
8
|
-
function traverseMenu(menu) {
|
|
9
|
-
// 遍历菜单项
|
|
32
|
+
|
|
33
|
+
function traverseMenu(menu: any[]) {
|
|
10
34
|
menu.forEach((item) => {
|
|
11
|
-
// 对微应用的菜单做处理
|
|
12
35
|
if (item.type === "micro") {
|
|
13
|
-
// 设置应用
|
|
14
36
|
setupApp({
|
|
15
37
|
...item.microOptions,
|
|
16
38
|
token: () => useUserStore().token,
|
|
17
|
-
params: item.microOptions?.params
|
|
39
|
+
params: item.microOptions?.params ?? {},
|
|
18
40
|
});
|
|
19
41
|
}
|
|
20
|
-
|
|
21
|
-
if (item.children) {
|
|
22
|
-
traverseMenu(item.children);
|
|
23
|
-
}
|
|
42
|
+
if (item.children) traverseMenu(item.children);
|
|
24
43
|
});
|
|
25
44
|
}
|
|
45
|
+
|
|
26
46
|
traverseMenu(window.$config.menus);
|
|
27
47
|
```
|
|
28
48
|
|
|
29
|
-
|
|
49
|
+
`setupApp` 配置:
|
|
50
|
+
|
|
51
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
52
|
+
| --- | --- | --- | --- |
|
|
53
|
+
| `name` | `string` | 必填 | 应用唯一名称 |
|
|
54
|
+
| `url` | `string` | 必填 | 子应用入口地址,支持相对地址 |
|
|
55
|
+
| `preload` | `boolean` | `false` | 浏览器空闲时预加载 |
|
|
56
|
+
| `keepAlive` | `boolean` | `false` | 切换离开后保留 iframe 和子应用内存状态 |
|
|
57
|
+
| `sync` | `boolean` | `true` | 将子应用路由同步到主应用 URL |
|
|
58
|
+
| `token` | `string \| () => string` | - | 注入子应用 URL 的 token |
|
|
59
|
+
| `params` | `Record<string, any>` | `{}` | 注入子应用 URL 的查询参数 |
|
|
60
|
+
| `onLoad` / `onUnload` / `onError` | `(event, app) => void` | - | iframe 生命周期回调 |
|
|
61
|
+
|
|
62
|
+
### 挂载 Host
|
|
63
|
+
|
|
64
|
+
推荐把 `XTMicroHost` 放在不会被路由销毁的布局中:
|
|
65
|
+
|
|
66
|
+
```vue
|
|
67
|
+
<script setup lang="ts">
|
|
68
|
+
import { computed } from "vue";
|
|
69
|
+
import { useRoute } from "vue-router";
|
|
70
|
+
import { XTMicroHost } from "@xingtukeji/micro";
|
|
71
|
+
|
|
72
|
+
const route = useRoute();
|
|
73
|
+
const activeMicroApp = computed(() =>
|
|
74
|
+
route.name === "micro" ? String(route.params.appId) : undefined
|
|
75
|
+
);
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<template>
|
|
79
|
+
<div class="content">
|
|
80
|
+
<XTMicroHost :active-app="activeMicroApp" />
|
|
81
|
+
<router-view v-show="!activeMicroApp" />
|
|
82
|
+
</div>
|
|
83
|
+
</template>
|
|
84
|
+
|
|
85
|
+
<style>
|
|
86
|
+
.content {
|
|
87
|
+
position: relative;
|
|
88
|
+
min-width: 0;
|
|
89
|
+
min-height: 0;
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`preload` 与 `keepAlive` 相互独立:`preload: true` 只表示浏览器空闲时提前加载(单个应用最多等待 15 秒);`keepAlive: true` 才会在切换离开后保留 iframe,并向子应用发送激活/失活通知。
|
|
30
95
|
|
|
31
|
-
```
|
|
32
|
-
|
|
96
|
+
```ts
|
|
97
|
+
setupApp({
|
|
98
|
+
name: "kept-app",
|
|
99
|
+
url: "http://127.0.0.1:12001",
|
|
100
|
+
preload: true,
|
|
101
|
+
keepAlive: true,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
setupApp({
|
|
105
|
+
name: "fresh-app",
|
|
106
|
+
url: "http://127.0.0.1:12002",
|
|
107
|
+
keepAlive: false,
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
保活会占用对应 iframe 的内存。刷新页面、调用 `reloadApp()` 或卸载 `XTMicroHost` 仍会重建 iframe,内存状态不会保留;需要跨刷新保存的数据应由子应用自行持久化。
|
|
112
|
+
|
|
113
|
+
`XTMicroView` 仅用于兼容旧接入方式:
|
|
114
|
+
|
|
115
|
+
```vue
|
|
116
|
+
<XTMicroView :app-id="appId" />
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
它会在组件卸载时销毁 iframe,不提供预加载和保活能力。
|
|
120
|
+
|
|
121
|
+
## 子应用接入
|
|
122
|
+
|
|
123
|
+
在创建 Vue 应用时调用 `microInit`。该方法在普通独立访问时也可安全调用:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
33
126
|
import { microInit } from "@xingtukeji/micro";
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
authHandler
|
|
37
|
-
|
|
38
|
-
|
|
127
|
+
|
|
128
|
+
await microInit({
|
|
129
|
+
authHandler(token) {
|
|
130
|
+
if (token) localStorage.setItem("token", token);
|
|
131
|
+
},
|
|
132
|
+
hideHeaderCssSelector: ["#app .app-header"],
|
|
133
|
+
onActivated() {
|
|
134
|
+
// 恢复轮询,并重新计算图表、地图等尺寸
|
|
135
|
+
},
|
|
136
|
+
onDeactivated() {
|
|
137
|
+
// 暂停轮询、动画等后台任务
|
|
39
138
|
},
|
|
40
|
-
//简易处理微应用环境下,隐藏 header
|
|
41
|
-
hideHeaderCssSelector: "#app ._hedaui-header",
|
|
42
139
|
});
|
|
43
140
|
```
|
|
44
141
|
|
|
45
|
-
|
|
46
|
-
|
|
142
|
+
| 参数 | 说明 |
|
|
143
|
+
| --- | --- |
|
|
144
|
+
| `authHandler` | 接收主应用传入的 token,支持异步函数 |
|
|
145
|
+
| `hideHeaderCssSelector` | 微应用模式下隐藏的 CSS 选择器,可传字符串或数组 |
|
|
146
|
+
| `onActivated` | iframe 被激活时调用,支持异步函数 |
|
|
147
|
+
| `onDeactivated` | iframe 被隐藏时调用,支持异步函数 |
|
|
47
148
|
|
|
48
|
-
|
|
49
|
-
|
|
149
|
+
## 常用 API
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import {
|
|
153
|
+
createAppUrl,
|
|
154
|
+
getApp,
|
|
155
|
+
getApps,
|
|
156
|
+
isMicro,
|
|
157
|
+
isParent,
|
|
158
|
+
reloadApp,
|
|
159
|
+
startApp,
|
|
160
|
+
stopApp,
|
|
161
|
+
} from "@xingtukeji/micro";
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
| API | 说明 |
|
|
165
|
+
| --- | --- |
|
|
166
|
+
| `getApp(name)` / `getApps()` | 获取已注册应用 |
|
|
167
|
+
| `startApp(name, options?)` | 挂载并激活应用 |
|
|
168
|
+
| `stopApp(name)` | 销毁应用 iframe |
|
|
169
|
+
| `reloadApp(name, isGoHome?)` | 刷新应用;`isGoHome` 为 `true` 时回到配置的入口地址 |
|
|
170
|
+
| `createAppUrl(targetUrl, appName?)` | 生成由主应用加载指定子应用页面的 URL |
|
|
171
|
+
| `isMicro()` / `isParent()` | 判断当前运行环境 |
|
|
172
|
+
|
|
173
|
+
## 路由同步与新标签页
|
|
174
|
+
|
|
175
|
+
`sync` 开启时,子应用路由会写入主应用查询参数 `__XT_MICRO_<应用名>`。需要在新标签页中仍由主应用加载子页面时,可使用:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const url = createAppUrl("/orders/123?tab=detail#section", "order-app");
|
|
179
|
+
window.open(url, "_blank");
|
|
50
180
|
```
|
|
51
181
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
182
|
+
手工拼接时,子应用地址必须经过 `encodeURIComponent`:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
const childUrl = encodeURIComponent("http://localhost:5173/page?tab=1#/detail");
|
|
186
|
+
const url = `${location.origin}/console/?__XT_MICRO_order-app=${childUrl}#/micro/order-app`;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 调试与运行时信息
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
window.micro_api.debug(true); // 开启调试日志
|
|
193
|
+
window.micro_api.debug(false); // 关闭调试日志
|
|
194
|
+
|
|
195
|
+
window.__XT_MICRO_VERSION; // 当前框架版本
|
|
196
|
+
window.__XT_MICRO_APP; // 当前微应用信息及主应用 location
|
|
55
197
|
```
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
(function(){try{if(typeof document<`u`){var e=document.createElement(`style`);e.appendChild(document.createTextNode(`.xt-micro{background-color:transparent;width:100%;height:100%;overflow:hidden}.micro-iframe{border:none;width:100%;height:100%;margin:0;padding:0}`)),document.head.appendChild(e)}}catch(e){console.error(`vite-plugin-css-injected-by-js`,e)}})();import { createElementBlock, defineComponent, mergeProps,
|
|
2
|
-
var __defProp = Object.defineProperty, __export = (
|
|
3
|
-
let
|
|
4
|
-
for (var
|
|
5
|
-
get:
|
|
1
|
+
(function(){try{if(typeof document<`u`){var e=document.createElement(`style`);e.appendChild(document.createTextNode(`.xt-micro{background-color:transparent;width:100%;height:100%;overflow:hidden}.micro-iframe{border:none;width:100%;height:100%;margin:0;padding:0}.xt-micro-host,.xt-micro-panel{position:absolute;top:0;bottom:0;left:0;right:0;overflow:hidden}.xt-micro-panel{visibility:hidden;pointer-events:none}.xt-micro-panel.is-active{visibility:visible;pointer-events:auto}`)),document.head.appendChild(e)}}catch(e){console.error(`vite-plugin-css-injected-by-js`,e)}})();import { Fragment, createElementBlock, defineComponent, mergeProps, nextTick, normalizeClass, onBeforeUnmount, onMounted, openBlock, ref, renderList, unref, watch } from "vue";
|
|
2
|
+
var __defProp = Object.defineProperty, __export = (s) => {
|
|
3
|
+
let I = {};
|
|
4
|
+
for (var L in s) __defProp(I, L, {
|
|
5
|
+
get: s[L],
|
|
6
6
|
enumerable: !0
|
|
7
7
|
});
|
|
8
|
-
return
|
|
8
|
+
return I;
|
|
9
9
|
};
|
|
10
10
|
const CONSTANT = {
|
|
11
11
|
KEY: "$xtm",
|
|
@@ -17,7 +17,7 @@ const CONSTANT = {
|
|
|
17
17
|
DOM_ID_PREFIX: "xt-micro-ifr-",
|
|
18
18
|
URL_PARAM_PREFIX: "__XT_MICRO_",
|
|
19
19
|
MICRO_VERSION: "__XT_MICRO_VERSION"
|
|
20
|
-
}, version = "1.1
|
|
20
|
+
}, version = "1.2.1";
|
|
21
21
|
var utils_exports = /* @__PURE__ */ __export({
|
|
22
22
|
ConsoleUtil: () => ConsoleUtil,
|
|
23
23
|
addOrReplaceUrlParam: () => addOrReplaceUrlParam,
|
|
@@ -28,247 +28,279 @@ var utils_exports = /* @__PURE__ */ __export({
|
|
|
28
28
|
getQueryParameter: () => getQueryParameter,
|
|
29
29
|
ipcSyncAppInfo: () => ipcSyncAppInfo
|
|
30
30
|
});
|
|
31
|
-
function getQueryParameter(
|
|
32
|
-
|
|
33
|
-
var
|
|
34
|
-
return
|
|
31
|
+
function getQueryParameter(s, I = window.location.href) {
|
|
32
|
+
s = s.replace(/[\[\]]/g, "\\$&");
|
|
33
|
+
var L = (/* @__PURE__ */ RegExp("[?&]" + s + "(=([^&#]*)|&|#|$)")).exec(I);
|
|
34
|
+
return L ? L[2] ? decodeURIComponent(L[2].replace(/\+/g, " ")).trim() : "" : null;
|
|
35
35
|
}
|
|
36
|
-
function getAbsolutePath(
|
|
36
|
+
function getAbsolutePath(s, I, L) {
|
|
37
37
|
try {
|
|
38
|
-
return
|
|
38
|
+
return s && (L && s.startsWith("#") ? s : new URL(s, I).href);
|
|
39
39
|
} catch {
|
|
40
|
-
return
|
|
40
|
+
return s;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
function anchorElementGenerator(
|
|
44
|
-
let
|
|
45
|
-
return
|
|
43
|
+
function anchorElementGenerator(s) {
|
|
44
|
+
let I = window.document.createElement("a");
|
|
45
|
+
return I.href = s, I.href = I.href, I;
|
|
46
46
|
}
|
|
47
|
-
function getAnchorElementQueryMap(
|
|
48
|
-
let
|
|
49
|
-
return [...new URLSearchParams(
|
|
47
|
+
function getAnchorElementQueryMap(s) {
|
|
48
|
+
let I = s.search || "";
|
|
49
|
+
return [...new URLSearchParams(I).entries()].reduce((s, I) => (s[I[0]] = I[1], s), {});
|
|
50
50
|
}
|
|
51
|
-
function debounce(
|
|
52
|
-
let
|
|
53
|
-
return function(...
|
|
54
|
-
let
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
},
|
|
51
|
+
function debounce(s, I) {
|
|
52
|
+
let L = null;
|
|
53
|
+
return function(...R) {
|
|
54
|
+
let z = this;
|
|
55
|
+
L && clearTimeout(L), L = setTimeout(() => {
|
|
56
|
+
s.apply(z, R);
|
|
57
|
+
}, I);
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
function addOrReplaceUrlParam(
|
|
61
|
-
let [
|
|
62
|
-
return
|
|
60
|
+
function addOrReplaceUrlParam(s, I, L) {
|
|
61
|
+
let [R, z] = s.split("#"), B = new URL(R), V = B.searchParams;
|
|
62
|
+
return I = CONSTANT.URL_PARAM_PREFIX + I, V.has(I) ? V.set(I, L) : V.append(I, L), z && (B.hash = z), B.search = V.toString(), ConsoleUtil.trace("urlObj", B), B.origin + B.pathname + B.search + B.hash;
|
|
63
63
|
}
|
|
64
|
-
const ipcSyncAppInfo = async (
|
|
65
|
-
window.
|
|
66
|
-
|
|
67
|
-
}),
|
|
64
|
+
const ipcSyncAppInfo = async (s) => new Promise((I, L) => {
|
|
65
|
+
let R = window.setTimeout(() => {
|
|
66
|
+
window.removeEventListener("message", z), L(/* @__PURE__ */ Error(`micro app info timeout: ${s}`));
|
|
67
|
+
}, 1e4), z = (L) => {
|
|
68
|
+
ConsoleUtil.trace("child ipcSyncAppInfo receive message", L.data), L.source === window.parent && L.data?.cmd === "$xt/micro/info" && L.data?.data?.name === s && L.data?.data?.mainLocation?.origin === L.origin && (window.clearTimeout(R), window.removeEventListener("message", z), L.data.data.mainMicroVersion !== "1.2.1" && ConsoleUtil.warn(`子应用版本与主应用版本不一致,${s}子应用版本:${version},主应用版本:${L.data.data.mainMicroVersion}`), I(L.data.data));
|
|
69
|
+
};
|
|
70
|
+
window.addEventListener("message", z), ConsoleUtil.trace("child ipcSyncAppInfo send message", s), window.parent.postMessage({
|
|
68
71
|
cmd: "$xt/micro/info",
|
|
69
|
-
data:
|
|
72
|
+
data: s
|
|
70
73
|
}, "*");
|
|
71
74
|
});
|
|
72
|
-
var ConsoleUtil = class
|
|
75
|
+
var ConsoleUtil = class s {
|
|
73
76
|
static STORAGE_KEY = "@xt/micro/console/enable";
|
|
74
77
|
static get enable() {
|
|
75
|
-
return localStorage.getItem(
|
|
78
|
+
return localStorage.getItem(s.STORAGE_KEY) === "true";
|
|
76
79
|
}
|
|
77
|
-
static setEnable(
|
|
78
|
-
localStorage.setItem(
|
|
80
|
+
static setEnable(I) {
|
|
81
|
+
localStorage.setItem(s.STORAGE_KEY, I.toString());
|
|
79
82
|
}
|
|
80
83
|
static getEnable() {
|
|
81
|
-
return
|
|
84
|
+
return s.enable;
|
|
82
85
|
}
|
|
83
86
|
static getCallerInfo() {
|
|
84
87
|
try {
|
|
85
|
-
let
|
|
86
|
-
if (
|
|
87
|
-
let
|
|
88
|
-
if (
|
|
89
|
-
let [,
|
|
90
|
-
return `[${
|
|
88
|
+
let s = /* @__PURE__ */ ((/* @__PURE__ */ Error()).stack || "").split("\n").slice(4);
|
|
89
|
+
if (s.length === 0) return "unknown location";
|
|
90
|
+
let I = s[0].trim(), L = I.match(/(?:http[s]?:\/\/.*?\/|)([^:]+):(\d+):(\d+)/);
|
|
91
|
+
if (L) {
|
|
92
|
+
let [, s, I] = L;
|
|
93
|
+
return `[${s.split("/").slice(-2).join("/")}:${I}]`;
|
|
91
94
|
}
|
|
92
|
-
return `[${
|
|
95
|
+
return `[${I}]`;
|
|
93
96
|
} catch {
|
|
94
97
|
return "[unknown location]";
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
|
-
static _log(
|
|
98
|
-
if (
|
|
99
|
-
let
|
|
100
|
-
console[
|
|
100
|
+
static _log(I, ...L) {
|
|
101
|
+
if (s.enable && typeof console[I] == "function") {
|
|
102
|
+
let s = this.getCallerInfo();
|
|
103
|
+
console[I](s, ...L);
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
|
-
static log(...
|
|
104
|
-
this._log("log", ...
|
|
106
|
+
static log(...s) {
|
|
107
|
+
this._log("log", ...s);
|
|
105
108
|
}
|
|
106
|
-
static info(...
|
|
107
|
-
this._log("info", ...
|
|
109
|
+
static info(...s) {
|
|
110
|
+
this._log("info", ...s);
|
|
108
111
|
}
|
|
109
|
-
static warn(...
|
|
110
|
-
this._log("warn", ...
|
|
112
|
+
static warn(...s) {
|
|
113
|
+
this._log("warn", ...s);
|
|
111
114
|
}
|
|
112
|
-
static error(...
|
|
113
|
-
this._log("error", ...
|
|
115
|
+
static error(...s) {
|
|
116
|
+
this._log("error", ...s);
|
|
114
117
|
}
|
|
115
|
-
static debug(...
|
|
116
|
-
this._log("debug", ...
|
|
118
|
+
static debug(...s) {
|
|
119
|
+
this._log("debug", ...s);
|
|
117
120
|
}
|
|
118
|
-
static trace(...
|
|
119
|
-
this._log("trace", ...
|
|
121
|
+
static trace(...s) {
|
|
122
|
+
this._log("trace", ...s);
|
|
120
123
|
}
|
|
121
|
-
static table(
|
|
122
|
-
this.enable && console.table(
|
|
124
|
+
static table(s, I) {
|
|
125
|
+
this.enable && console.table(s, I);
|
|
123
126
|
}
|
|
124
|
-
static time(
|
|
125
|
-
this.enable && console.time(
|
|
127
|
+
static time(s) {
|
|
128
|
+
this.enable && console.time(s);
|
|
126
129
|
}
|
|
127
|
-
static timeEnd(
|
|
128
|
-
this.enable && console.timeEnd(
|
|
130
|
+
static timeEnd(s) {
|
|
131
|
+
this.enable && console.timeEnd(s);
|
|
129
132
|
}
|
|
130
133
|
}, _isMicro = ref(!1), descriptor = Object.getOwnPropertyDescriptor(window, CONSTANT.IS_MICRO);
|
|
131
134
|
descriptor ? descriptor.configurable ? Object.defineProperty(window, "__XT_MICRO", {
|
|
132
135
|
get: () => _isMicro.value,
|
|
133
|
-
set: (
|
|
134
|
-
_isMicro.value =
|
|
136
|
+
set: (s) => {
|
|
137
|
+
_isMicro.value = s;
|
|
135
138
|
},
|
|
136
139
|
configurable: !0,
|
|
137
140
|
enumerable: !0
|
|
138
141
|
}) : console.warn("__XT_MICRO 不可配置,无法重定义,已跳过") : Object.defineProperty(window, "__XT_MICRO", {
|
|
139
142
|
get: () => _isMicro.value,
|
|
140
|
-
set: (
|
|
141
|
-
_isMicro.value =
|
|
143
|
+
set: (s) => {
|
|
144
|
+
_isMicro.value = s;
|
|
142
145
|
},
|
|
143
146
|
configurable: !0,
|
|
144
147
|
enumerable: !0
|
|
145
148
|
});
|
|
146
|
-
var generateId = (
|
|
147
|
-
function
|
|
148
|
-
return typeof
|
|
149
|
-
}
|
|
150
|
-
let
|
|
151
|
-
if (!
|
|
152
|
-
let
|
|
153
|
-
if (
|
|
154
|
-
ConsoleUtil.log("获取绝对路径",
|
|
155
|
-
let
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}),
|
|
149
|
+
var generateId = (s) => `${CONSTANT.DOM_ID_PREFIX}${s}`, generateURL = (s, I = !1) => {
|
|
150
|
+
function L(s) {
|
|
151
|
+
return typeof s == "object" && !!s && !Array.isArray(s);
|
|
152
|
+
}
|
|
153
|
+
let R = typeof s.params == "function" ? s.params() : L(s.params) ? s.params : {}, z = typeof s.token == "function" ? s.token() : s.token || "", B = new URL(s.url, window.location.origin), V = getQueryParameter(CONSTANT.URL_PARAM_PREFIX + s.name);
|
|
154
|
+
if (!I && V) {
|
|
155
|
+
let I = getAbsolutePath(V, B.origin, !0);
|
|
156
|
+
if (I) {
|
|
157
|
+
ConsoleUtil.log("获取绝对路径", I, s);
|
|
158
|
+
let L = new URL(I, B.origin);
|
|
159
|
+
L.searchParams.forEach((s, I) => {
|
|
160
|
+
B.searchParams.set(I, s);
|
|
161
|
+
}), B.hash = L.hash;
|
|
159
162
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
g.remove();
|
|
163
|
+
}
|
|
164
|
+
if (B.searchParams.set(CONSTANT.IS_MICRO, "true"), B.searchParams.set(CONSTANT.MICRO_NAME, s.name), z && B.searchParams.set(CONSTANT.MICRO_TOKEN, z), R) for (let s of Object.keys(R)) B.searchParams.set(s, R[s]);
|
|
165
|
+
return B.href;
|
|
166
|
+
}, generateLoading = (s) => {
|
|
167
|
+
ConsoleUtil.log("generateLoading", s);
|
|
168
|
+
let I = document.createElement("div");
|
|
169
|
+
return I.id = generateId(s) + "-loading", I.innerHTML = "应用加载中...", I.style.textAlign = "center", I.style.lineHeight = "100px", I.style.fontSize = "20px", I.style.color = "#999", I.style.position = "absolute", I.style.top = "0", I.style.left = "0", I.style.right = "0", I.style.bottom = "0", I.style.zIndex = "999", I.style.background = "transparent", I.style["mix-blend-mode"] = "difference", I;
|
|
170
|
+
}, removeLoading = (s) => {
|
|
171
|
+
s.style.opacity = "0", setTimeout(() => {
|
|
172
|
+
document.querySelectorAll("#" + s.id).forEach((s) => {
|
|
173
|
+
s.remove();
|
|
172
174
|
});
|
|
173
175
|
}, 500);
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
});
|
|
182
|
-
return V.observe(g.panel.parentNode, {
|
|
183
|
-
childList: !0,
|
|
184
|
-
subtree: !1
|
|
185
|
-
}), B;
|
|
176
|
+
}, activeMicroApp;
|
|
177
|
+
const getActiveMicroApp = () => activeMicroApp, setActiveMicroApp = (s) => {
|
|
178
|
+
activeMicroApp = s;
|
|
179
|
+
};
|
|
180
|
+
var generateIframe = (s) => {
|
|
181
|
+
let I = document.createElement("iframe");
|
|
182
|
+
return I.id = generateId(s.app.name), I.src = generateURL(s.app), I.style.width = "100%", I.style.height = "100%", I.style.border = "none", I.style.margin = "0", I.style.padding = "0", I.style.backgroundColor = "transparent", I.style["color-scheme"] = "unset", I.style.visibility = "hidden", I.addEventListener("load", (I) => s.onLoad.call(s, I)), I.addEventListener("error", (I) => s.onError.call(s, I)), I.addEventListener("unload", (I) => s.onUnload.call(s, I)), I;
|
|
186
183
|
}, MicroApp = class {
|
|
187
184
|
app;
|
|
188
185
|
dom;
|
|
189
186
|
panel;
|
|
190
187
|
loading;
|
|
191
188
|
loadingTimer;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
} else
|
|
189
|
+
state = "idle";
|
|
190
|
+
active = !1;
|
|
191
|
+
loadPromise;
|
|
192
|
+
resolveLoad;
|
|
193
|
+
observer;
|
|
194
|
+
destroying = !1;
|
|
195
|
+
constructor(s) {
|
|
196
|
+
return this.app = s, this.dom = void 0, this.panel = void 0, this;
|
|
197
|
+
}
|
|
198
|
+
getPanel(s) {
|
|
199
|
+
let I;
|
|
200
|
+
if (s) {
|
|
201
|
+
if (I = typeof s == "string" ? document.querySelector(s) : s, !I) throw Error(`没有找到微应用容器: ${s}`);
|
|
202
|
+
} else I = document.body;
|
|
203
|
+
return I;
|
|
204
|
+
}
|
|
205
|
+
ensureLoaded(s) {
|
|
206
|
+
let I = this.getPanel(s);
|
|
207
|
+
if (this.dom) {
|
|
208
|
+
if (this.panel !== I) throw Error(`微应用 ${this.app.name} 已挂载到其他容器`);
|
|
209
|
+
return this.loadPromise || Promise.resolve();
|
|
210
|
+
}
|
|
211
|
+
this.panel = I, this.state = "loading", this.loadPromise = new Promise((s) => this.resolveLoad = s);
|
|
212
|
+
let L = generateIframe(this);
|
|
213
|
+
return this.dom = L, this.observer = new MutationObserver((s) => {
|
|
214
|
+
!this.destroying && s.some((s) => Array.from(s.removedNodes).includes(L)) && (this.reset(), this.onUnload(new Event("unload")));
|
|
215
|
+
}), this.observer.observe(I, { childList: !0 }), I.appendChild(L), this.loadPromise;
|
|
216
|
+
}
|
|
217
|
+
showLoading() {
|
|
218
|
+
!this.panel || this.loading || (this.loading = generateLoading(this.app.name), this.panel.appendChild(this.loading));
|
|
219
|
+
}
|
|
220
|
+
mount(s) {
|
|
221
|
+
return this.activate(s);
|
|
222
|
+
}
|
|
223
|
+
preload(s) {
|
|
224
|
+
return ConsoleUtil.trace("preload started", this.app.name), this.active = !1, this.ensureLoaded(s);
|
|
225
|
+
}
|
|
226
|
+
activate(s) {
|
|
227
|
+
this.state === "error" && this.destroy(), this.active = !0, setActiveMicroApp(this.app.name);
|
|
228
|
+
let I = this.ensureLoaded(s);
|
|
229
|
+
return this.state === "loading" && this.showLoading(), this.dom && (this.dom.style.visibility = "visible"), (this.state === "loaded" || this.state === "active") && (this.state = "active", this.postLifecycle("activated")), ConsoleUtil.trace("app activated", this.app.name), I;
|
|
230
|
+
}
|
|
231
|
+
deactivate() {
|
|
232
|
+
!this.dom || !this.active || (this.active = !1, this.dom && (this.dom.style.visibility = "hidden"), this.state === "active" && (this.state = "loaded"), this.postLifecycle("deactivated"), ConsoleUtil.trace("app deactivated", this.app.name));
|
|
206
233
|
}
|
|
207
234
|
unmount() {
|
|
208
|
-
|
|
209
|
-
let g = document.getElementById(generateId(this.app.name));
|
|
210
|
-
if (g) this.app.preload ? (g.style.display = "none", document.body.appendChild(g)) : this.panel?.removeChild(g);
|
|
211
|
-
else throw Error("app dom not found");
|
|
235
|
+
this.destroy();
|
|
212
236
|
}
|
|
213
|
-
preloadRender(
|
|
214
|
-
this.
|
|
237
|
+
preloadRender(s) {
|
|
238
|
+
return this.activate(s);
|
|
215
239
|
}
|
|
216
|
-
|
|
217
|
-
this.
|
|
240
|
+
destroy() {
|
|
241
|
+
this.dom && (ConsoleUtil.trace("app destroyed", this.app.name), this.destroying = !0, this.observer?.disconnect(), this.dom.remove(), this.onUnload(new Event("unload")), this.reset(), getActiveMicroApp() === this.app.name && setActiveMicroApp(), this.destroying = !1);
|
|
218
242
|
}
|
|
219
|
-
reload(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
243
|
+
reload(s = !1) {
|
|
244
|
+
if (!this.dom) throw Error(`app dom not found: ${this.app.name}`);
|
|
245
|
+
let I = this.dom.src;
|
|
246
|
+
s && (I = generateURL(this.app, !0), ConsoleUtil.trace("go home", I)), ConsoleUtil.trace("reload app", this.app, I);
|
|
247
|
+
let L = new URL(I);
|
|
248
|
+
L.searchParams.set("__t", Date.now().toString()), this.dom.style.visibility = "hidden", this.state = "loading", this.loadPromise = new Promise((s) => this.resolveLoad = s), this.active && this.showLoading(), this.dom.src = L.toString();
|
|
224
249
|
}
|
|
225
|
-
changeOptions(
|
|
226
|
-
ConsoleUtil.trace("changeOptions", this.app,
|
|
250
|
+
changeOptions(s) {
|
|
251
|
+
ConsoleUtil.trace("changeOptions", this.app, s), this.app = {
|
|
227
252
|
...this.app,
|
|
228
|
-
...
|
|
253
|
+
...s
|
|
229
254
|
};
|
|
230
255
|
}
|
|
231
|
-
onLoad(
|
|
232
|
-
ConsoleUtil.trace("app onLoad", this.app.name, this.loadingTimer, this.loading), this.loadingTimer && clearTimeout(this.loadingTimer), this.loading && removeLoading(this.loading), _postMicro(this), ConsoleUtil.trace("this.app.onLoad", this.app.onLoad), this.app.onLoad && this.app.onLoad(
|
|
256
|
+
onLoad(s) {
|
|
257
|
+
ConsoleUtil.trace("app onLoad", this.app.name, this.loadingTimer, this.loading), this.loadingTimer && clearTimeout(this.loadingTimer), this.loading && removeLoading(this.loading), this.loading = void 0, this.state = this.active ? "active" : "loaded", this.dom && (this.dom.style.visibility = this.active ? "visible" : "hidden"), _postMicro(this), this.active && this.postLifecycle("activated"), this.resolveLoad?.(), this.resolveLoad = void 0, ConsoleUtil.trace("preload loaded", this.app.name), ConsoleUtil.trace("this.app.onLoad", this.app.onLoad), this.app.onLoad && this.app.onLoad(s, this);
|
|
258
|
+
}
|
|
259
|
+
onUnload(s) {
|
|
260
|
+
ConsoleUtil.trace("app onUnload", this.app.name), getActiveMicroApp() === this.app.name && clearParentUrl(this.app.name), this.app.onUnload && this.app.onUnload(s, this);
|
|
233
261
|
}
|
|
234
|
-
|
|
235
|
-
|
|
262
|
+
onError(s) {
|
|
263
|
+
this.state = "error", this.resolveLoad?.(), this.resolveLoad = void 0, ConsoleUtil.error("app onError", this.app.name), this.app.onError && this.app.onError(s, this);
|
|
236
264
|
}
|
|
237
|
-
|
|
238
|
-
|
|
265
|
+
postLifecycle(s) {
|
|
266
|
+
this.dom?.contentWindow?.postMessage({ cmd: `$xt/micro/${this.app.name}/${s}` }, new URL(this.app.url, window.location.origin).origin);
|
|
239
267
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
268
|
+
reset() {
|
|
269
|
+
this.observer?.disconnect(), this.observer = void 0, this.dom = void 0, this.panel = void 0, this.loading = void 0, this.loadPromise = void 0, this.resolveLoad = void 0, this.state = "idle", this.active = !1;
|
|
270
|
+
}
|
|
271
|
+
}, _postMicro = (s) => {
|
|
272
|
+
s.dom?.contentWindow?.postMessage({
|
|
273
|
+
cmd: `$xt/micro/${s.app.name}`,
|
|
243
274
|
data: {
|
|
244
|
-
name:
|
|
245
|
-
url:
|
|
246
|
-
preload:
|
|
247
|
-
sync:
|
|
275
|
+
name: s.app.name,
|
|
276
|
+
url: s.app.url,
|
|
277
|
+
preload: s.app.preload,
|
|
278
|
+
sync: s.app.sync ?? !0
|
|
248
279
|
}
|
|
249
|
-
},
|
|
250
|
-
};
|
|
280
|
+
}, new URL(s.app.url, window.location.origin).origin);
|
|
281
|
+
}, initialized = !1;
|
|
251
282
|
const mainMicroInit = () => {
|
|
252
|
-
window[CONSTANT.MICRO_TYPE] = "parent", window.addEventListener("message", (
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
283
|
+
initialized || (initialized = !0, window[CONSTANT.MICRO_TYPE] = "parent", window.addEventListener("message", (s) => {
|
|
284
|
+
if (s.data?.cmd === "$xt/micro/sync") {
|
|
285
|
+
let I = getApp(s.data?.data?.name);
|
|
286
|
+
if (!isAppMessage(s, I) || getActiveMicroApp() !== I.name) return;
|
|
287
|
+
ConsoleUtil.trace("父页面接受子应用同步路由信息", s.data);
|
|
288
|
+
let L = [
|
|
256
289
|
CONSTANT.IS_MICRO,
|
|
257
290
|
CONSTANT.MICRO_NAME,
|
|
258
291
|
CONSTANT.MICRO_TOKEN
|
|
259
|
-
],
|
|
260
|
-
for (let
|
|
261
|
-
ConsoleUtil.trace("tempUrl",
|
|
262
|
-
let
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
ConsoleUtil.trace("
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
g.source.postMessage({
|
|
292
|
+
], R = new URL(window.decodeURIComponent(s.data.data.url), s.origin);
|
|
293
|
+
for (let s of L) R.searchParams.delete(s);
|
|
294
|
+
ConsoleUtil.trace("tempUrl", R);
|
|
295
|
+
let z = clearParentUrl(s.data.data.name), B = new URL(z);
|
|
296
|
+
ConsoleUtil.trace("mainURL.href", B.href);
|
|
297
|
+
let V = addOrReplaceUrlParam(B.href, s.data.data.name, R.href);
|
|
298
|
+
ConsoleUtil.trace("curUrl", V), window.history.replaceState(window.history.state, "", V);
|
|
299
|
+
} else if (s.data?.cmd === "$xt/micro/info") {
|
|
300
|
+
ConsoleUtil.trace("parent 「$xt/micro/info」 receive message", s.data);
|
|
301
|
+
let I = getApp(s.data.data);
|
|
302
|
+
if (!isAppMessage(s, I)) return;
|
|
303
|
+
s.source.postMessage({
|
|
272
304
|
cmd: "$xt/micro/info",
|
|
273
305
|
data: {
|
|
274
306
|
mainLocation: {
|
|
@@ -283,147 +315,198 @@ const mainMicroInit = () => {
|
|
|
283
315
|
protocol: window.location.protocol
|
|
284
316
|
},
|
|
285
317
|
mainMicroVersion: version,
|
|
286
|
-
name:
|
|
287
|
-
url:
|
|
288
|
-
params:
|
|
289
|
-
sync:
|
|
290
|
-
preload:
|
|
318
|
+
name: I.name,
|
|
319
|
+
url: I.url,
|
|
320
|
+
params: I.params,
|
|
321
|
+
sync: I.sync,
|
|
322
|
+
preload: I.preload
|
|
291
323
|
}
|
|
292
|
-
}, { targetOrigin:
|
|
324
|
+
}, { targetOrigin: s.origin });
|
|
293
325
|
}
|
|
294
|
-
});
|
|
295
|
-
}
|
|
326
|
+
}));
|
|
327
|
+
};
|
|
328
|
+
var isAppMessage = (s, I) => {
|
|
329
|
+
if (!I?.instance.dom?.contentWindow) return !1;
|
|
330
|
+
let L = new URL(I.url, window.location.origin).origin;
|
|
331
|
+
return s.source === I.instance.dom.contentWindow && s.origin === L;
|
|
332
|
+
};
|
|
333
|
+
const microInit = async (s = {}) => {
|
|
296
334
|
window[CONSTANT.MICRO_TYPE] = "child";
|
|
297
|
-
let
|
|
298
|
-
if (
|
|
299
|
-
function
|
|
300
|
-
var
|
|
301
|
-
if (!
|
|
302
|
-
var
|
|
303
|
-
document.head.appendChild(
|
|
335
|
+
let I = getQueryParameter(CONSTANT.IS_MICRO), L = getQueryParameter(CONSTANT.MICRO_NAME), R = getQueryParameter(CONSTANT.MICRO_TOKEN);
|
|
336
|
+
if (s.authHandler && await s.authHandler(R), ConsoleUtil.trace("child microInit", I, L), I && (window[CONSTANT.IS_MICRO] = I === "true", L && await syncAppInfo(L)), window[CONSTANT.IS_MICRO]) {
|
|
337
|
+
function I(s) {
|
|
338
|
+
var I = document.styleSheets[0];
|
|
339
|
+
if (!I) {
|
|
340
|
+
var L = document.createElement("style");
|
|
341
|
+
document.head.appendChild(L), I = L.sheet;
|
|
304
342
|
}
|
|
305
|
-
|
|
343
|
+
I.insertRule(s, I.cssRules.length);
|
|
306
344
|
}
|
|
307
|
-
window[CONSTANT.IS_MICRO] &&
|
|
308
|
-
|
|
309
|
-
}) :
|
|
310
|
-
|
|
311
|
-
});
|
|
345
|
+
window[CONSTANT.IS_MICRO] && s.hideHeaderCssSelector && (Array.isArray(s.hideHeaderCssSelector) ? s.hideHeaderCssSelector.forEach((s) => {
|
|
346
|
+
I(`${s} { display: none !important; }`);
|
|
347
|
+
}) : I(`${s.hideHeaderCssSelector} { display: none !important; }`)), await patchIframeHistory(L, window), window.addEventListener("message", async (I) => {
|
|
348
|
+
I.source === window.parent && I.origin === window[CONSTANT.MICRO_APP]?.mainLocation.origin && I.data?.cmd === `$xt/micro/${L}` ? syncUrlToWindow(L) : I.source === window.parent && I.origin === window[CONSTANT.MICRO_APP]?.mainLocation.origin && I.data?.cmd === `$xt/micro/${L}/activated` ? (await syncUrlToWindow(L), await s.onActivated?.()) : I.source === window.parent && I.origin === window[CONSTANT.MICRO_APP]?.mainLocation.origin && I.data?.cmd === `$xt/micro/${L}/deactivated` && await s.onDeactivated?.();
|
|
349
|
+
}), L && await syncUrlToWindow(L);
|
|
312
350
|
} else ConsoleUtil.warn("当前环境非微应用环境");
|
|
313
351
|
};
|
|
314
|
-
function patchIframeHistory(
|
|
315
|
-
let
|
|
316
|
-
|
|
317
|
-
let
|
|
318
|
-
...
|
|
319
|
-
...
|
|
352
|
+
function patchIframeHistory(s, I) {
|
|
353
|
+
let L = I.history, R = L.pushState, z = L.replaceState;
|
|
354
|
+
L.pushState = function(I, z, B) {
|
|
355
|
+
let V = {
|
|
356
|
+
...L.state || {},
|
|
357
|
+
...I,
|
|
320
358
|
_patchedByParent: !0
|
|
321
359
|
};
|
|
322
|
-
|
|
323
|
-
},
|
|
324
|
-
let
|
|
325
|
-
...
|
|
326
|
-
...
|
|
360
|
+
R.call(L, V, z, B), syncUrlToWindow(s);
|
|
361
|
+
}, L.replaceState = function(s, I, R) {
|
|
362
|
+
let B = {
|
|
363
|
+
...L.state || {},
|
|
364
|
+
...s,
|
|
327
365
|
_patchedByParent: !0
|
|
328
366
|
};
|
|
329
|
-
|
|
367
|
+
z.call(L, B, I, R);
|
|
330
368
|
};
|
|
331
369
|
}
|
|
332
|
-
var syncAppInfo = async (
|
|
370
|
+
var syncAppInfo = async (s) => await ipcSyncAppInfo(s).then((s) => {
|
|
333
371
|
window[CONSTANT.MICRO_APP] = {
|
|
334
372
|
microVersion: version,
|
|
335
|
-
...
|
|
373
|
+
...s
|
|
336
374
|
};
|
|
337
375
|
});
|
|
338
|
-
async function syncUrlToWindow(
|
|
339
|
-
|
|
340
|
-
let { name:
|
|
341
|
-
|
|
376
|
+
async function syncUrlToWindow(s) {
|
|
377
|
+
ConsoleUtil.trace("syncUrlToWindow", s, window[CONSTANT.MICRO_APP]), window[CONSTANT.MICRO_APP] || await syncAppInfo(s);
|
|
378
|
+
let { name: I, sync: L, mainLocation: R } = window[CONSTANT.MICRO_APP];
|
|
379
|
+
if (!L) return;
|
|
380
|
+
let z = window.location.pathname + window.location.search + window.location.hash;
|
|
381
|
+
ConsoleUtil.trace("curUrl", z), ConsoleUtil.trace("child", "「$xt/micro/sync」", "send", I, z), window.parent.postMessage({
|
|
342
382
|
cmd: "$xt/micro/sync",
|
|
343
383
|
data: {
|
|
344
|
-
name:
|
|
345
|
-
url: window.encodeURIComponent(
|
|
384
|
+
name: I,
|
|
385
|
+
url: window.encodeURIComponent(z)
|
|
346
386
|
}
|
|
347
|
-
},
|
|
387
|
+
}, R.origin);
|
|
348
388
|
}
|
|
349
389
|
var _apps = {}, defaultAppOption = {
|
|
350
390
|
url: "",
|
|
351
391
|
name: "",
|
|
352
392
|
sync: !0,
|
|
353
|
-
preload: !1
|
|
393
|
+
preload: !1,
|
|
394
|
+
keepAlive: !1
|
|
354
395
|
};
|
|
355
|
-
const setupApp = (
|
|
356
|
-
if (!
|
|
357
|
-
ConsoleUtil.error("app url is required",
|
|
396
|
+
const setupApp = (s) => {
|
|
397
|
+
if (!s.url || s.url === "" || s.url === "undefined") {
|
|
398
|
+
ConsoleUtil.error("app url is required", s);
|
|
358
399
|
return;
|
|
359
400
|
}
|
|
360
|
-
let
|
|
361
|
-
return
|
|
362
|
-
...
|
|
363
|
-
...
|
|
364
|
-
} : _apps[
|
|
365
|
-
...
|
|
366
|
-
instance: new MicroApp(
|
|
367
|
-
}, _apps[
|
|
368
|
-
}, getApp = (
|
|
369
|
-
var setApp = (
|
|
370
|
-
...
|
|
371
|
-
...
|
|
401
|
+
let I = Object.assign({}, defaultAppOption, s), L = _apps[s.name];
|
|
402
|
+
return L ? (L.instance.changeOptions(I), _apps[s.name] = {
|
|
403
|
+
...L,
|
|
404
|
+
...I
|
|
405
|
+
}) : _apps[s.name] = {
|
|
406
|
+
...I,
|
|
407
|
+
instance: new MicroApp(s)
|
|
408
|
+
}, _apps[s.name];
|
|
409
|
+
}, getApp = (s) => _apps[s], getApps = () => Object.values(_apps);
|
|
410
|
+
var setApp = (s, I) => _apps[s.name] = {
|
|
411
|
+
...s,
|
|
412
|
+
...I
|
|
372
413
|
};
|
|
373
|
-
const startApp = (
|
|
374
|
-
let
|
|
375
|
-
|
|
376
|
-
}), stopApp = (
|
|
377
|
-
let
|
|
378
|
-
|
|
379
|
-
}, reloadApp = (
|
|
380
|
-
let
|
|
381
|
-
|
|
382
|
-
}, clearParentUrl = (
|
|
383
|
-
ConsoleUtil.trace("clearParentUrl",
|
|
384
|
-
let
|
|
385
|
-
ConsoleUtil.trace("url",
|
|
386
|
-
let
|
|
387
|
-
|
|
388
|
-
let
|
|
389
|
-
return window.history.replaceState(
|
|
390
|
-
}, isMicro = () => window[CONSTANT.IS_MICRO] === !0, isParent = () => window[CONSTANT.MICRO_TYPE] === "parent", createAppUrl = (
|
|
391
|
-
let
|
|
392
|
-
if (isMicro())
|
|
393
|
-
else if (!
|
|
414
|
+
const startApp = (s, I) => new Promise((L, R) => {
|
|
415
|
+
let z = getApp(s);
|
|
416
|
+
z ? (I && (z.instance.changeOptions(I), z = setApp(z, I)), z.instance.activate(z.el), L(z)) : R("app not found, please setup app first");
|
|
417
|
+
}), stopApp = (s) => {
|
|
418
|
+
let I = getApp(s);
|
|
419
|
+
I && I.instance.destroy();
|
|
420
|
+
}, reloadApp = (s, I = !1) => {
|
|
421
|
+
let L = getApp(s);
|
|
422
|
+
L && L.instance.reload(I);
|
|
423
|
+
}, clearParentUrl = (s) => {
|
|
424
|
+
ConsoleUtil.trace("clearParentUrl", s, CONSTANT.URL_PARAM_PREFIX + s);
|
|
425
|
+
let I = window.location.href.split("#");
|
|
426
|
+
ConsoleUtil.trace("url", I);
|
|
427
|
+
let L = new URL(I[0]);
|
|
428
|
+
L.searchParams.delete(CONSTANT.URL_PARAM_PREFIX + s);
|
|
429
|
+
let R = I.length > 1 ? L.href + "#" + I[1] : L.href;
|
|
430
|
+
return window.history.replaceState(window.history.state, "", R), R;
|
|
431
|
+
}, isMicro = () => window[CONSTANT.IS_MICRO] === !0, isParent = () => window[CONSTANT.MICRO_TYPE] === "parent", createAppUrl = (s, I = window.__XT_MICRO_APP?.name) => {
|
|
432
|
+
let L = window.location;
|
|
433
|
+
if (isMicro()) L = window.__XT_MICRO_APP.mainLocation;
|
|
434
|
+
else if (!I) {
|
|
394
435
|
ConsoleUtil.error("在主应用中需要传入应用名称");
|
|
395
436
|
return;
|
|
396
437
|
}
|
|
397
|
-
|
|
438
|
+
let R = new URL(L.href);
|
|
439
|
+
return R.searchParams.set(CONSTANT.URL_PARAM_PREFIX + I, s), R.href;
|
|
398
440
|
};
|
|
399
441
|
var XTMicroView_default = /* @__PURE__ */ defineComponent({
|
|
400
442
|
__name: "XTMicroView",
|
|
401
443
|
props: { appId: String },
|
|
402
|
-
setup(
|
|
403
|
-
let
|
|
404
|
-
|
|
405
|
-
el:
|
|
406
|
-
onUnload(
|
|
407
|
-
ConsoleUtil.trace("on unload",
|
|
444
|
+
setup(s) {
|
|
445
|
+
let L = s, z = ref(), B = () => {
|
|
446
|
+
L.appId && getApp(L.appId)?.preload && ConsoleUtil.warn(`微应用 ${L.appId} 的 preload 需要使用 XTMicroHost,当前按即时加载处理`), L.appId && startApp(L.appId, {
|
|
447
|
+
el: z.value,
|
|
448
|
+
onUnload(s, I) {
|
|
449
|
+
ConsoleUtil.trace("on unload", I.app.name);
|
|
408
450
|
}
|
|
409
|
-
}).then((
|
|
410
|
-
ConsoleUtil.trace("app mounted",
|
|
451
|
+
}).then((s) => {
|
|
452
|
+
ConsoleUtil.trace("app mounted", L.appId);
|
|
411
453
|
});
|
|
412
454
|
};
|
|
413
|
-
return watch(() =>
|
|
414
|
-
|
|
455
|
+
return watch(() => L.appId, (s, I) => {
|
|
456
|
+
s !== I && I && stopApp(I), B();
|
|
415
457
|
}), onMounted(() => {
|
|
416
|
-
|
|
417
|
-
}),
|
|
418
|
-
ConsoleUtil.trace("「micro」", "app unmount",
|
|
419
|
-
}), (
|
|
458
|
+
B();
|
|
459
|
+
}), onBeforeUnmount(() => {
|
|
460
|
+
ConsoleUtil.trace("「micro」", "app unmount", L.appId), L.appId && stopApp(L.appId), L.appId && clearParentUrl(L.appId);
|
|
461
|
+
}), (s, L) => (openBlock(), createElementBlock("div", mergeProps({
|
|
420
462
|
ref_key: "refPanel",
|
|
421
|
-
ref:
|
|
422
|
-
},
|
|
463
|
+
ref: z
|
|
464
|
+
}, s.$attrs, { class: "xt-micro" }), null, 16));
|
|
465
|
+
}
|
|
466
|
+
}), _hoisted_1 = { class: "xt-micro-host" }, XTMicroHost_default = /* @__PURE__ */ defineComponent({
|
|
467
|
+
__name: "XTMicroHost",
|
|
468
|
+
props: { activeApp: {} },
|
|
469
|
+
setup(L) {
|
|
470
|
+
let R = L, H = getApps(), U = {}, W = /* @__PURE__ */ new Set(), G = !1, K, q, J, Y = (s, I) => {
|
|
471
|
+
I instanceof HTMLElement && (U[s] = I);
|
|
472
|
+
}, X = async (s) => {
|
|
473
|
+
for (let I of H) if (I.name !== s) {
|
|
474
|
+
let s = I.instance.active;
|
|
475
|
+
I.instance.deactivate(), s && !I.keepAlive && I.instance.destroy();
|
|
476
|
+
}
|
|
477
|
+
if (setActiveMicroApp(s), !s) return;
|
|
478
|
+
let I = H.find((I) => I.name === s), L = U[s];
|
|
479
|
+
!I || !L || (W.add(s), await I.instance.activate(L));
|
|
480
|
+
}, Z = (s) => new Promise((I) => {
|
|
481
|
+
J = window.setTimeout(I, s);
|
|
482
|
+
}), Q = (s) => {
|
|
483
|
+
typeof window.requestIdleCallback == "function" ? K = window.requestIdleCallback(s) : q = setTimeout(s, 200);
|
|
484
|
+
}, $ = async (s) => {
|
|
485
|
+
let I = s.shift();
|
|
486
|
+
if (!I || G) return;
|
|
487
|
+
let L = U[I.name];
|
|
488
|
+
if (!L || I.instance.state !== "idle") {
|
|
489
|
+
Q(() => $(s));
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
W.add(I.name), await Promise.race([I.instance.preload(L), Z(15e3)]), J !== void 0 && clearTimeout(J), G || Q(() => $(s));
|
|
493
|
+
};
|
|
494
|
+
return onMounted(async () => {
|
|
495
|
+
await nextTick(), await X(R.activeApp);
|
|
496
|
+
let s = H.filter((s) => s.preload && s.name !== R.activeApp);
|
|
497
|
+
s.forEach((s) => ConsoleUtil.trace("preload queued", s.name)), Q(() => $(s));
|
|
498
|
+
}), watch(() => R.activeApp, X), onBeforeUnmount(() => {
|
|
499
|
+
G = !0, K !== void 0 && window.cancelIdleCallback(K), q !== void 0 && clearTimeout(q), J !== void 0 && window.clearTimeout(J), W.forEach((s) => H.find((I) => I.name === s)?.instance.destroy()), setActiveMicroApp();
|
|
500
|
+
}), (R, z) => (openBlock(), createElementBlock("div", _hoisted_1, [(openBlock(!0), createElementBlock(Fragment, null, renderList(unref(H), (s) => (openBlock(), createElementBlock("div", {
|
|
501
|
+
key: s.name,
|
|
502
|
+
ref_for: !0,
|
|
503
|
+
ref: (I) => Y(s.name, I),
|
|
504
|
+
class: normalizeClass(["xt-micro-panel", { "is-active": s.name === L.activeApp }])
|
|
505
|
+
}, null, 2))), 128))]));
|
|
423
506
|
}
|
|
424
507
|
});
|
|
425
508
|
window[CONSTANT.MICRO_VERSION] = version, window.micro_api = { debug: ConsoleUtil.setEnable };
|
|
426
|
-
var src_default = { install: (
|
|
427
|
-
|
|
509
|
+
var src_default = { install: (s, I = {}) => {
|
|
510
|
+
s.component("xt-micro-view", XTMicroView_default), s.component("xt-micro-host", XTMicroHost_default), mainMicroInit();
|
|
428
511
|
} };
|
|
429
|
-
export { XTMicroView_default as XTMicroView, clearParentUrl, createAppUrl, src_default as default, getApp, isMicro, isParent, microInit, reloadApp, setupApp, startApp, stopApp, utils_exports as utils };
|
|
512
|
+
export { XTMicroHost_default as XTMicroHost, XTMicroView_default as XTMicroView, clearParentUrl, createAppUrl, src_default as default, getApp, getApps, isMicro, isParent, microInit, reloadApp, setupApp, startApp, stopApp, utils_exports as utils };
|
package/dist/types/api.d.ts
CHANGED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
activeApp?: string;
|
|
3
|
+
};
|
|
4
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
5
|
+
export default _default;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { App } from 'vue';
|
|
2
2
|
import { default as XTMicroView } from './components/XTMicroView.vue';
|
|
3
|
+
import { default as XTMicroHost } from './components/XTMicroHost.vue';
|
|
3
4
|
export * from './api';
|
|
4
5
|
import * as utils from "./utils";
|
|
5
|
-
export { XTMicroView, utils };
|
|
6
|
+
export { XTMicroHost, XTMicroView, utils };
|
|
6
7
|
declare const _default: {
|
|
7
8
|
install: (app: App, _options?: any) => void;
|
|
8
9
|
};
|
package/dist/types/parent.d.ts
CHANGED
|
@@ -1,32 +1,44 @@
|
|
|
1
|
-
import { AppOption, App } from './types';
|
|
1
|
+
import { AppOption, App, MicroAppState } from './types';
|
|
2
2
|
export declare const isMicro: import('vue').Ref<boolean, boolean>;
|
|
3
|
+
export declare const getActiveMicroApp: () => string;
|
|
4
|
+
export declare const setActiveMicroApp: (name?: string) => void;
|
|
3
5
|
export declare class MicroApp {
|
|
4
6
|
app: App | AppOption;
|
|
5
7
|
dom: HTMLIFrameElement | undefined;
|
|
6
8
|
panel: HTMLElement | undefined;
|
|
7
9
|
loading: HTMLElement | undefined;
|
|
8
10
|
loadingTimer: NodeJS.Timeout | undefined;
|
|
11
|
+
state: MicroAppState;
|
|
12
|
+
active: boolean;
|
|
13
|
+
private loadPromise?;
|
|
14
|
+
private resolveLoad?;
|
|
15
|
+
private observer?;
|
|
16
|
+
private destroying;
|
|
9
17
|
constructor(app: AppOption);
|
|
10
|
-
|
|
18
|
+
private getPanel;
|
|
19
|
+
private ensureLoaded;
|
|
20
|
+
private showLoading;
|
|
21
|
+
mount(el: HTMLElement | string | undefined): Promise<void>;
|
|
22
|
+
preload(el: HTMLElement | string | undefined): Promise<void>;
|
|
23
|
+
activate(el: HTMLElement | string | undefined): Promise<void>;
|
|
24
|
+
deactivate(): void;
|
|
11
25
|
unmount(): void;
|
|
12
26
|
/**
|
|
13
27
|
* 预加载渲染
|
|
14
28
|
* TODO 还差用户切走之后,如何将ifr还原回去,等待下次载入
|
|
15
29
|
* @param el 挂载dom对象
|
|
16
30
|
*/
|
|
17
|
-
preloadRender(el: HTMLElement | string | undefined): void
|
|
31
|
+
preloadRender(el: HTMLElement | string | undefined): Promise<void>;
|
|
18
32
|
/**
|
|
19
33
|
* 预加载app,先放到body,待启动时,挪过来
|
|
20
34
|
*/
|
|
21
|
-
|
|
35
|
+
destroy(): void;
|
|
22
36
|
reload(isGoHome?: boolean): void;
|
|
23
37
|
changeOptions(options: Partial<AppOption>): void;
|
|
24
38
|
onLoad(_event: Event): void;
|
|
25
39
|
onUnload(_event: Event): void;
|
|
26
40
|
onError(_event: Event): void;
|
|
41
|
+
private postLifecycle;
|
|
42
|
+
private reset;
|
|
27
43
|
}
|
|
28
|
-
/**
|
|
29
|
-
* 初始化主应用微前端
|
|
30
|
-
* 包括:监听子应用消息,同步子应用路由到主应用上
|
|
31
|
-
*/
|
|
32
44
|
export declare const mainMicroInit: () => void;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ export interface AppOption {
|
|
|
5
5
|
url: string;
|
|
6
6
|
el?: HTMLElement | string;
|
|
7
7
|
preload?: boolean;
|
|
8
|
-
|
|
8
|
+
keepAlive?: boolean;
|
|
9
|
+
token?: string | (() => string);
|
|
9
10
|
params?: {
|
|
10
11
|
[key: string]: any;
|
|
11
12
|
};
|
|
@@ -19,8 +20,11 @@ export interface App extends AppOption {
|
|
|
19
20
|
}
|
|
20
21
|
export interface MicroInitOptions {
|
|
21
22
|
hideHeaderCssSelector?: string | string[];
|
|
22
|
-
authHandler?: (token: string) => void
|
|
23
|
+
authHandler?: (token: string | null) => void | Promise<void>;
|
|
24
|
+
onActivated?: () => void | Promise<void>;
|
|
25
|
+
onDeactivated?: () => void | Promise<void>;
|
|
23
26
|
}
|
|
27
|
+
export type MicroAppState = "idle" | "loading" | "loaded" | "error" | "active";
|
|
24
28
|
declare global {
|
|
25
29
|
interface Window {
|
|
26
30
|
[key: string]: any;
|