-
-
Notifications
You must be signed in to change notification settings - Fork 915
/
apps.js
161 lines (139 loc) · 4.81 KB
/
apps.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import { Loader } from '../loader.js';
import { ensureJQuerySupport } from '../jquery-support.js';
import { isActive, isLoaded, isntLoaded, toName, NOT_LOADED, shouldBeActive, shouldntBeActive, isntActive, notSkipped } from './app.helpers.js';
import { reroute } from 'src/navigation/reroute.js';
import { find } from 'src/utils/find.js';
import { toUnmountPromise } from 'src/applications/lifecycles/unmount.js';
import { toUnloadPromise, getAppUnloadInfo, addAppToUnload } from 'src/applications/lifecycles/unload.js';
const apps = [];
export function getMountedApps() {
return apps.filter(isActive).map(toName);
}
export function getAppNames() {
return app.map(toName);
}
export function getAppStatus(appName) {
const app = find(apps, app => app.name === appName);
return app ? app.status : null;
}
export function declareChildApplication(appName, arg1, arg2) {
console.warn('declareChildApplication is deprecated and will be removed in the next major version, use "registerApplication" instead')
return registerApplication(appName, arg1, arg2)
}
export function registerApplication(appName, arg1, arg2, customProps = {}) {
if (typeof appName !== 'string' || appName.length === 0)
throw new Error(`The first argument must be a non-empty string 'appName'`);
if (apps[appName])
throw new Error(`There is already an app declared with name ${appName}`);
if (typeof customProps !== 'object')
throw new Error('customProps must be an object');
let loadImpl, activeWhen;
if (!arg2) {
if (!Loader) {
throw new Error(`You cannot declare a single-spa application without either providing a way to load the application or a Loader. See https://github.com/CanopyTax/single-spa/blob/master/docs/single-spa-api.md#declareApplication`);
}
loadImpl = () => Loader.import(appName);
activeWhen = arg1;
} else {
if (typeof arg1 !== 'function') {
loadImpl = () => Promise.resolve(arg1)
} else {
loadImpl = arg1;
}
activeWhen = arg2;
}
if (typeof activeWhen !== 'function')
throw new Error(`The activeWhen argument must be a function`);
apps.push({
name: appName,
loadImpl,
activeWhen,
status: NOT_LOADED,
customProps: customProps
});
ensureJQuerySupport();
reroute();
}
export function checkActivityFunctions(location) {
const activeApps = []
for (let i = 0; i < apps.length; i++) {
if (apps[i].activeWhen(location)) {
activeApps.push(apps[i].name)
}
}
return activeApps
}
export function getAppsToLoad() {
return apps
.filter(shouldBeActive)
.filter(notSkipped)
.filter(isntLoaded)
}
export function getAppsToUnmount() {
return apps
.filter(shouldntBeActive)
.filter(notSkipped)
.filter(isActive)
}
export function getAppsToMount() {
return apps
.filter(shouldBeActive)
.filter(notSkipped)
.filter(isntActive)
.filter(isLoaded)
}
export function unloadChildApplication(appName, opts) {
console.warn('unloadChildApplication is deprecated and will be removed in the next major version, use "unloadApplication" instead')
return unloadApplication(appName, opts)
}
export function unloadApplication(appName, opts={waitForUnmount: false}) {
if (typeof appName !== 'string') {
throw new Error(`unloadApplication requires a string 'appName'`);
}
const app = find(apps, App => App.name === appName);
if (!app) {
throw new Error(`Could not unload application '${appName}' because no such application has been declared`);
}
const appUnloadInfo = getAppUnloadInfo(app.name);
if (opts && opts.waitForUnmount) {
// We need to wait for unmount before unloading the app
if (appUnloadInfo) {
// Someone else is already waiting for this, too
return appUnloadInfo.promise;
} else {
// We're the first ones wanting the app to be resolved.
const promise = new Promise((resolve, reject) => {
addAppToUnload(app, () => promise, resolve, reject);
});
return promise;
}
} else {
/* We should unmount the app, unload it, and remount it immediately.
*/
let resultPromise;
if (appUnloadInfo) {
// Someone else is already waiting for this app to unload
resultPromise = appUnloadInfo.promise;
immediatelyUnloadApp(app, appUnloadInfo.resolve, appUnloadInfo.reject);
} else {
// We're the first ones wanting the app to be resolved.
resultPromise = new Promise((resolve, reject) => {
addAppToUnload(app, () => resultPromise, resolve, reject);
immediatelyUnloadApp(app, resolve, reject);
});
}
return resultPromise;
}
}
function immediatelyUnloadApp(app, resolve, reject) {
toUnmountPromise(app)
.then(toUnloadPromise)
.then(() => {
resolve()
setTimeout(() => {
// reroute, but the unload promise is done
reroute()
});
})
.catch(reject);
}