@micro-zoe/micro-app 0.5.0 → 0.6.0
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 +20 -62
- package/README.zh-cn.md +19 -61
- package/lib/index.d.ts +72 -3
- package/lib/index.esm.js +243 -107
- package/lib/index.esm.js.map +1 -1
- package/lib/index.min.js +1 -1
- package/lib/index.min.js.map +1 -1
- package/lib/index.umd.js +1 -1
- package/lib/index.umd.js.map +1 -1
- package/package.json +4 -4
- package/polyfill/jsx-custom-event.js +14 -6
- package/polyfill/jsx-custom-event.js.map +1 -1
- package/typings/global.d.ts +14 -4
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '0.
|
|
1
|
+
const version = '0.6.0';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -297,16 +297,16 @@ var ObservedAttrName;
|
|
|
297
297
|
ObservedAttrName["URL"] = "url";
|
|
298
298
|
})(ObservedAttrName || (ObservedAttrName = {}));
|
|
299
299
|
// app status
|
|
300
|
-
var
|
|
301
|
-
(function (
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
})(
|
|
300
|
+
var appStates;
|
|
301
|
+
(function (appStates) {
|
|
302
|
+
appStates["NOT_LOADED"] = "NOT_LOADED";
|
|
303
|
+
appStates["LOADING_SOURCE_CODE"] = "LOADING_SOURCE_CODE";
|
|
304
|
+
appStates["LOAD_SOURCE_FINISHED"] = "LOAD_SOURCE_FINISHED";
|
|
305
|
+
appStates["LOAD_SOURCE_ERROR"] = "LOAD_SOURCE_ERROR";
|
|
306
|
+
appStates["MOUNTING"] = "MOUNTING";
|
|
307
|
+
appStates["MOUNTED"] = "MOUNTED";
|
|
308
|
+
appStates["UNMOUNT"] = "UNMOUNT";
|
|
309
|
+
})(appStates || (appStates = {}));
|
|
310
310
|
// lifecycles
|
|
311
311
|
var lifeCycles;
|
|
312
312
|
(function (lifeCycles) {
|
|
@@ -315,7 +315,17 @@ var lifeCycles;
|
|
|
315
315
|
lifeCycles["MOUNTED"] = "mounted";
|
|
316
316
|
lifeCycles["UNMOUNT"] = "unmount";
|
|
317
317
|
lifeCycles["ERROR"] = "error";
|
|
318
|
+
// 👇 keep-alive only
|
|
319
|
+
lifeCycles["BEFORESHOW"] = "beforeshow";
|
|
320
|
+
lifeCycles["AFTERSHOW"] = "aftershow";
|
|
321
|
+
lifeCycles["AFTERHIDDEN"] = "afterhidden";
|
|
318
322
|
})(lifeCycles || (lifeCycles = {}));
|
|
323
|
+
// keep-alive status
|
|
324
|
+
var keepAliveStates;
|
|
325
|
+
(function (keepAliveStates) {
|
|
326
|
+
keepAliveStates["KEEP_ALIVE_SHOW"] = "KEEP_ALIVE_SHOW";
|
|
327
|
+
keepAliveStates["KEEP_ALIVE_HIDDEN"] = "KEEP_ALIVE_HIDDEN";
|
|
328
|
+
})(keepAliveStates || (keepAliveStates = {}));
|
|
319
329
|
|
|
320
330
|
/**
|
|
321
331
|
* fetch source of html, js, css
|
|
@@ -625,7 +635,7 @@ const globalLinks = new Map();
|
|
|
625
635
|
* @param microAppHead micro-app-head element
|
|
626
636
|
* @param isDynamic dynamic insert
|
|
627
637
|
*/
|
|
628
|
-
function extractLinkFromHtml(link, parent, app,
|
|
638
|
+
function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
629
639
|
const rel = link.getAttribute('rel');
|
|
630
640
|
let href = link.getAttribute('href');
|
|
631
641
|
let replaceComment = null;
|
|
@@ -633,12 +643,9 @@ function extractLinkFromHtml(link, parent, app, microAppHead, isDynamic = false)
|
|
|
633
643
|
href = CompletionPath(href, app.url);
|
|
634
644
|
if (!isDynamic) {
|
|
635
645
|
replaceComment = document.createComment(`link element with href=${href} move to micro-app-head as style element`);
|
|
636
|
-
const placeholderComment = document.createComment(`placeholder for link with href=${href}`);
|
|
637
|
-
// all style elements insert into microAppHead
|
|
638
|
-
microAppHead.appendChild(placeholderComment);
|
|
639
646
|
app.source.links.set(href, {
|
|
640
647
|
code: '',
|
|
641
|
-
placeholder:
|
|
648
|
+
placeholder: replaceComment,
|
|
642
649
|
isGlobal: link.hasAttribute('global'),
|
|
643
650
|
});
|
|
644
651
|
}
|
|
@@ -653,7 +660,7 @@ function extractLinkFromHtml(link, parent, app, microAppHead, isDynamic = false)
|
|
|
653
660
|
}
|
|
654
661
|
}
|
|
655
662
|
else if (rel && ['prefetch', 'preload', 'prerender', 'icon', 'apple-touch-icon'].includes(rel)) {
|
|
656
|
-
// preload prefetch
|
|
663
|
+
// preload prefetch icon ....
|
|
657
664
|
if (isDynamic) {
|
|
658
665
|
replaceComment = document.createComment(`link element with rel=${rel}${href ? ' & href=' + href : ''} removed by micro-app`);
|
|
659
666
|
}
|
|
@@ -708,6 +715,7 @@ function fetchLinkSuccess(url, info, data, microAppHead, app) {
|
|
|
708
715
|
const styleLink = pureCreateElement('style');
|
|
709
716
|
styleLink.textContent = data;
|
|
710
717
|
styleLink.__MICRO_APP_LINK_PATH__ = url;
|
|
718
|
+
styleLink.setAttribute('data-origin-href', url);
|
|
711
719
|
microAppHead.replaceChild(scopedCSS(styleLink, app), info.placeholder);
|
|
712
720
|
info.placeholder = null;
|
|
713
721
|
info.code = data;
|
|
@@ -1012,9 +1020,6 @@ function runCode2InlineScript(url, code, module, scriptElement, callback) {
|
|
|
1012
1020
|
const blob = new Blob([code], { type: 'text/javascript' });
|
|
1013
1021
|
scriptElement.src = URL.createObjectURL(blob);
|
|
1014
1022
|
scriptElement.setAttribute('type', 'module');
|
|
1015
|
-
if (!url.startsWith('inline-')) {
|
|
1016
|
-
scriptElement.setAttribute('originSrc', url);
|
|
1017
|
-
}
|
|
1018
1023
|
if (callback) {
|
|
1019
1024
|
callback.moduleCount && callback.moduleCount--;
|
|
1020
1025
|
scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0);
|
|
@@ -1023,6 +1028,9 @@ function runCode2InlineScript(url, code, module, scriptElement, callback) {
|
|
|
1023
1028
|
else {
|
|
1024
1029
|
scriptElement.textContent = code;
|
|
1025
1030
|
}
|
|
1031
|
+
if (!url.startsWith('inline-')) {
|
|
1032
|
+
scriptElement.setAttribute('data-origin-src', url);
|
|
1033
|
+
}
|
|
1026
1034
|
}
|
|
1027
1035
|
// init & run code2Function
|
|
1028
1036
|
function runCode2Function(code, info) {
|
|
@@ -1092,7 +1100,7 @@ function getWrapElement(str) {
|
|
|
1092
1100
|
function flatChildren(parent, app, microAppHead) {
|
|
1093
1101
|
const children = Array.from(parent.children);
|
|
1094
1102
|
children.length && children.forEach((child) => {
|
|
1095
|
-
flatChildren(child, app
|
|
1103
|
+
flatChildren(child, app);
|
|
1096
1104
|
});
|
|
1097
1105
|
for (const dom of children) {
|
|
1098
1106
|
if (dom instanceof HTMLLinkElement) {
|
|
@@ -1100,7 +1108,7 @@ function flatChildren(parent, app, microAppHead) {
|
|
|
1100
1108
|
parent.replaceChild(document.createComment('link element with exclude attribute ignored by micro-app'), dom);
|
|
1101
1109
|
}
|
|
1102
1110
|
else if (!dom.hasAttribute('ignore')) {
|
|
1103
|
-
extractLinkFromHtml(dom, parent, app
|
|
1111
|
+
extractLinkFromHtml(dom, parent, app);
|
|
1104
1112
|
}
|
|
1105
1113
|
else if (dom.hasAttribute('href')) {
|
|
1106
1114
|
dom.setAttribute('href', CompletionPath(dom.getAttribute('href'), app.url));
|
|
@@ -1111,7 +1119,7 @@ function flatChildren(parent, app, microAppHead) {
|
|
|
1111
1119
|
parent.replaceChild(document.createComment('style element with exclude attribute ignored by micro-app'), dom);
|
|
1112
1120
|
}
|
|
1113
1121
|
else if (app.scopecss && !dom.hasAttribute('ignore')) {
|
|
1114
|
-
|
|
1122
|
+
scopedCSS(dom, app);
|
|
1115
1123
|
}
|
|
1116
1124
|
}
|
|
1117
1125
|
else if (dom instanceof HTMLScriptElement) {
|
|
@@ -1139,7 +1147,7 @@ function extractSourceDom(htmlStr, app) {
|
|
|
1139
1147
|
app.onerror(new Error(msg));
|
|
1140
1148
|
return logError(msg, app.name);
|
|
1141
1149
|
}
|
|
1142
|
-
flatChildren(wrapElement, app
|
|
1150
|
+
flatChildren(wrapElement, app);
|
|
1143
1151
|
if (app.source.links.size) {
|
|
1144
1152
|
fetchLinksFromHtml(wrapElement, app, microAppHead);
|
|
1145
1153
|
}
|
|
@@ -1319,14 +1327,16 @@ function releaseEffectDocumentEvent() {
|
|
|
1319
1327
|
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
1320
1328
|
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
1321
1329
|
}
|
|
1330
|
+
// this events should be sent to the specified app
|
|
1331
|
+
const formatEventList = ['unmount', 'appstate-change'];
|
|
1322
1332
|
/**
|
|
1323
1333
|
* Format event name
|
|
1324
1334
|
* @param type event name
|
|
1325
1335
|
* @param microWindow micro window
|
|
1326
1336
|
*/
|
|
1327
1337
|
function formatEventType(type, microWindow) {
|
|
1328
|
-
if (type
|
|
1329
|
-
return
|
|
1338
|
+
if (formatEventList.includes(type)) {
|
|
1339
|
+
return `${type}-${microWindow.__MICRO_APP_NAME__}`;
|
|
1330
1340
|
}
|
|
1331
1341
|
return type;
|
|
1332
1342
|
}
|
|
@@ -1890,12 +1900,15 @@ class SandBox {
|
|
|
1890
1900
|
return key in target;
|
|
1891
1901
|
return key in unscopables || key in target || key in rawWindow;
|
|
1892
1902
|
},
|
|
1903
|
+
// Object.getOwnPropertyDescriptor(window, key)
|
|
1904
|
+
// TODO: use set
|
|
1893
1905
|
getOwnPropertyDescriptor: (target, key) => {
|
|
1894
1906
|
if (target.hasOwnProperty(key)) {
|
|
1895
1907
|
descriptorTargetMap.set(key, 'target');
|
|
1896
1908
|
return Object.getOwnPropertyDescriptor(target, key);
|
|
1897
1909
|
}
|
|
1898
1910
|
if (rawWindow.hasOwnProperty(key)) {
|
|
1911
|
+
// like console, alert ...
|
|
1899
1912
|
descriptorTargetMap.set(key, 'rawWindow');
|
|
1900
1913
|
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
1901
1914
|
if (descriptor && !descriptor.configurable) {
|
|
@@ -1905,6 +1918,7 @@ class SandBox {
|
|
|
1905
1918
|
}
|
|
1906
1919
|
return undefined;
|
|
1907
1920
|
},
|
|
1921
|
+
// Object.defineProperty(window, key, Descriptor)
|
|
1908
1922
|
defineProperty: (target, key, value) => {
|
|
1909
1923
|
const from = descriptorTargetMap.get(key);
|
|
1910
1924
|
if (from === 'rawWindow') {
|
|
@@ -1912,11 +1926,13 @@ class SandBox {
|
|
|
1912
1926
|
}
|
|
1913
1927
|
return Reflect.defineProperty(target, key, value);
|
|
1914
1928
|
},
|
|
1929
|
+
// Object.getOwnPropertyNames(window)
|
|
1915
1930
|
ownKeys: (target) => {
|
|
1916
1931
|
return unique(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)));
|
|
1917
1932
|
},
|
|
1918
1933
|
deleteProperty: (target, key) => {
|
|
1919
1934
|
if (target.hasOwnProperty(key)) {
|
|
1935
|
+
this.injectedKeys.has(key) && this.injectedKeys.delete(key);
|
|
1920
1936
|
this.escapeKeys.has(key) && Reflect.deleteProperty(rawWindow, key);
|
|
1921
1937
|
return Reflect.deleteProperty(target, key);
|
|
1922
1938
|
}
|
|
@@ -2072,11 +2088,15 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
2072
2088
|
element.dispatchEvent(event);
|
|
2073
2089
|
}
|
|
2074
2090
|
/**
|
|
2075
|
-
* Dispatch
|
|
2076
|
-
* @param
|
|
2091
|
+
* Dispatch custom event to micro app
|
|
2092
|
+
* @param eventName event name
|
|
2093
|
+
* @param appName app name
|
|
2094
|
+
* @param detail event detail
|
|
2077
2095
|
*/
|
|
2078
|
-
function
|
|
2079
|
-
const event = new CustomEvent(
|
|
2096
|
+
function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
|
|
2097
|
+
const event = new CustomEvent(`${eventName}-${appName}`, {
|
|
2098
|
+
detail,
|
|
2099
|
+
});
|
|
2080
2100
|
window.dispatchEvent(event);
|
|
2081
2101
|
}
|
|
2082
2102
|
|
|
@@ -2084,7 +2104,9 @@ function dispatchUnmountToMicroApp(appName) {
|
|
|
2084
2104
|
const appInstanceMap = new Map();
|
|
2085
2105
|
class CreateApp {
|
|
2086
2106
|
constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, macro, baseroute, }) {
|
|
2087
|
-
this.
|
|
2107
|
+
this.state = appStates.NOT_LOADED;
|
|
2108
|
+
this.keepAliveState = null;
|
|
2109
|
+
this.keepAliveContainer = null;
|
|
2088
2110
|
this.loadSourceLevel = 0;
|
|
2089
2111
|
this.umdHookMount = null;
|
|
2090
2112
|
this.umdHookUnmount = null;
|
|
@@ -2114,7 +2136,7 @@ class CreateApp {
|
|
|
2114
2136
|
}
|
|
2115
2137
|
// Load resources
|
|
2116
2138
|
loadSourceCode() {
|
|
2117
|
-
this.
|
|
2139
|
+
this.state = appStates.LOADING_SOURCE_CODE;
|
|
2118
2140
|
extractHtml(this);
|
|
2119
2141
|
}
|
|
2120
2142
|
/**
|
|
@@ -2123,9 +2145,9 @@ class CreateApp {
|
|
|
2123
2145
|
onLoad(html) {
|
|
2124
2146
|
if (++this.loadSourceLevel === 2) {
|
|
2125
2147
|
this.source.html = html;
|
|
2126
|
-
if (this.isPrefetch ||
|
|
2148
|
+
if (this.isPrefetch || appStates.UNMOUNT === this.state)
|
|
2127
2149
|
return;
|
|
2128
|
-
this.
|
|
2150
|
+
this.state = appStates.LOAD_SOURCE_FINISHED;
|
|
2129
2151
|
this.mount();
|
|
2130
2152
|
}
|
|
2131
2153
|
}
|
|
@@ -2135,9 +2157,9 @@ class CreateApp {
|
|
|
2135
2157
|
*/
|
|
2136
2158
|
onLoadError(e) {
|
|
2137
2159
|
this.loadSourceLevel = -1;
|
|
2138
|
-
if (
|
|
2160
|
+
if (appStates.UNMOUNT !== this.state) {
|
|
2139
2161
|
this.onerror(e);
|
|
2140
|
-
this.
|
|
2162
|
+
this.state = appStates.LOAD_SOURCE_ERROR;
|
|
2141
2163
|
}
|
|
2142
2164
|
}
|
|
2143
2165
|
/**
|
|
@@ -2154,11 +2176,11 @@ class CreateApp {
|
|
|
2154
2176
|
this.container = (_a = this.container) !== null && _a !== void 0 ? _a : container;
|
|
2155
2177
|
this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : this.baseroute;
|
|
2156
2178
|
if (this.loadSourceLevel !== 2) {
|
|
2157
|
-
this.
|
|
2179
|
+
this.state = appStates.LOADING_SOURCE_CODE;
|
|
2158
2180
|
return;
|
|
2159
2181
|
}
|
|
2160
2182
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
2161
|
-
this.
|
|
2183
|
+
this.state = appStates.MOUNTING;
|
|
2162
2184
|
cloneContainer(this.source.html, this.container, !this.umdMode);
|
|
2163
2185
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.baseroute);
|
|
2164
2186
|
let umdHookMountResult; // result of mount function
|
|
@@ -2218,20 +2240,23 @@ class CreateApp {
|
|
|
2218
2240
|
* dispatch mounted event when app run finished
|
|
2219
2241
|
*/
|
|
2220
2242
|
dispatchMountedEvent() {
|
|
2221
|
-
if (
|
|
2222
|
-
this.
|
|
2243
|
+
if (appStates.UNMOUNT !== this.state) {
|
|
2244
|
+
this.state = appStates.MOUNTED;
|
|
2223
2245
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
2224
2246
|
}
|
|
2225
2247
|
}
|
|
2226
2248
|
/**
|
|
2227
2249
|
* unmount app
|
|
2228
2250
|
* @param destroy completely destroy, delete cache resources
|
|
2251
|
+
* @param unmountcb callback of unmount
|
|
2229
2252
|
*/
|
|
2230
|
-
unmount(destroy) {
|
|
2231
|
-
if (this.
|
|
2253
|
+
unmount(destroy, unmountcb) {
|
|
2254
|
+
if (this.state === appStates.LOAD_SOURCE_ERROR) {
|
|
2232
2255
|
destroy = true;
|
|
2233
2256
|
}
|
|
2234
|
-
this.
|
|
2257
|
+
this.state = appStates.UNMOUNT;
|
|
2258
|
+
this.keepAliveState = null;
|
|
2259
|
+
this.keepAliveContainer = null;
|
|
2235
2260
|
// result of unmount function
|
|
2236
2261
|
let umdHookUnmountResult;
|
|
2237
2262
|
/**
|
|
@@ -2247,28 +2272,31 @@ class CreateApp {
|
|
|
2247
2272
|
}
|
|
2248
2273
|
}
|
|
2249
2274
|
// dispatch unmount event to micro app
|
|
2250
|
-
|
|
2251
|
-
this.handleUnmounted(destroy, umdHookUnmountResult);
|
|
2275
|
+
dispatchCustomEventToMicroApp('unmount', this.name);
|
|
2276
|
+
this.handleUnmounted(destroy, umdHookUnmountResult, unmountcb);
|
|
2252
2277
|
}
|
|
2253
2278
|
/**
|
|
2254
2279
|
* handle for promise umdHookUnmount
|
|
2280
|
+
* @param destroy completely destroy, delete cache resources
|
|
2255
2281
|
* @param umdHookUnmountResult result of umdHookUnmount
|
|
2282
|
+
* @param unmountcb callback of unmount
|
|
2256
2283
|
*/
|
|
2257
|
-
handleUnmounted(destroy, umdHookUnmountResult) {
|
|
2284
|
+
handleUnmounted(destroy, umdHookUnmountResult, unmountcb) {
|
|
2258
2285
|
if (isPromise(umdHookUnmountResult)) {
|
|
2259
2286
|
umdHookUnmountResult
|
|
2260
|
-
.then(() => this.actionsForUnmount(destroy))
|
|
2261
|
-
.catch(() => this.actionsForUnmount(destroy));
|
|
2287
|
+
.then(() => this.actionsForUnmount(destroy, unmountcb))
|
|
2288
|
+
.catch(() => this.actionsForUnmount(destroy, unmountcb));
|
|
2262
2289
|
}
|
|
2263
2290
|
else {
|
|
2264
|
-
this.actionsForUnmount(destroy);
|
|
2291
|
+
this.actionsForUnmount(destroy, unmountcb);
|
|
2265
2292
|
}
|
|
2266
2293
|
}
|
|
2267
2294
|
/**
|
|
2268
2295
|
* actions for unmount app
|
|
2269
2296
|
* @param destroy completely destroy, delete cache resources
|
|
2297
|
+
* @param unmountcb callback of unmount
|
|
2270
2298
|
*/
|
|
2271
|
-
actionsForUnmount(destroy) {
|
|
2299
|
+
actionsForUnmount(destroy, unmountcb) {
|
|
2272
2300
|
var _a;
|
|
2273
2301
|
// dispatch unmount event to base app
|
|
2274
2302
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
@@ -2277,12 +2305,11 @@ class CreateApp {
|
|
|
2277
2305
|
this.actionsForCompletelyDestory();
|
|
2278
2306
|
}
|
|
2279
2307
|
else if (this.umdMode && this.container.childElementCount) {
|
|
2280
|
-
/**
|
|
2281
|
-
* In umd mode, ui frameworks will no longer create style elements to head in lazy load page when render again, so we should save container to keep these elements
|
|
2282
|
-
*/
|
|
2283
2308
|
cloneContainer(this.container, this.source.html, false);
|
|
2284
2309
|
}
|
|
2310
|
+
this.container.innerHTML = '';
|
|
2285
2311
|
this.container = null;
|
|
2312
|
+
unmountcb && unmountcb();
|
|
2286
2313
|
}
|
|
2287
2314
|
// actions for completely destroy
|
|
2288
2315
|
actionsForCompletelyDestory() {
|
|
@@ -2291,6 +2318,37 @@ class CreateApp {
|
|
|
2291
2318
|
}
|
|
2292
2319
|
appInstanceMap.delete(this.name);
|
|
2293
2320
|
}
|
|
2321
|
+
// hidden app when disconnectedCallback called with keep-alive
|
|
2322
|
+
hiddenKeepAliveApp() {
|
|
2323
|
+
this.keepAliveState = keepAliveStates.KEEP_ALIVE_HIDDEN;
|
|
2324
|
+
// event should dispatch before clone node
|
|
2325
|
+
// dispatch afterhidden event to micro-app
|
|
2326
|
+
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
2327
|
+
appState: 'afterhidden',
|
|
2328
|
+
});
|
|
2329
|
+
// dispatch afterhidden event to base app
|
|
2330
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
|
|
2331
|
+
cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
|
|
2332
|
+
this.container = this.keepAliveContainer;
|
|
2333
|
+
}
|
|
2334
|
+
// show app when connectedCallback called with keep-alive
|
|
2335
|
+
showKeepAliveApp(container) {
|
|
2336
|
+
// dispatch beforeshow event to micro-app
|
|
2337
|
+
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
2338
|
+
appState: 'beforeshow',
|
|
2339
|
+
});
|
|
2340
|
+
// dispatch beforeshow event to base app
|
|
2341
|
+
dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
|
|
2342
|
+
cloneContainer(this.container, container, false);
|
|
2343
|
+
this.container = container;
|
|
2344
|
+
this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
|
|
2345
|
+
// dispatch aftershow event to micro-app
|
|
2346
|
+
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
2347
|
+
appState: 'aftershow',
|
|
2348
|
+
});
|
|
2349
|
+
// dispatch aftershow event to base app
|
|
2350
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERSHOW);
|
|
2351
|
+
}
|
|
2294
2352
|
/**
|
|
2295
2353
|
* app rendering error
|
|
2296
2354
|
* @param e Error
|
|
@@ -2298,15 +2356,19 @@ class CreateApp {
|
|
|
2298
2356
|
onerror(e) {
|
|
2299
2357
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
|
|
2300
2358
|
}
|
|
2301
|
-
// get app
|
|
2302
|
-
|
|
2303
|
-
return this.
|
|
2359
|
+
// get app state
|
|
2360
|
+
getAppState() {
|
|
2361
|
+
return this.state;
|
|
2362
|
+
}
|
|
2363
|
+
// get keep-alive state
|
|
2364
|
+
getKeepAliveState() {
|
|
2365
|
+
return this.keepAliveState;
|
|
2304
2366
|
}
|
|
2305
2367
|
// get umd library, if it not exist, return empty object
|
|
2306
2368
|
getUmdLibraryHooks() {
|
|
2307
2369
|
var _a, _b;
|
|
2308
2370
|
// after execScripts, the app maybe unmounted
|
|
2309
|
-
if (
|
|
2371
|
+
if (appStates.UNMOUNT !== this.state) {
|
|
2310
2372
|
const global = ((_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) !== null && _b !== void 0 ? _b : globalEnv.rawWindow);
|
|
2311
2373
|
this.libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
|
|
2312
2374
|
// do not use isObject
|
|
@@ -2315,6 +2377,20 @@ class CreateApp {
|
|
|
2315
2377
|
return {};
|
|
2316
2378
|
}
|
|
2317
2379
|
}
|
|
2380
|
+
// if app not prefetch & not unmount, then app is active
|
|
2381
|
+
function getActiveApps() {
|
|
2382
|
+
const activeApps = [];
|
|
2383
|
+
appInstanceMap.forEach((app, appName) => {
|
|
2384
|
+
if (appStates.UNMOUNT !== app.getAppState() && !app.isPrefetch) {
|
|
2385
|
+
activeApps.push(appName);
|
|
2386
|
+
}
|
|
2387
|
+
});
|
|
2388
|
+
return activeApps;
|
|
2389
|
+
}
|
|
2390
|
+
// get all registered apps
|
|
2391
|
+
function getAllApps() {
|
|
2392
|
+
return Array.from(appInstanceMap.keys());
|
|
2393
|
+
}
|
|
2318
2394
|
|
|
2319
2395
|
// Record element and map element
|
|
2320
2396
|
const dynamicElementInMicroAppMap = new WeakMap();
|
|
@@ -2345,7 +2421,7 @@ function handleNewNode(parent, child, app) {
|
|
|
2345
2421
|
else if (child.hasAttribute('ignore')) {
|
|
2346
2422
|
return child;
|
|
2347
2423
|
}
|
|
2348
|
-
const { url, info, replaceComment } = extractLinkFromHtml(child, parent, app,
|
|
2424
|
+
const { url, info, replaceComment } = extractLinkFromHtml(child, parent, app, true);
|
|
2349
2425
|
if (url && info) {
|
|
2350
2426
|
const replaceStyle = pureCreateElement('style');
|
|
2351
2427
|
replaceStyle.__MICRO_APP_LINK_PATH__ = url;
|
|
@@ -2682,7 +2758,7 @@ function rejectMicroAppStyle() {
|
|
|
2682
2758
|
}
|
|
2683
2759
|
|
|
2684
2760
|
function unmountNestedApp() {
|
|
2685
|
-
|
|
2761
|
+
releaseUnmountOfNestedApp();
|
|
2686
2762
|
appInstanceMap.forEach(app => {
|
|
2687
2763
|
// @ts-ignore
|
|
2688
2764
|
app.container && getRootContainer(app.container).disconnectedCallback();
|
|
@@ -2700,7 +2776,7 @@ function listenUmountOfNestedApp() {
|
|
|
2700
2776
|
}
|
|
2701
2777
|
}
|
|
2702
2778
|
// release listener
|
|
2703
|
-
function
|
|
2779
|
+
function releaseUnmountOfNestedApp() {
|
|
2704
2780
|
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
2705
2781
|
window.removeEventListener('unmount', unmountNestedApp, false);
|
|
2706
2782
|
}
|
|
@@ -2727,7 +2803,6 @@ function defineElement(tagName) {
|
|
|
2727
2803
|
* handle for change of name an url after element inited
|
|
2728
2804
|
*/
|
|
2729
2805
|
this.handleAttributeUpdate = () => {
|
|
2730
|
-
var _a;
|
|
2731
2806
|
this.isWating = false;
|
|
2732
2807
|
const formatAttrName = formatAppName(this.getAttribute('name'));
|
|
2733
2808
|
const formatAttrUrl = formatAppURL(this.getAttribute('url'), this.appName);
|
|
@@ -2735,44 +2810,27 @@ function defineElement(tagName) {
|
|
|
2735
2810
|
const existApp = appInstanceMap.get(formatAttrName);
|
|
2736
2811
|
if (formatAttrName !== this.appName && existApp) {
|
|
2737
2812
|
// handling of cached and non-prefetch apps
|
|
2738
|
-
if (
|
|
2813
|
+
if (appStates.UNMOUNT !== existApp.getAppState() &&
|
|
2814
|
+
keepAliveStates.KEEP_ALIVE_HIDDEN !== existApp.getKeepAliveState() &&
|
|
2815
|
+
!existApp.isPrefetch) {
|
|
2739
2816
|
this.setAttribute('name', this.appName);
|
|
2740
|
-
return logError(`an app named ${formatAttrName}
|
|
2817
|
+
return logError(`app name conflict, an app named ${formatAttrName} is running`, this.appName);
|
|
2741
2818
|
}
|
|
2742
2819
|
}
|
|
2743
2820
|
if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
*/
|
|
2749
|
-
if (this.getDisposeResult('ssr')) {
|
|
2750
|
-
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, formatAttrUrl);
|
|
2751
|
-
}
|
|
2752
|
-
else if (this.ssrUrl) {
|
|
2753
|
-
this.ssrUrl = '';
|
|
2754
|
-
}
|
|
2755
|
-
this.appName = formatAttrName;
|
|
2756
|
-
this.appUrl = formatAttrUrl;
|
|
2757
|
-
((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
|
|
2758
|
-
if (formatAttrName !== this.getAttribute('name')) {
|
|
2759
|
-
this.setAttribute('name', this.appName);
|
|
2821
|
+
if (formatAttrName === this.appName) {
|
|
2822
|
+
this.handleUnmount(true, () => {
|
|
2823
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
|
|
2824
|
+
});
|
|
2760
2825
|
}
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
* scene2: if formatAttrName and this.appName are different: existApp must be prefetch or unmounted, if url is equal, then just mount, if url is different, then create new app to replace existApp
|
|
2765
|
-
* scene3: url is different but ssrUrl is equal
|
|
2766
|
-
* scene4: url is equal but ssrUrl is different, if url is equal, name must different
|
|
2767
|
-
*/
|
|
2768
|
-
if (existApp &&
|
|
2769
|
-
existApp.url === this.appUrl &&
|
|
2770
|
-
existApp.ssrUrl === this.ssrUrl) {
|
|
2771
|
-
// mount app
|
|
2772
|
-
this.handleAppMount(existApp);
|
|
2826
|
+
else if (this.getDisposeResult('keep-alive')) {
|
|
2827
|
+
this.handleHiddenKeepAliveApp();
|
|
2828
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
|
|
2773
2829
|
}
|
|
2774
2830
|
else {
|
|
2775
|
-
this.
|
|
2831
|
+
this.handleUnmount(this.getDisposeResult('destroy') || this.getDisposeResult('destory'), () => {
|
|
2832
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
|
|
2833
|
+
});
|
|
2776
2834
|
}
|
|
2777
2835
|
}
|
|
2778
2836
|
}
|
|
@@ -2798,6 +2856,7 @@ function defineElement(tagName) {
|
|
|
2798
2856
|
// disableSandbox: whether disable sandbox, default is false
|
|
2799
2857
|
// macro: used to solve the async render problem of vue3, default is false
|
|
2800
2858
|
// baseRoute: route prefix, default is ''
|
|
2859
|
+
// keep-alive: open keep-alive mode, keep-alive has priority over destroy
|
|
2801
2860
|
connectedCallback() {
|
|
2802
2861
|
this.hasConnected = true;
|
|
2803
2862
|
if (!elementInstanceMap.has(this)) {
|
|
@@ -2808,10 +2867,17 @@ function defineElement(tagName) {
|
|
|
2808
2867
|
}
|
|
2809
2868
|
disconnectedCallback() {
|
|
2810
2869
|
this.hasConnected = false;
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2870
|
+
// keep-alive has priority over destroy
|
|
2871
|
+
if (this.getDisposeResult('keep-alive')) {
|
|
2872
|
+
this.handleHiddenKeepAliveApp();
|
|
2873
|
+
}
|
|
2874
|
+
else {
|
|
2875
|
+
elementInstanceMap.delete(this);
|
|
2876
|
+
this.handleUnmount(this.getDisposeResult('destroy') || this.getDisposeResult('destory'), () => {
|
|
2877
|
+
if (elementInstanceMap.size === 0) {
|
|
2878
|
+
releasePatches();
|
|
2879
|
+
}
|
|
2880
|
+
});
|
|
2815
2881
|
}
|
|
2816
2882
|
}
|
|
2817
2883
|
attributeChangedCallback(attr, _oldVal, newVal) {
|
|
@@ -2855,7 +2921,7 @@ function defineElement(tagName) {
|
|
|
2855
2921
|
if (elementInstanceMap.set(this, true).size === 1) {
|
|
2856
2922
|
patchElementPrototypeMethods();
|
|
2857
2923
|
rejectMicroAppStyle();
|
|
2858
|
-
|
|
2924
|
+
releaseUnmountOfNestedApp();
|
|
2859
2925
|
listenUmountOfNestedApp();
|
|
2860
2926
|
}
|
|
2861
2927
|
}
|
|
@@ -2874,15 +2940,21 @@ function defineElement(tagName) {
|
|
|
2874
2940
|
else if (this.ssrUrl) {
|
|
2875
2941
|
this.ssrUrl = '';
|
|
2876
2942
|
}
|
|
2877
|
-
|
|
2878
|
-
|
|
2943
|
+
if (appInstanceMap.has(this.appName)) {
|
|
2944
|
+
const app = appInstanceMap.get(this.appName);
|
|
2879
2945
|
const existAppUrl = app.ssrUrl || app.url;
|
|
2880
2946
|
const activeAppUrl = this.ssrUrl || this.appUrl;
|
|
2881
|
-
|
|
2882
|
-
|
|
2947
|
+
// keep-alive don't care about ssrUrl
|
|
2948
|
+
// Even if the keep-alive app is pushed into the background, it is still active and cannot be replaced. Otherwise, it is difficult for developers to troubleshoot in case of conflict and will leave developers at a loss
|
|
2949
|
+
if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
|
|
2950
|
+
app.url === this.appUrl) {
|
|
2951
|
+
this.handleShowKeepAliveApp(app);
|
|
2952
|
+
}
|
|
2953
|
+
else if (existAppUrl === activeAppUrl && (app.isPrefetch ||
|
|
2954
|
+
app.getAppState() === appStates.UNMOUNT)) {
|
|
2883
2955
|
this.handleAppMount(app);
|
|
2884
2956
|
}
|
|
2885
|
-
else if (app.isPrefetch || app.
|
|
2957
|
+
else if (app.isPrefetch || app.getAppState() === appStates.UNMOUNT) {
|
|
2886
2958
|
/**
|
|
2887
2959
|
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
2888
2960
|
*/
|
|
@@ -2890,7 +2962,56 @@ function defineElement(tagName) {
|
|
|
2890
2962
|
this.handleCreateApp();
|
|
2891
2963
|
}
|
|
2892
2964
|
else {
|
|
2893
|
-
logError(`an app named ${this.appName}
|
|
2965
|
+
logError(`app name conflict, an app named ${this.appName} is running`, this.appName);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
else {
|
|
2969
|
+
this.handleCreateApp();
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
// remount app or create app if attribute url or name change
|
|
2973
|
+
actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp) {
|
|
2974
|
+
var _a;
|
|
2975
|
+
/**
|
|
2976
|
+
* change ssrUrl in ssr mode
|
|
2977
|
+
* do not add judgment of formatAttrUrl === this.appUrl
|
|
2978
|
+
*/
|
|
2979
|
+
if (this.getDisposeResult('ssr')) {
|
|
2980
|
+
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, formatAttrUrl);
|
|
2981
|
+
}
|
|
2982
|
+
else if (this.ssrUrl) {
|
|
2983
|
+
this.ssrUrl = '';
|
|
2984
|
+
}
|
|
2985
|
+
this.appName = formatAttrName;
|
|
2986
|
+
this.appUrl = formatAttrUrl;
|
|
2987
|
+
((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
|
|
2988
|
+
if (formatAttrName !== this.getAttribute('name')) {
|
|
2989
|
+
this.setAttribute('name', this.appName);
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* when existApp not null: this.appName === existApp.name
|
|
2993
|
+
* scene1: if formatAttrName and this.appName are equal: exitApp is the current app, the url must be different, existApp has been unmounted
|
|
2994
|
+
* scene2: if formatAttrName and this.appName are different: existApp must be prefetch or unmounted, if url is equal, then just mount, if url is different, then create new app to replace existApp
|
|
2995
|
+
* scene3: url is different but ssrUrl is equal
|
|
2996
|
+
* scene4: url is equal but ssrUrl is different, if url is equal, name must different
|
|
2997
|
+
* scene5: if existApp is KEEP_ALIVE_HIDDEN, name must different
|
|
2998
|
+
*/
|
|
2999
|
+
if (existApp) {
|
|
3000
|
+
if (existApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
3001
|
+
if (existApp.url === this.appUrl) {
|
|
3002
|
+
this.handleShowKeepAliveApp(existApp);
|
|
3003
|
+
}
|
|
3004
|
+
else {
|
|
3005
|
+
// the hidden keep-alive app is still active
|
|
3006
|
+
logError(`app name conflict, an app named ${this.appName} is running`, this.appName);
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
else if (existApp.url === this.appUrl && existApp.ssrUrl === this.ssrUrl) {
|
|
3010
|
+
// mount app
|
|
3011
|
+
this.handleAppMount(existApp);
|
|
3012
|
+
}
|
|
3013
|
+
else {
|
|
3014
|
+
this.handleCreateApp();
|
|
2894
3015
|
}
|
|
2895
3016
|
}
|
|
2896
3017
|
else {
|
|
@@ -2950,10 +3071,24 @@ function defineElement(tagName) {
|
|
|
2950
3071
|
* unmount app
|
|
2951
3072
|
* @param destroy delete cache resources when unmount
|
|
2952
3073
|
*/
|
|
2953
|
-
handleUnmount(destroy) {
|
|
3074
|
+
handleUnmount(destroy, unmountcb) {
|
|
2954
3075
|
const app = appInstanceMap.get(this.appName);
|
|
2955
|
-
if (app &&
|
|
2956
|
-
app.
|
|
3076
|
+
if (app &&
|
|
3077
|
+
app.getAppState() !== appStates.UNMOUNT)
|
|
3078
|
+
app.unmount(destroy, unmountcb);
|
|
3079
|
+
}
|
|
3080
|
+
// hidden app when disconnectedCallback called with keep-alive
|
|
3081
|
+
handleHiddenKeepAliveApp() {
|
|
3082
|
+
const app = appInstanceMap.get(this.appName);
|
|
3083
|
+
if (app &&
|
|
3084
|
+
app.getAppState() !== appStates.UNMOUNT &&
|
|
3085
|
+
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN)
|
|
3086
|
+
app.hiddenKeepAliveApp();
|
|
3087
|
+
}
|
|
3088
|
+
// show app when connectedCallback called with keep-alive
|
|
3089
|
+
handleShowKeepAliveApp(app) {
|
|
3090
|
+
// must be asnyc
|
|
3091
|
+
defer(() => { var _a; return app.showKeepAliveApp((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this); });
|
|
2957
3092
|
}
|
|
2958
3093
|
/**
|
|
2959
3094
|
* Get configuration
|
|
@@ -3129,6 +3264,7 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
3129
3264
|
this.disableScopecss = options.disableScopecss;
|
|
3130
3265
|
this.disableSandbox = options.disableSandbox;
|
|
3131
3266
|
this.macro = options.macro;
|
|
3267
|
+
this.ssr = options.ssr;
|
|
3132
3268
|
isFunction(options.fetch) && (this.fetch = options.fetch);
|
|
3133
3269
|
isPlainObject(options.lifeCycles) && (this.lifeCycles = options.lifeCycles);
|
|
3134
3270
|
// load app assets when browser is idle
|
|
@@ -3156,5 +3292,5 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
3156
3292
|
var microApp = new MicroApp();
|
|
3157
3293
|
|
|
3158
3294
|
export default microApp;
|
|
3159
|
-
export { EventCenterForMicroApp, preFetch, pureCreateElement, removeDomScope, version };
|
|
3295
|
+
export { EventCenterForMicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, removeDomScope, version };
|
|
3160
3296
|
//# sourceMappingURL=index.esm.js.map
|