NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/single-spa/lib/es2015/single-spa.dev.js
2023-09-14 14:47:11 +08:00

1639 lines
54 KiB
Java

/* single-spa@5.9.4 - ES2015 - dev */
var singleSpa = /*#__PURE__*/Object.freeze({
__proto__: null,
get start () { return start; },
get ensureJQuerySupport () { return ensureJQuerySupport; },
get setBootstrapMaxTime () { return setBootstrapMaxTime; },
get setMountMaxTime () { return setMountMaxTime; },
get setUnmountMaxTime () { return setUnmountMaxTime; },
get setUnloadMaxTime () { return setUnloadMaxTime; },
get registerApplication () { return registerApplication; },
get unregisterApplication () { return unregisterApplication; },
get getMountedApps () { return getMountedApps; },
get getAppStatus () { return getAppStatus; },
get unloadApplication () { return unloadApplication; },
get checkActivityFunctions () { return checkActivityFunctions; },
get getAppNames () { return getAppNames; },
get pathToActiveWhen () { return pathToActiveWhen; },
get navigateToUrl () { return navigateToUrl; },
get triggerAppChange () { return triggerAppChange; },
get addErrorHandler () { return addErrorHandler; },
get removeErrorHandler () { return removeErrorHandler; },
get mountRootParcel () { return mountRootParcel; },
get NOT_LOADED () { return NOT_LOADED; },
get LOADING_SOURCE_CODE () { return LOADING_SOURCE_CODE; },
get NOT_BOOTSTRAPPED () { return NOT_BOOTSTRAPPED; },
get BOOTSTRAPPING () { return BOOTSTRAPPING; },
get NOT_MOUNTED () { return NOT_MOUNTED; },
get MOUNTING () { return MOUNTING; },
get UPDATING () { return UPDATING; },
get LOAD_ERROR () { return LOAD_ERROR; },
get MOUNTED () { return MOUNTED; },
get UNMOUNTING () { return UNMOUNTING; },
get SKIP_BECAUSE_BROKEN () { return SKIP_BECAUSE_BROKEN; }
});
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
var NativeCustomEvent = commonjsGlobal.CustomEvent;
function useNative () {
try {
var p = new NativeCustomEvent('cat', { detail: { foo: 'bar' } });
return 'cat' === p.type && 'bar' === p.detail.foo;
} catch (e) {
}
return false;
}
/**
* Cross-browser `CustomEvent` constructor.
*
* https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent.CustomEvent
*
* @public
*/
var customEvent = useNative() ? NativeCustomEvent :
// IE >= 9
'undefined' !== typeof document && 'function' === typeof document.createEvent ? function CustomEvent (type, params) {
var e = document.createEvent('CustomEvent');
if (params) {
e.initCustomEvent(type, params.bubbles, params.cancelable, params.detail);
} else {
e.initCustomEvent(type, false, false, void 0);
}
return e;
} :
// IE <= 8
function CustomEvent (type, params) {
var e = document.createEventObject();
e.type = type;
if (params) {
e.bubbles = Boolean(params.bubbles);
e.cancelable = Boolean(params.cancelable);
e.detail = params.detail;
} else {
e.bubbles = false;
e.cancelable = false;
e.detail = void 0;
}
return e;
};
let errorHandlers = [];
function handleAppError(err, app, newStatus) {
const transformedErr = transformErr(err, app, newStatus);
if (errorHandlers.length) {
errorHandlers.forEach(handler => handler(transformedErr));
} else {
setTimeout(() => {
throw transformedErr;
});
}
}
function addErrorHandler(handler) {
if (typeof handler !== "function") {
throw Error(formatErrorMessage(28, "a single-spa error handler must be a function"));
}
errorHandlers.push(handler);
}
function removeErrorHandler(handler) {
if (typeof handler !== "function") {
throw Error(formatErrorMessage(29, "a single-spa error handler must be a function"));
}
let removedSomething = false;
errorHandlers = errorHandlers.filter(h => {
const isHandler = h === handler;
removedSomething = removedSomething || isHandler;
return !isHandler;
});
return removedSomething;
}
function formatErrorMessage(code, msg, ...args) {
return `single-spa minified message #${code}: ${msg ? msg + " " : ""}See https://single-spa.js.org/error/?code=${code}${args.length ? `&arg=${args.join("&arg=")}` : ""}`;
}
function transformErr(ogErr, appOrParcel, newStatus) {
const errPrefix = `${objectType(appOrParcel)} '${toName(appOrParcel)}' died in status ${appOrParcel.status}: `;
let result;
if (ogErr instanceof Error) {
try {
ogErr.message = errPrefix + ogErr.message;
} catch (err) {
/* Some errors have read-only message properties, in which case there is nothing
* that we can do.
*/
}
result = ogErr;
} else {
console.warn(formatErrorMessage(30, `While ${appOrParcel.status}, '${toName(appOrParcel)}' rejected its lifecycle function promise with a non-Error. This will cause stack traces to not be accurate.`, appOrParcel.status, toName(appOrParcel)));
try {
result = Error(errPrefix + JSON.stringify(ogErr));
} catch (err) {
// If it's not an Error and you can't stringify it, then what else can you even do to it?
result = ogErr;
}
}
result.appOrParcelName = toName(appOrParcel); // We set the status after transforming the error so that the error message
// references the state the application was in before the status change.
appOrParcel.status = newStatus;
return result;
}
const NOT_LOADED = "NOT_LOADED";
const LOADING_SOURCE_CODE = "LOADING_SOURCE_CODE";
const NOT_BOOTSTRAPPED = "NOT_BOOTSTRAPPED";
const BOOTSTRAPPING = "BOOTSTRAPPING";
const NOT_MOUNTED = "NOT_MOUNTED";
const MOUNTING = "MOUNTING";
const MOUNTED = "MOUNTED";
const UPDATING = "UPDATING";
const UNMOUNTING = "UNMOUNTING";
const UNLOADING = "UNLOADING";
const LOAD_ERROR = "LOAD_ERROR";
const SKIP_BECAUSE_BROKEN = "SKIP_BECAUSE_BROKEN";
function isActive(app) {
return app.status === MOUNTED;
}
function shouldBeActive(app) {
try {
return app.activeWhen(window.location);
} catch (err) {
handleAppError(err, app, SKIP_BECAUSE_BROKEN);
return false;
}
}
function toName(app) {
return app.name;
}
function isParcel(appOrParcel) {
return Boolean(appOrParcel.unmountThisParcel);
}
function objectType(appOrParcel) {
return isParcel(appOrParcel) ? "parcel" : "application";
}
// Object.assign() is not available in IE11. And the babel compiled output for object spread
// syntax checks a bunch of Symbol stuff and is almost a kb. So this function is the smaller replacement.
function assign() {
for (let i = arguments.length - 1; i > 0; i--) {
for (let key in arguments[i]) {
if (key === "__proto__") {
continue;
}
arguments[i - 1][key] = arguments[i][key];
}
}
return arguments[0];
}
/* the array.prototype.find polyfill on npmjs.com is ~20kb (not worth it)
* and lodash is ~200kb (not worth it)
*/
function find(arr, func) {
for (let i = 0; i < arr.length; i++) {
if (func(arr[i])) {
return arr[i];
}
}
return null;
}
function validLifecycleFn(fn) {
return fn && (typeof fn === "function" || isArrayOfFns(fn));
function isArrayOfFns(arr) {
return Array.isArray(arr) && !find(arr, item => typeof item !== "function");
}
}
function flattenFnArray(appOrParcel, lifecycle) {
let fns = appOrParcel[lifecycle] || [];
fns = Array.isArray(fns) ? fns : [fns];
if (fns.length === 0) {
fns = [() => Promise.resolve()];
}
const type = objectType(appOrParcel);
const name = toName(appOrParcel);
return function (props) {
return fns.reduce((resultPromise, fn, index) => {
return resultPromise.then(() => {
const thisPromise = fn(props);
return smellsLikeAPromise(thisPromise) ? thisPromise : Promise.reject(formatErrorMessage(15, `Within ${type} ${name}, the lifecycle function ${lifecycle} at array index ${index} did not return a promise`, type, name, lifecycle, index));
});
}, Promise.resolve());
};
}
function smellsLikeAPromise(promise) {
return promise && typeof promise.then === "function" && typeof promise.catch === "function";
}
function toBootstrapPromise(appOrParcel, hardFail) {
return Promise.resolve().then(() => {
if (appOrParcel.status !== NOT_BOOTSTRAPPED) {
return appOrParcel;
}
appOrParcel.status = BOOTSTRAPPING;
if (!appOrParcel.bootstrap) {
// Default implementation of bootstrap
return Promise.resolve().then(successfulBootstrap);
}
return reasonableTime(appOrParcel, "bootstrap").then(successfulBootstrap).catch(err => {
if (hardFail) {
throw transformErr(err, appOrParcel, SKIP_BECAUSE_BROKEN);
} else {
handleAppError(err, appOrParcel, SKIP_BECAUSE_BROKEN);
return appOrParcel;
}
});
});
function successfulBootstrap() {
appOrParcel.status = NOT_MOUNTED;
return appOrParcel;
}
}
function toUnmountPromise(appOrParcel, hardFail) {
return Promise.resolve().then(() => {
if (appOrParcel.status !== MOUNTED) {
return appOrParcel;
}
appOrParcel.status = UNMOUNTING;
const unmountChildrenParcels = Object.keys(appOrParcel.parcels).map(parcelId => appOrParcel.parcels[parcelId].unmountThisParcel());
return Promise.all(unmountChildrenParcels).then(unmountAppOrParcel, parcelError => {
// There is a parcel unmount error
return unmountAppOrParcel().then(() => {
// Unmounting the app/parcel succeeded, but unmounting its children parcels did not
const parentError = Error(parcelError.message);
if (hardFail) {
throw transformErr(parentError, appOrParcel, SKIP_BECAUSE_BROKEN);
} else {
handleAppError(parentError, appOrParcel, SKIP_BECAUSE_BROKEN);
}
});
}).then(() => appOrParcel);
function unmountAppOrParcel() {
// We always try to unmount the appOrParcel, even if the children parcels failed to unmount.
return reasonableTime(appOrParcel, "unmount").then(() => {
// The appOrParcel needs to stay in a broken status if its children parcels fail to unmount
{
appOrParcel.status = NOT_MOUNTED;
}
}).catch(err => {
if (hardFail) {
throw transformErr(err, appOrParcel, SKIP_BECAUSE_BROKEN);
} else {
handleAppError(err, appOrParcel, SKIP_BECAUSE_BROKEN);
}
});
}
});
}
let beforeFirstMountFired = false;
let firstMountFired = false;
function toMountPromise(appOrParcel, hardFail) {
return Promise.resolve().then(() => {
if (appOrParcel.status !== NOT_MOUNTED) {
return appOrParcel;
}
if (!beforeFirstMountFired) {
window.dispatchEvent(new customEvent("single-spa:before-first-mount"));
beforeFirstMountFired = true;
}
return reasonableTime(appOrParcel, "mount").then(() => {
appOrParcel.status = MOUNTED;
if (!firstMountFired) {
window.dispatchEvent(new customEvent("single-spa:first-mount"));
firstMountFired = true;
}
return appOrParcel;
}).catch(err => {
// If we fail to mount the appOrParcel, we should attempt to unmount it before putting in SKIP_BECAUSE_BROKEN
// We temporarily put the appOrParcel into MOUNTED status so that toUnmountPromise actually attempts to unmount it
// instead of just doing a no-op.
appOrParcel.status = MOUNTED;
return toUnmountPromise(appOrParcel, true).then(setSkipBecauseBroken, setSkipBecauseBroken);
function setSkipBecauseBroken() {
if (!hardFail) {
handleAppError(err, appOrParcel, SKIP_BECAUSE_BROKEN);
return appOrParcel;
} else {
throw transformErr(err, appOrParcel, SKIP_BECAUSE_BROKEN);
}
}
});
});
}
function toUpdatePromise(parcel) {
return Promise.resolve().then(() => {
if (parcel.status !== MOUNTED) {
throw Error(formatErrorMessage(32, `Cannot update parcel '${toName(parcel)}' because it is not mounted`, toName(parcel)));
}
parcel.status = UPDATING;
return reasonableTime(parcel, "update").then(() => {
parcel.status = MOUNTED;
return parcel;
}).catch(err => {
throw transformErr(err, parcel, SKIP_BECAUSE_BROKEN);
});
});
}
let parcelCount = 0;
const rootParcels = {
parcels: {}
}; // This is a public api, exported to users of single-spa
function mountRootParcel() {
return mountParcel.apply(rootParcels, arguments);
}
function mountParcel(config, customProps) {
const owningAppOrParcel = this; // Validate inputs
if (!config || typeof config !== "object" && typeof config !== "function") {
throw Error(formatErrorMessage(2, "Cannot mount parcel without a config object or config loading function"));
}
if (config.name && typeof config.name !== "string") {
throw Error(formatErrorMessage(3, `Parcel name must be a string, if provided. Was given ${typeof config.name}`, typeof config.name));
}
if (typeof customProps !== "object") {
throw Error(formatErrorMessage(4, `Parcel ${name} has invalid customProps -- must be an object but was given ${typeof customProps}`, name, typeof customProps));
}
if (!customProps.domElement) {
throw Error(formatErrorMessage(5, `Parcel ${name} cannot be mounted without a domElement provided as a prop`, name));
}
const id = parcelCount++;
const passedConfigLoadingFunction = typeof config === "function";
const configLoadingFunction = passedConfigLoadingFunction ? config : () => Promise.resolve(config); // Internal representation
const parcel = {
id,
parcels: {},
status: passedConfigLoadingFunction ? LOADING_SOURCE_CODE : NOT_BOOTSTRAPPED,
customProps,
parentName: toName(owningAppOrParcel),
unmountThisParcel() {
return mountPromise.then(() => {
if (parcel.status !== MOUNTED) {
throw Error(formatErrorMessage(6, `Cannot unmount parcel '${name}' -- it is in a ${parcel.status} status`, name, parcel.status));
}
return toUnmountPromise(parcel, true);
}).then(value => {
if (parcel.parentName) {
delete owningAppOrParcel.parcels[parcel.id];
}
return value;
}).then(value => {
resolveUnmount(value);
return value;
}).catch(err => {
parcel.status = SKIP_BECAUSE_BROKEN;
rejectUnmount(err);
throw err;
});
}
}; // We return an external representation
let externalRepresentation; // Add to owning app or parcel
owningAppOrParcel.parcels[id] = parcel;
let loadPromise = configLoadingFunction();
if (!loadPromise || typeof loadPromise.then !== "function") {
throw Error(formatErrorMessage(7, `When mounting a parcel, the config loading function must return a promise that resolves with the parcel config`));
}
loadPromise = loadPromise.then(config => {
if (!config) {
throw Error(formatErrorMessage(8, `When mounting a parcel, the config loading function returned a promise that did not resolve with a parcel config`));
}
const name = config.name || `parcel-${id}`;
if ( // ES Module objects don't have the object prototype
Object.prototype.hasOwnProperty.call(config, "bootstrap") && !validLifecycleFn(config.bootstrap)) {
throw Error(formatErrorMessage(9, `Parcel ${name} provided an invalid bootstrap function`, name));
}
if (!validLifecycleFn(config.mount)) {
throw Error(formatErrorMessage(10, `Parcel ${name} must have a valid mount function`, name));
}
if (!validLifecycleFn(config.unmount)) {
throw Error(formatErrorMessage(11, `Parcel ${name} must have a valid unmount function`, name));
}
if (config.update && !validLifecycleFn(config.update)) {
throw Error(formatErrorMessage(12, `Parcel ${name} provided an invalid update function`, name));
}
const bootstrap = flattenFnArray(config, "bootstrap");
const mount = flattenFnArray(config, "mount");
const unmount = flattenFnArray(config, "unmount");
parcel.status = NOT_BOOTSTRAPPED;
parcel.name = name;
parcel.bootstrap = bootstrap;
parcel.mount = mount;
parcel.unmount = unmount;
parcel.timeouts = ensureValidAppTimeouts(config.timeouts);
if (config.update) {
parcel.update = flattenFnArray(config, "update");
externalRepresentation.update = function (customProps) {
parcel.customProps = customProps;
return promiseWithoutReturnValue(toUpdatePromise(parcel));
};
}
}); // Start bootstrapping and mounting
// The .then() causes the work to be put on the event loop instead of happening immediately
const bootstrapPromise = loadPromise.then(() => toBootstrapPromise(parcel, true));
const mountPromise = bootstrapPromise.then(() => toMountPromise(parcel, true));
let resolveUnmount, rejectUnmount;
const unmountPromise = new Promise((resolve, reject) => {
resolveUnmount = resolve;
rejectUnmount = reject;
});
externalRepresentation = {
mount() {
return promiseWithoutReturnValue(Promise.resolve().then(() => {
if (parcel.status !== NOT_MOUNTED) {
throw Error(formatErrorMessage(13, `Cannot mount parcel '${name}' -- it is in a ${parcel.status} status`, name, parcel.status));
} // Add to owning app or parcel
owningAppOrParcel.parcels[id] = parcel;
return toMountPromise(parcel);
}));
},
unmount() {
return promiseWithoutReturnValue(parcel.unmountThisParcel());
},
getStatus() {
return parcel.status;
},
loadPromise: promiseWithoutReturnValue(loadPromise),
bootstrapPromise: promiseWithoutReturnValue(bootstrapPromise),
mountPromise: promiseWithoutReturnValue(mountPromise),
unmountPromise: promiseWithoutReturnValue(unmountPromise)
};
return externalRepresentation;
}
function promiseWithoutReturnValue(promise) {
return promise.then(() => null);
}
function getProps(appOrParcel) {
const name = toName(appOrParcel);
let customProps = typeof appOrParcel.customProps === "function" ? appOrParcel.customProps(name, window.location) : appOrParcel.customProps;
if (typeof customProps !== "object" || customProps === null || Array.isArray(customProps)) {
customProps = {};
console.warn(formatErrorMessage(40, `single-spa: ${name}'s customProps function must return an object. Received ${customProps}`), name, customProps);
}
const result = assign({}, customProps, {
name,
mountParcel: mountParcel.bind(appOrParcel),
singleSpa
});
if (isParcel(appOrParcel)) {
result.unmountSelf = appOrParcel.unmountThisParcel;
}
return result;
}
const defaultWarningMillis = 1000;
const globalTimeoutConfig = {
bootstrap: {
millis: 4000,
dieOnTimeout: false,
warningMillis: defaultWarningMillis
},
mount: {
millis: 3000,
dieOnTimeout: false,
warningMillis: defaultWarningMillis
},
unmount: {
millis: 3000,
dieOnTimeout: false,
warningMillis: defaultWarningMillis
},
unload: {
millis: 3000,
dieOnTimeout: false,
warningMillis: defaultWarningMillis
},
update: {
millis: 3000,
dieOnTimeout: false,
warningMillis: defaultWarningMillis
}
};
function setBootstrapMaxTime(time, dieOnTimeout, warningMillis) {
if (typeof time !== "number" || time <= 0) {
throw Error(formatErrorMessage(16, `bootstrap max time must be a positive integer number of milliseconds`));
}
globalTimeoutConfig.bootstrap = {
millis: time,
dieOnTimeout,
warningMillis: warningMillis || defaultWarningMillis
};
}
function setMountMaxTime(time, dieOnTimeout, warningMillis) {
if (typeof time !== "number" || time <= 0) {
throw Error(formatErrorMessage(17, `mount max time must be a positive integer number of milliseconds`));
}
globalTimeoutConfig.mount = {
millis: time,
dieOnTimeout,
warningMillis: warningMillis || defaultWarningMillis
};
}
function setUnmountMaxTime(time, dieOnTimeout, warningMillis) {
if (typeof time !== "number" || time <= 0) {
throw Error(formatErrorMessage(18, `unmount max time must be a positive integer number of milliseconds`));
}
globalTimeoutConfig.unmount = {
millis: time,
dieOnTimeout,
warningMillis: warningMillis || defaultWarningMillis
};
}
function setUnloadMaxTime(time, dieOnTimeout, warningMillis) {
if (typeof time !== "number" || time <= 0) {
throw Error(formatErrorMessage(19, `unload max time must be a positive integer number of milliseconds`));
}
globalTimeoutConfig.unload = {
millis: time,
dieOnTimeout,
warningMillis: warningMillis || defaultWarningMillis
};
}
function reasonableTime(appOrParcel, lifecycle) {
const timeoutConfig = appOrParcel.timeouts[lifecycle];
const warningPeriod = timeoutConfig.warningMillis;
const type = objectType(appOrParcel);
return new Promise((resolve, reject) => {
let finished = false;
let errored = false;
appOrParcel[lifecycle](getProps(appOrParcel)).then(val => {
finished = true;
resolve(val);
}).catch(val => {
finished = true;
reject(val);
});
setTimeout(() => maybeTimingOut(1), warningPeriod);
setTimeout(() => maybeTimingOut(true), timeoutConfig.millis);
const errMsg = formatErrorMessage(31, `Lifecycle function ${lifecycle} for ${type} ${toName(appOrParcel)} lifecycle did not resolve or reject for ${timeoutConfig.millis} ms.`, lifecycle, type, toName(appOrParcel), timeoutConfig.millis);
function maybeTimingOut(shouldError) {
if (!finished) {
if (shouldError === true) {
errored = true;
if (timeoutConfig.dieOnTimeout) {
reject(Error(errMsg));
} else {
console.error(errMsg); //don't resolve or reject, we're waiting this one out
}
} else if (!errored) {
const numWarnings = shouldError;
const numMillis = numWarnings * warningPeriod;
console.warn(errMsg);
if (numMillis + warningPeriod < timeoutConfig.millis) {
setTimeout(() => maybeTimingOut(numWarnings + 1), warningPeriod);
}
}
}
}
});
}
function ensureValidAppTimeouts(timeouts) {
const result = {};
for (let key in globalTimeoutConfig) {
result[key] = assign({}, globalTimeoutConfig[key], timeouts && timeouts[key] || {});
}
return result;
}
function toLoadPromise(app) {
return Promise.resolve().then(() => {
if (app.loadPromise) {
return app.loadPromise;
}
if (app.status !== NOT_LOADED && app.status !== LOAD_ERROR) {
return app;
}
app.status = LOADING_SOURCE_CODE;
let appOpts, isUserErr;
return app.loadPromise = Promise.resolve().then(() => {
const loadPromise = app.loadApp(getProps(app));
if (!smellsLikeAPromise(loadPromise)) {
// The name of the app will be prepended to this error message inside of the handleAppError function
isUserErr = true;
throw Error(formatErrorMessage(33, `single-spa loading function did not return a promise. Check the second argument to registerApplication('${toName(app)}', loadingFunction, activityFunction)`, toName(app)));
}
return loadPromise.then(val => {
app.loadErrorTime = null;
appOpts = val;
let validationErrMessage, validationErrCode;
if (typeof appOpts !== "object") {
validationErrCode = 34;
{
validationErrMessage = `does not export anything`;
}
}
if ( // ES Modules don't have the Object prototype
Object.prototype.hasOwnProperty.call(appOpts, "bootstrap") && !validLifecycleFn(appOpts.bootstrap)) {
validationErrCode = 35;
{
validationErrMessage = `does not export a valid bootstrap function or array of functions`;
}
}
if (!validLifecycleFn(appOpts.mount)) {
validationErrCode = 36;
{
validationErrMessage = `does not export a mount function or array of functions`;
}
}
if (!validLifecycleFn(appOpts.unmount)) {
validationErrCode = 37;
{
validationErrMessage = `does not export a unmount function or array of functions`;
}
}
const type = objectType(appOpts);
if (validationErrCode) {
let appOptsStr;
try {
appOptsStr = JSON.stringify(appOpts);
} catch (_unused) {}
console.error(formatErrorMessage(validationErrCode, `The loading function for single-spa ${type} '${toName(app)}' resolved with the following, which does not have bootstrap, mount, and unmount functions`, type, toName(app), appOptsStr), appOpts);
handleAppError(validationErrMessage, app, SKIP_BECAUSE_BROKEN);
return app;
}
if (appOpts.devtools && appOpts.devtools.overlays) {
app.devtools.overlays = assign({}, app.devtools.overlays, appOpts.devtools.overlays);
}
app.status = NOT_BOOTSTRAPPED;
app.bootstrap = flattenFnArray(appOpts, "bootstrap");
app.mount = flattenFnArray(appOpts, "mount");
app.unmount = flattenFnArray(appOpts, "unmount");
app.unload = flattenFnArray(appOpts, "unload");
app.timeouts = ensureValidAppTimeouts(appOpts.timeouts);
delete app.loadPromise;
return app;
});
}).catch(err => {
delete app.loadPromise;
let newStatus;
if (isUserErr) {
newStatus = SKIP_BECAUSE_BROKEN;
} else {
newStatus = LOAD_ERROR;
app.loadErrorTime = new Date().getTime();
}
handleAppError(err, app, newStatus);
return app;
});
});
}
const isInBrowser = typeof window !== "undefined";
/* We capture navigation event listeners so that we can make sure
* that application navigation listeners are not called until
* single-spa has ensured that the correct applications are
* unmounted and mounted.
*/
const capturedEventListeners = {
hashchange: [],
popstate: []
};
const routingEventsListeningTo = ["hashchange", "popstate"];
function navigateToUrl(obj) {
let url;
if (typeof obj === "string") {
url = obj;
} else if (this && this.href) {
url = this.href;
} else if (obj && obj.currentTarget && obj.currentTarget.href && obj.preventDefault) {
url = obj.currentTarget.href;
obj.preventDefault();
} else {
throw Error(formatErrorMessage(14, `singleSpaNavigate/navigateToUrl must be either called with a string url, with an <a> tag as its context, or with an event whose currentTarget is an <a> tag`));
}
const current = parseUri(window.location.href);
const destination = parseUri(url);
if (url.indexOf("#") === 0) {
window.location.hash = destination.hash;
} else if (current.host !== destination.host && destination.host) {
{
window.location.href = url;
}
} else if (destination.pathname === current.pathname && destination.search === current.search) {
window.location.hash = destination.hash;
} else {
// different path, host, or query params
window.history.pushState(null, null, url);
}
}
function callCapturedEventListeners(eventArguments) {
if (eventArguments) {
const eventType = eventArguments[0].type;
if (routingEventsListeningTo.indexOf(eventType) >= 0) {
capturedEventListeners[eventType].forEach(listener => {
try {
// The error thrown by application event listener should not break single-spa down.
// Just like https://github.com/single-spa/single-spa/blob/85f5042dff960e40936f3a5069d56fc9477fac04/src/navigation/reroute.js#L140-L146 did
listener.apply(this, eventArguments);
} catch (e) {
setTimeout(() => {
throw e;
});
}
});
}
}
}
let urlRerouteOnly;
function setUrlRerouteOnly(val) {
urlRerouteOnly = val;
}
function urlReroute() {
reroute([], arguments);
}
function patchedUpdateState(updateState, methodName) {
return function () {
const urlBefore = window.location.href;
const result = updateState.apply(this, arguments);
const urlAfter = window.location.href;
if (!urlRerouteOnly || urlBefore !== urlAfter) {
if (isStarted()) {
// fire an artificial popstate event once single-spa is started,
// so that single-spa applications know about routing that
// occurs in a different application
window.dispatchEvent(createPopStateEvent(window.history.state, methodName));
} else {
// do not fire an artificial popstate event before single-spa is started,
// since no single-spa applications need to know about routing events
// outside of their own router.
reroute([]);
}
}
return result;
};
}
function createPopStateEvent(state, originalMethodName) {
// https://github.com/single-spa/single-spa/issues/224 and https://github.com/single-spa/single-spa-angular/issues/49
// We need a popstate event even though the browser doesn't do one by default when you call replaceState, so that
// all the applications can reroute. We explicitly identify this extraneous event by setting singleSpa=true and
// singleSpaTrigger=<pushState|replaceState> on the event instance.
let evt;
try {
evt = new PopStateEvent("popstate", {
state
});
} catch (err) {
// IE 11 compatibility https://github.com/single-spa/single-spa/issues/299
// https://docs.microsoft.com/en-us/openspecs/ie_standards/ms-html5e/bd560f47-b349-4d2c-baa8-f1560fb489dd
evt = document.createEvent("PopStateEvent");
evt.initPopStateEvent("popstate", false, false, state);
}
evt.singleSpa = true;
evt.singleSpaTrigger = originalMethodName;
return evt;
}
if (isInBrowser) {
// We will trigger an app change for any routing events.
window.addEventListener("hashchange", urlReroute);
window.addEventListener("popstate", urlReroute); // Monkeypatch addEventListener so that we can ensure correct timing
const originalAddEventListener = window.addEventListener;
const originalRemoveEventListener = window.removeEventListener;
window.addEventListener = function (eventName, fn) {
if (typeof fn === "function") {
if (routingEventsListeningTo.indexOf(eventName) >= 0 && !find(capturedEventListeners[eventName], listener => listener === fn)) {
capturedEventListeners[eventName].push(fn);
return;
}
}
return originalAddEventListener.apply(this, arguments);
};
window.removeEventListener = function (eventName, listenerFn) {
if (typeof listenerFn === "function") {
if (routingEventsListeningTo.indexOf(eventName) >= 0) {
capturedEventListeners[eventName] = capturedEventListeners[eventName].filter(fn => fn !== listenerFn);
return;
}
}
return originalRemoveEventListener.apply(this, arguments);
};
window.history.pushState = patchedUpdateState(window.history.pushState, "pushState");
window.history.replaceState = patchedUpdateState(window.history.replaceState, "replaceState");
if (window.singleSpaNavigate) {
console.warn(formatErrorMessage(41, "single-spa has been loaded twice on the page. This can result in unexpected behavior."));
} else {
/* For convenience in `onclick` attributes, we expose a global function for navigating to
* whatever an <a> tag's href is.
*/
window.singleSpaNavigate = navigateToUrl;
}
}
function parseUri(str) {
const anchor = document.createElement("a");
anchor.href = str;
return anchor;
}
let hasInitialized = false;
function ensureJQuerySupport(jQuery = window.jQuery) {
if (!jQuery) {
if (window.$ && window.$.fn && window.$.fn.jquery) {
jQuery = window.$;
}
}
if (jQuery && !hasInitialized) {
const originalJQueryOn = jQuery.fn.on;
const originalJQueryOff = jQuery.fn.off;
jQuery.fn.on = function (eventString, fn) {
return captureRoutingEvents.call(this, originalJQueryOn, window.addEventListener, eventString, fn, arguments);
};
jQuery.fn.off = function (eventString, fn) {
return captureRoutingEvents.call(this, originalJQueryOff, window.removeEventListener, eventString, fn, arguments);
};
hasInitialized = true;
}
}
function captureRoutingEvents(originalJQueryFunction, nativeFunctionToCall, eventString, fn, originalArgs) {
if (typeof eventString !== "string") {
return originalJQueryFunction.apply(this, originalArgs);
}
const eventNames = eventString.split(/\s+/);
eventNames.forEach(eventName => {
if (routingEventsListeningTo.indexOf(eventName) >= 0) {
nativeFunctionToCall(eventName, fn);
eventString = eventString.replace(eventName, "");
}
});
if (eventString.trim() === "") {
return this;
} else {
return originalJQueryFunction.apply(this, originalArgs);
}
}
const appsToUnload = {};
function toUnloadPromise(app) {
return Promise.resolve().then(() => {
const unloadInfo = appsToUnload[toName(app)];
if (!unloadInfo) {
/* No one has called unloadApplication for this app,
*/
return app;
}
if (app.status === NOT_LOADED) {
/* This app is already unloaded. We just need to clean up
* anything that still thinks we need to unload the app.
*/
finishUnloadingApp(app, unloadInfo);
return app;
}
if (app.status === UNLOADING) {
/* Both unloadApplication and reroute want to unload this app.
* It only needs to be done once, though.
*/
return unloadInfo.promise.then(() => app);
}
if (app.status !== NOT_MOUNTED && app.status !== LOAD_ERROR) {
/* The app cannot be unloaded until it is unmounted.
*/
return app;
}
const unloadPromise = app.status === LOAD_ERROR ? Promise.resolve() : reasonableTime(app, "unload");
app.status = UNLOADING;
return unloadPromise.then(() => {
finishUnloadingApp(app, unloadInfo);
return app;
}).catch(err => {
errorUnloadingApp(app, unloadInfo, err);
return app;
});
});
}
function finishUnloadingApp(app, unloadInfo) {
delete appsToUnload[toName(app)]; // Unloaded apps don't have lifecycles
delete app.bootstrap;
delete app.mount;
delete app.unmount;
delete app.unload;
app.status = NOT_LOADED;
/* resolve the promise of whoever called unloadApplication.
* This should be done after all other cleanup/bookkeeping
*/
unloadInfo.resolve();
}
function errorUnloadingApp(app, unloadInfo, err) {
delete appsToUnload[toName(app)]; // Unloaded apps don't have lifecycles
delete app.bootstrap;
delete app.mount;
delete app.unmount;
delete app.unload;
handleAppError(err, app, SKIP_BECAUSE_BROKEN);
unloadInfo.reject(err);
}
function addAppToUnload(app, promiseGetter, resolve, reject) {
appsToUnload[toName(app)] = {
app,
resolve,
reject
};
Object.defineProperty(appsToUnload[toName(app)], "promise", {
get: promiseGetter
});
}
function getAppUnloadInfo(appName) {
return appsToUnload[appName];
}
const apps = [];
function getAppChanges() {
const appsToUnload = [],
appsToUnmount = [],
appsToLoad = [],
appsToMount = []; // We re-attempt to download applications in LOAD_ERROR after a timeout of 200 milliseconds
const currentTime = new Date().getTime();
apps.forEach(app => {
const appShouldBeActive = app.status !== SKIP_BECAUSE_BROKEN && shouldBeActive(app);
switch (app.status) {
case LOAD_ERROR:
if (appShouldBeActive && currentTime - app.loadErrorTime >= 200) {
appsToLoad.push(app);
}
break;
case NOT_LOADED:
case LOADING_SOURCE_CODE:
if (appShouldBeActive) {
appsToLoad.push(app);
}
break;
case NOT_BOOTSTRAPPED:
case NOT_MOUNTED:
if (!appShouldBeActive && getAppUnloadInfo(toName(app))) {
appsToUnload.push(app);
} else if (appShouldBeActive) {
appsToMount.push(app);
}
break;
case MOUNTED:
if (!appShouldBeActive) {
appsToUnmount.push(app);
}
break;
// all other statuses are ignored
}
});
return {
appsToUnload,
appsToUnmount,
appsToLoad,
appsToMount
};
}
function getMountedApps() {
return apps.filter(isActive).map(toName);
}
function getAppNames() {
return apps.map(toName);
} // used in devtools, not (currently) exposed as a single-spa API
function getRawAppData() {
return [...apps];
}
function getAppStatus(appName) {
const app = find(apps, app => toName(app) === appName);
return app ? app.status : null;
}
function registerApplication(appNameOrConfig, appOrLoadApp, activeWhen, customProps) {
const registration = sanitizeArguments(appNameOrConfig, appOrLoadApp, activeWhen, customProps);
if (getAppNames().indexOf(registration.name) !== -1) throw Error(formatErrorMessage(21, `There is already an app registered with name ${registration.name}`, registration.name));
apps.push(assign({
loadErrorTime: null,
status: NOT_LOADED,
parcels: {},
devtools: {
overlays: {
options: {},
selectors: []
}
}
}, registration));
if (isInBrowser) {
ensureJQuerySupport();
reroute();
}
}
function checkActivityFunctions(location = window.location) {
return apps.filter(app => app.activeWhen(location)).map(toName);
}
function unregisterApplication(appName) {
if (apps.filter(app => toName(app) === appName).length === 0) {
throw Error(formatErrorMessage(25, `Cannot unregister application '${appName}' because no such application has been registered`, appName));
}
return unloadApplication(appName).then(() => {
const appIndex = apps.map(toName).indexOf(appName);
apps.splice(appIndex, 1);
});
}
function unloadApplication(appName, opts = {
waitForUnmount: false
}) {
if (typeof appName !== "string") {
throw Error(formatErrorMessage(26, `unloadApplication requires a string 'appName'`));
}
const app = find(apps, App => toName(App) === appName);
if (!app) {
throw Error(formatErrorMessage(27, `Could not unload application '${appName}' because no such application has been registered`, appName));
}
const appUnloadInfo = getAppUnloadInfo(toName(app));
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);
}
function validateRegisterWithArguments(name, appOrLoadApp, activeWhen, customProps) {
if (typeof name !== "string" || name.length === 0) throw Error(formatErrorMessage(20, `The 1st argument to registerApplication must be a non-empty string 'appName'`));
if (!appOrLoadApp) throw Error(formatErrorMessage(23, "The 2nd argument to registerApplication must be an application or loading application function"));
if (typeof activeWhen !== "function") throw Error(formatErrorMessage(24, "The 3rd argument to registerApplication must be an activeWhen function"));
if (!validCustomProps(customProps)) throw Error(formatErrorMessage(22, "The optional 4th argument is a customProps and must be an object"));
}
function validateRegisterWithConfig(config) {
if (Array.isArray(config) || config === null) throw Error(formatErrorMessage(39, "Configuration object can't be an Array or null!"));
const validKeys = ["name", "app", "activeWhen", "customProps"];
const invalidKeys = Object.keys(config).reduce((invalidKeys, prop) => validKeys.indexOf(prop) >= 0 ? invalidKeys : invalidKeys.concat(prop), []);
if (invalidKeys.length !== 0) throw Error(formatErrorMessage(38, `The configuration object accepts only: ${validKeys.join(", ")}. Invalid keys: ${invalidKeys.join(", ")}.`, validKeys.join(", "), invalidKeys.join(", ")));
if (typeof config.name !== "string" || config.name.length === 0) throw Error(formatErrorMessage(20, "The config.name on registerApplication must be a non-empty string"));
if (typeof config.app !== "object" && typeof config.app !== "function") throw Error(formatErrorMessage(20, "The config.app on registerApplication must be an application or a loading function"));
const allowsStringAndFunction = activeWhen => typeof activeWhen === "string" || typeof activeWhen === "function";
if (!allowsStringAndFunction(config.activeWhen) && !(Array.isArray(config.activeWhen) && config.activeWhen.every(allowsStringAndFunction))) throw Error(formatErrorMessage(24, "The config.activeWhen on registerApplication must be a string, function or an array with both"));
if (!validCustomProps(config.customProps)) throw Error(formatErrorMessage(22, "The optional config.customProps must be an object"));
}
function validCustomProps(customProps) {
return !customProps || typeof customProps === "function" || typeof customProps === "object" && customProps !== null && !Array.isArray(customProps);
}
function sanitizeArguments(appNameOrConfig, appOrLoadApp, activeWhen, customProps) {
const usingObjectAPI = typeof appNameOrConfig === "object";
const registration = {
name: null,
loadApp: null,
activeWhen: null,
customProps: null
};
if (usingObjectAPI) {
validateRegisterWithConfig(appNameOrConfig);
registration.name = appNameOrConfig.name;
registration.loadApp = appNameOrConfig.app;
registration.activeWhen = appNameOrConfig.activeWhen;
registration.customProps = appNameOrConfig.customProps;
} else {
validateRegisterWithArguments(appNameOrConfig, appOrLoadApp, activeWhen, customProps);
registration.name = appNameOrConfig;
registration.loadApp = appOrLoadApp;
registration.activeWhen = activeWhen;
registration.customProps = customProps;
}
registration.loadApp = sanitizeLoadApp(registration.loadApp);
registration.customProps = sanitizeCustomProps(registration.customProps);
registration.activeWhen = sanitizeActiveWhen(registration.activeWhen);
return registration;
}
function sanitizeLoadApp(loadApp) {
if (typeof loadApp !== "function") {
return () => Promise.resolve(loadApp);
}
return loadApp;
}
function sanitizeCustomProps(customProps) {
return customProps ? customProps : {};
}
function sanitizeActiveWhen(activeWhen) {
let activeWhenArray = Array.isArray(activeWhen) ? activeWhen : [activeWhen];
activeWhenArray = activeWhenArray.map(activeWhenOrPath => typeof activeWhenOrPath === "function" ? activeWhenOrPath : pathToActiveWhen(activeWhenOrPath));
return location => activeWhenArray.some(activeWhen => activeWhen(location));
}
function pathToActiveWhen(path, exactMatch) {
const regex = toDynamicPathValidatorRegex(path, exactMatch);
return location => {
// compatible with IE10
let origin = location.origin;
if (!origin) {
origin = `${location.protocol}//${location.host}`;
}
const route = location.href.replace(origin, "").replace(location.search, "").split("?")[0];
return regex.test(route);
};
}
function toDynamicPathValidatorRegex(path, exactMatch) {
let lastIndex = 0,
inDynamic = false,
regexStr = "^";
if (path[0] !== "/") {
path = "/" + path;
}
for (let charIndex = 0; charIndex < path.length; charIndex++) {
const char = path[charIndex];
const startOfDynamic = !inDynamic && char === ":";
const endOfDynamic = inDynamic && char === "/";
if (startOfDynamic || endOfDynamic) {
appendToRegex(charIndex);
}
}
appendToRegex(path.length);
return new RegExp(regexStr, "i");
function appendToRegex(index) {
const anyCharMaybeTrailingSlashRegex = "[^/]+/?";
const commonStringSubPath = escapeStrRegex(path.slice(lastIndex, index));
regexStr += inDynamic ? anyCharMaybeTrailingSlashRegex : commonStringSubPath;
if (index === path.length) {
if (inDynamic) {
if (exactMatch) {
// Ensure exact match paths that end in a dynamic portion don't match
// urls with characters after a slash after the dynamic portion.
regexStr += "$";
}
} else {
// For exact matches, expect no more characters. Otherwise, allow
// any characters.
const suffix = exactMatch ? "" : ".*";
regexStr = // use charAt instead as we could not use es6 method endsWith
regexStr.charAt(regexStr.length - 1) === "/" ? `${regexStr}${suffix}$` : `${regexStr}(/${suffix})?(#.*)?$`;
}
}
inDynamic = !inDynamic;
lastIndex = index;
}
function escapeStrRegex(str) {
// borrowed from https://github.com/sindresorhus/escape-string-regexp/blob/master/index.js
return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
}
}
let appChangeUnderway = false,
peopleWaitingOnAppChange = [],
currentUrl = isInBrowser && window.location.href;
function triggerAppChange() {
// Call reroute with no arguments, intentionally
return reroute();
}
function reroute(pendingPromises = [], eventArguments) {
if (appChangeUnderway) {
return new Promise((resolve, reject) => {
peopleWaitingOnAppChange.push({
resolve,
reject,
eventArguments
});
});
}
const {
appsToUnload,
appsToUnmount,
appsToLoad,
appsToMount
} = getAppChanges();
let appsThatChanged,
navigationIsCanceled = false,
oldUrl = currentUrl,
newUrl = currentUrl = window.location.href;
if (isStarted()) {
appChangeUnderway = true;
appsThatChanged = appsToUnload.concat(appsToLoad, appsToUnmount, appsToMount);
return performAppChanges();
} else {
appsThatChanged = appsToLoad;
return loadApps();
}
function cancelNavigation() {
navigationIsCanceled = true;
}
function loadApps() {
return Promise.resolve().then(() => {
const loadPromises = appsToLoad.map(toLoadPromise);
return Promise.all(loadPromises).then(callAllEventListeners) // there are no mounted apps, before start() is called, so we always return []
.then(() => []).catch(err => {
callAllEventListeners();
throw err;
});
});
}
function performAppChanges() {
return Promise.resolve().then(() => {
// https://github.com/single-spa/single-spa/issues/545
window.dispatchEvent(new customEvent(appsThatChanged.length === 0 ? "single-spa:before-no-app-change" : "single-spa:before-app-change", getCustomEventDetail(true)));
window.dispatchEvent(new customEvent("single-spa:before-routing-event", getCustomEventDetail(true, {
cancelNavigation
})));
if (navigationIsCanceled) {
window.dispatchEvent(new customEvent("single-spa:before-mount-routing-event", getCustomEventDetail(true)));
finishUpAndReturn();
navigateToUrl(oldUrl);
return;
}
const unloadPromises = appsToUnload.map(toUnloadPromise);
const unmountUnloadPromises = appsToUnmount.map(toUnmountPromise).map(unmountPromise => unmountPromise.then(toUnloadPromise));
const allUnmountPromises = unmountUnloadPromises.concat(unloadPromises);
const unmountAllPromise = Promise.all(allUnmountPromises);
unmountAllPromise.then(() => {
window.dispatchEvent(new customEvent("single-spa:before-mount-routing-event", getCustomEventDetail(true)));
});
/* We load and bootstrap apps while other apps are unmounting, but we
* wait to mount the app until all apps are finishing unmounting
*/
const loadThenMountPromises = appsToLoad.map(app => {
return toLoadPromise(app).then(app => tryToBootstrapAndMount(app, unmountAllPromise));
});
/* These are the apps that are already bootstrapped and just need
* to be mounted. They each wait for all unmounting apps to finish up
* before they mount.
*/
const mountPromises = appsToMount.filter(appToMount => appsToLoad.indexOf(appToMount) < 0).map(appToMount => {
return tryToBootstrapAndMount(appToMount, unmountAllPromise);
});
return unmountAllPromise.catch(err => {
callAllEventListeners();
throw err;
}).then(() => {
/* Now that the apps that needed to be unmounted are unmounted, their DOM navigation
* events (like hashchange or popstate) should have been cleaned up. So it's safe
* to let the remaining captured event listeners to handle about the DOM event.
*/
callAllEventListeners();
return Promise.all(loadThenMountPromises.concat(mountPromises)).catch(err => {
pendingPromises.forEach(promise => promise.reject(err));
throw err;
}).then(finishUpAndReturn);
});
});
}
function finishUpAndReturn() {
const returnValue = getMountedApps();
pendingPromises.forEach(promise => promise.resolve(returnValue));
try {
const appChangeEventName = appsThatChanged.length === 0 ? "single-spa:no-app-change" : "single-spa:app-change";
window.dispatchEvent(new customEvent(appChangeEventName, getCustomEventDetail()));
window.dispatchEvent(new customEvent("single-spa:routing-event", getCustomEventDetail()));
} catch (err) {
/* We use a setTimeout because if someone else's event handler throws an error, single-spa
* needs to carry on. If a listener to the event throws an error, it's their own fault, not
* single-spa's.
*/
setTimeout(() => {
throw err;
});
}
/* Setting this allows for subsequent calls to reroute() to actually perform
* a reroute instead of just getting queued behind the current reroute call.
* We want to do this after the mounting/unmounting is done but before we
* resolve the promise for the `reroute` function.
*/
appChangeUnderway = false;
if (peopleWaitingOnAppChange.length > 0) {
/* While we were rerouting, someone else triggered another reroute that got queued.
* So we need reroute again.
*/
const nextPendingPromises = peopleWaitingOnAppChange;
peopleWaitingOnAppChange = [];
reroute(nextPendingPromises);
}
return returnValue;
}
/* We need to call all event listeners that have been delayed because they were
* waiting on single-spa. This includes haschange and popstate events for both
* the current run of performAppChanges(), but also all of the queued event listeners.
* We want to call the listeners in the same order as if they had not been delayed by
* single-spa, which means queued ones first and then the most recent one.
*/
function callAllEventListeners() {
pendingPromises.forEach(pendingPromise => {
callCapturedEventListeners(pendingPromise.eventArguments);
});
callCapturedEventListeners(eventArguments);
}
function getCustomEventDetail(isBeforeChanges = false, extraProperties) {
const newAppStatuses = {};
const appsByNewStatus = {
// for apps that were mounted
[MOUNTED]: [],
// for apps that were unmounted
[NOT_MOUNTED]: [],
// apps that were forcibly unloaded
[NOT_LOADED]: [],
// apps that attempted to do something but are broken now
[SKIP_BECAUSE_BROKEN]: []
};
if (isBeforeChanges) {
appsToLoad.concat(appsToMount).forEach((app, index) => {
addApp(app, MOUNTED);
});
appsToUnload.forEach(app => {
addApp(app, NOT_LOADED);
});
appsToUnmount.forEach(app => {
addApp(app, NOT_MOUNTED);
});
} else {
appsThatChanged.forEach(app => {
addApp(app);
});
}
const result = {
detail: {
newAppStatuses,
appsByNewStatus,
totalAppChanges: appsThatChanged.length,
originalEvent: eventArguments === null || eventArguments === void 0 ? void 0 : eventArguments[0],
oldUrl,
newUrl,
navigationIsCanceled
}
};
if (extraProperties) {
assign(result.detail, extraProperties);
}
return result;
function addApp(app, status) {
const appName = toName(app);
status = status || getAppStatus(appName);
newAppStatuses[appName] = status;
const statusArr = appsByNewStatus[status] = appsByNewStatus[status] || [];
statusArr.push(appName);
}
}
}
/**
* Let's imagine that some kind of delay occurred during application loading.
* The user without waiting for the application to load switched to another route,
* this means that we shouldn't bootstrap and mount that application, thus we check
* twice if that application should be active before bootstrapping and mounting.
* https://github.com/single-spa/single-spa/issues/524
*/
function tryToBootstrapAndMount(app, unmountAllPromise) {
if (shouldBeActive(app)) {
return toBootstrapPromise(app).then(app => unmountAllPromise.then(() => shouldBeActive(app) ? toMountPromise(app) : app));
} else {
return unmountAllPromise.then(() => app);
}
}
let started = false;
function start(opts) {
started = true;
if (opts && opts.urlRerouteOnly) {
setUrlRerouteOnly(opts.urlRerouteOnly);
}
if (isInBrowser) {
reroute();
}
}
function isStarted() {
return started;
}
if (isInBrowser) {
setTimeout(() => {
if (!started) {
console.warn(formatErrorMessage(1, `singleSpa.start() has not been called, 5000ms after single-spa was loaded. Before start() is called, apps can be declared and loaded, but not bootstrapped or mounted.`));
}
}, 5000);
}
var devtools = {
getRawAppData,
reroute,
NOT_LOADED,
toLoadPromise,
toBootstrapPromise,
unregisterApplication
};
if (isInBrowser && window.__SINGLE_SPA_DEVTOOLS__) {
window.__SINGLE_SPA_DEVTOOLS__.exposedMethods = devtools;
}
export { BOOTSTRAPPING, LOADING_SOURCE_CODE, LOAD_ERROR, MOUNTED, MOUNTING, NOT_BOOTSTRAPPED, NOT_LOADED, NOT_MOUNTED, SKIP_BECAUSE_BROKEN, UNMOUNTING, UPDATING, addErrorHandler, checkActivityFunctions, ensureJQuerySupport, getAppNames, getAppStatus, getMountedApps, mountRootParcel, navigateToUrl, pathToActiveWhen, registerApplication, removeErrorHandler, setBootstrapMaxTime, setMountMaxTime, setUnloadMaxTime, setUnmountMaxTime, start, triggerAppChange, unloadApplication, unregisterApplication };
//# sourceMappingURL=single-spa.dev.js.map