UNPKG

49.9 kBJavaScriptView Raw
1/* single-spa@5.0.0 - UMD - dev */
2(function (global, factory) {
3 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4 typeof define === 'function' && define.amd ? define(['exports'], factory) :
5 (global = global || self, factory(global.singleSpa = {}));
6}(this, (function (exports) { 'use strict';
7
8 var singleSpa = /*#__PURE__*/Object.freeze({
9 __proto__: null,
10 get start () { return start; },
11 get ensureJQuerySupport () { return ensureJQuerySupport; },
12 get setBootstrapMaxTime () { return setBootstrapMaxTime; },
13 get setMountMaxTime () { return setMountMaxTime; },
14 get setUnmountMaxTime () { return setUnmountMaxTime; },
15 get setUnloadMaxTime () { return setUnloadMaxTime; },
16 get registerApplication () { return registerApplication; },
17 get getMountedApps () { return getMountedApps; },
18 get getAppStatus () { return getAppStatus; },
19 get unloadApplication () { return unloadApplication; },
20 get checkActivityFunctions () { return checkActivityFunctions; },
21 get getAppNames () { return getAppNames; },
22 get navigateToUrl () { return navigateToUrl; },
23 get triggerAppChange () { return triggerAppChange; },
24 get addErrorHandler () { return addErrorHandler; },
25 get removeErrorHandler () { return removeErrorHandler; },
26 get mountRootParcel () { return mountRootParcel; },
27 get NOT_LOADED () { return NOT_LOADED; },
28 get LOADING_SOURCE_CODE () { return LOADING_SOURCE_CODE; },
29 get NOT_BOOTSTRAPPED () { return NOT_BOOTSTRAPPED; },
30 get BOOTSTRAPPING () { return BOOTSTRAPPING; },
31 get NOT_MOUNTED () { return NOT_MOUNTED; },
32 get MOUNTING () { return MOUNTING; },
33 get UPDATING () { return UPDATING; },
34 get LOAD_ERROR () { return LOAD_ERROR; },
35 get MOUNTED () { return MOUNTED; },
36 get UNMOUNTING () { return UNMOUNTING; },
37 get SKIP_BECAUSE_BROKEN () { return SKIP_BECAUSE_BROKEN; }
38 });
39
40 var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
41
42 var NativeCustomEvent = commonjsGlobal.CustomEvent;
43
44 function useNative () {
45 try {
46 var p = new NativeCustomEvent('cat', { detail: { foo: 'bar' } });
47 return 'cat' === p.type && 'bar' === p.detail.foo;
48 } catch (e) {
49 }
50 return false;
51 }
52
53 /**
54 * Cross-browser `CustomEvent` constructor.
55 *
56 * https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent.CustomEvent
57 *
58 * @public
59 */
60
61 var customEvent = useNative() ? NativeCustomEvent :
62
63 // IE >= 9
64 'undefined' !== typeof document && 'function' === typeof document.createEvent ? function CustomEvent (type, params) {
65 var e = document.createEvent('CustomEvent');
66 if (params) {
67 e.initCustomEvent(type, params.bubbles, params.cancelable, params.detail);
68 } else {
69 e.initCustomEvent(type, false, false, void 0);
70 }
71 return e;
72 } :
73
74 // IE <= 8
75 function CustomEvent (type, params) {
76 var e = document.createEventObject();
77 e.type = type;
78 if (params) {
79 e.bubbles = Boolean(params.bubbles);
80 e.cancelable = Boolean(params.cancelable);
81 e.detail = params.detail;
82 } else {
83 e.bubbles = false;
84 e.cancelable = false;
85 e.detail = void 0;
86 }
87 return e;
88 };
89
90 function _typeof(obj) {
91 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
92 _typeof = function (obj) {
93 return typeof obj;
94 };
95 } else {
96 _typeof = function (obj) {
97 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
98 };
99 }
100
101 return _typeof(obj);
102 }
103
104 var errorHandlers = [];
105 function handleAppError(err, app) {
106 var transformedErr = transformErr(err, app);
107
108 if (errorHandlers.length) {
109 errorHandlers.forEach(function (handler) {
110 return handler(transformedErr);
111 });
112 } else {
113 setTimeout(function () {
114 throw transformedErr;
115 });
116 }
117 }
118 function addErrorHandler(handler) {
119 if (typeof handler !== "function") {
120 throw Error(formatErrorMessage(28, "a single-spa error handler must be a function"));
121 }
122
123 errorHandlers.push(handler);
124 }
125 function removeErrorHandler(handler) {
126 if (typeof handler !== "function") {
127 throw Error(formatErrorMessage(29, "a single-spa error handler must be a function"));
128 }
129
130 var removedSomething = false;
131 errorHandlers = errorHandlers.filter(function (h) {
132 var isHandler = h === handler;
133 removedSomething = removedSomething || isHandler;
134 return !isHandler;
135 });
136 return removedSomething;
137 }
138 function formatErrorMessage(code, msg) {
139 for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
140 args[_key - 2] = arguments[_key];
141 }
142
143 return "single-spa minified message #".concat(code, ": ").concat(msg ? msg + " " : "", "See https://single-spa.js.org/error/?code=").concat(code).concat(args.length ? "&arg=".concat(args.join("&arg=")) : "");
144 }
145 function transformErr(ogErr, appOrParcel) {
146 var errPrefix = "".concat(objectType(appOrParcel), " '").concat(toName(appOrParcel), "' died in status ").concat(appOrParcel.status, ": ");
147 var result;
148
149 if (ogErr instanceof Error) {
150 try {
151 ogErr.message = errPrefix + ogErr.message;
152 } catch (err) {
153 /* Some errors have read-only message properties, in which case there is nothing
154 * that we can do.
155 */
156 }
157
158 result = ogErr;
159 } else {
160 console.warn(formatErrorMessage(30, "While ".concat(appOrParcel.status, ", '").concat(toName(appOrParcel), "' rejected its lifecycle function promise with a non-Error. This will cause stack traces to not be accurate."), appOrParcel.status, toName(appOrParcel)));
161
162 try {
163 result = Error(errPrefix + JSON.stringify(ogErr));
164 } catch (err) {
165 // If it's not an Error and you can't stringify it, then what else can you even do to it?
166 result = ogErr;
167 }
168 }
169
170 result.appOrParcelName = toName(appOrParcel);
171 return result;
172 }
173
174 var NOT_LOADED = "NOT_LOADED";
175 var LOADING_SOURCE_CODE = "LOADING_SOURCE_CODE";
176 var NOT_BOOTSTRAPPED = "NOT_BOOTSTRAPPED";
177 var BOOTSTRAPPING = "BOOTSTRAPPING";
178 var NOT_MOUNTED = "NOT_MOUNTED";
179 var MOUNTING = "MOUNTING";
180 var MOUNTED = "MOUNTED";
181 var UPDATING = "UPDATING";
182 var UNMOUNTING = "UNMOUNTING";
183 var UNLOADING = "UNLOADING";
184 var LOAD_ERROR = "LOAD_ERROR";
185 var SKIP_BECAUSE_BROKEN = "SKIP_BECAUSE_BROKEN";
186 function isActive(app) {
187 return app.status === MOUNTED;
188 }
189 function isntActive(app) {
190 return !isActive(app);
191 }
192 function isLoaded(app) {
193 return app.status !== NOT_LOADED && app.status !== LOADING_SOURCE_CODE && app.status !== LOAD_ERROR;
194 }
195 function isntLoaded(app) {
196 return !isLoaded(app);
197 }
198 function shouldBeActive(app) {
199 try {
200 return app.activeWhen(window.location);
201 } catch (err) {
202 handleAppError(err, app);
203 app.status = SKIP_BECAUSE_BROKEN;
204 }
205 }
206 function shouldntBeActive(app) {
207 try {
208 return !app.activeWhen(window.location);
209 } catch (err) {
210 handleAppError(err, app);
211 app.status = SKIP_BECAUSE_BROKEN;
212 }
213 }
214 function notSkipped(item) {
215 return item !== SKIP_BECAUSE_BROKEN && (!item || item.status !== SKIP_BECAUSE_BROKEN);
216 }
217 function withoutLoadErrors(app) {
218 return app.status === LOAD_ERROR ? new Date().getTime() - app.loadErrorTime >= 200 : true;
219 }
220 function toName(app) {
221 return app.name;
222 }
223 function isParcel(appOrParcel) {
224 return Boolean(appOrParcel.unmountThisParcel);
225 }
226 function objectType(appOrParcel) {
227 return isParcel(appOrParcel) ? "parcel" : "application";
228 }
229
230 // Object.assign() is not available in IE11. And the babel compiled output for object spread
231 // syntax checks a bunch of Symbol stuff and is almost a kb. So this function is the smaller replacement.
232 function assign() {
233 for (var i = arguments.length - 1; i > 0; i--) {
234 for (var key in arguments[i]) {
235 if (key === "__proto__") {
236 continue;
237 }
238
239 arguments[i - 1][key] = arguments[i][key];
240 }
241 }
242
243 return arguments[0];
244 }
245
246 /* the array.prototype.find polyfill on npmjs.com is ~20kb (not worth it)
247 * and lodash is ~200kb (not worth it)
248 */
249 function find(arr, func) {
250 for (var i = 0; i < arr.length; i++) {
251 if (func(arr[i])) {
252 return arr[i];
253 }
254 }
255
256 return null;
257 }
258
259 function validLifecycleFn(fn) {
260 return fn && (typeof fn === "function" || isArrayOfFns(fn));
261
262 function isArrayOfFns(arr) {
263 return Array.isArray(arr) && !find(arr, function (item) {
264 return typeof item !== "function";
265 });
266 }
267 }
268 function flattenFnArray(appOrParcel, lifecycle) {
269 var fns = appOrParcel[lifecycle] || [];
270 fns = Array.isArray(fns) ? fns : [fns];
271
272 if (fns.length === 0) {
273 fns = [function () {
274 return Promise.resolve();
275 }];
276 }
277
278 var type = objectType(appOrParcel);
279 var name = toName(appOrParcel);
280 return function (props) {
281 return fns.reduce(function (resultPromise, fn, index) {
282 return resultPromise.then(function () {
283 var thisPromise = fn(props);
284 return smellsLikeAPromise(thisPromise) ? thisPromise : Promise.reject(formatErrorMessage(15, "Within ".concat(type, " ").concat(name, ", the lifecycle function ").concat(lifecycle, " at array index ").concat(index, " did not return a promise"), type, name, lifecycle, index));
285 });
286 }, Promise.resolve());
287 };
288 }
289 function smellsLikeAPromise(promise) {
290 return promise && typeof promise.then === "function" && typeof promise.catch === "function";
291 }
292
293 function toBootstrapPromise(appOrParcel, hardFail) {
294 return Promise.resolve().then(function () {
295 if (appOrParcel.status !== NOT_BOOTSTRAPPED) {
296 return appOrParcel;
297 }
298
299 appOrParcel.status = BOOTSTRAPPING;
300 return reasonableTime(appOrParcel, "bootstrap").then(function () {
301 appOrParcel.status = NOT_MOUNTED;
302 return appOrParcel;
303 }).catch(function (err) {
304 appOrParcel.status = SKIP_BECAUSE_BROKEN;
305
306 if (hardFail) {
307 throw transformErr(err, appOrParcel);
308 } else {
309 handleAppError(err, appOrParcel);
310 return appOrParcel;
311 }
312 });
313 });
314 }
315
316 function toUnmountPromise(appOrParcel, hardFail) {
317 return Promise.resolve().then(function () {
318 if (appOrParcel.status !== MOUNTED) {
319 return appOrParcel;
320 }
321
322 appOrParcel.status = UNMOUNTING;
323 var unmountChildrenParcels = Object.keys(appOrParcel.parcels).map(function (parcelId) {
324 return appOrParcel.parcels[parcelId].unmountThisParcel();
325 });
326 return Promise.all(unmountChildrenParcels).then(unmountAppOrParcel, function (parcelError) {
327 // There is a parcel unmount error
328 return unmountAppOrParcel().then(function () {
329 // Unmounting the app/parcel succeeded, but unmounting its children parcels did not
330 var parentError = Error(parcelError.message);
331
332 if (hardFail) {
333 var transformedErr = transformErr(parentError, appOrParcel);
334 appOrParcel.status = SKIP_BECAUSE_BROKEN;
335 throw transformedErr;
336 } else {
337 handleAppError(parentError, appOrParcel);
338 appOrParcel.status = SKIP_BECAUSE_BROKEN;
339 }
340 });
341 }).then(function () {
342 return appOrParcel;
343 });
344
345 function unmountAppOrParcel() {
346 // We always try to unmount the appOrParcel, even if the children parcels failed to unmount.
347 return reasonableTime(appOrParcel, "unmount").then(function () {
348 // The appOrParcel needs to stay in a broken status if its children parcels fail to unmount
349 {
350 appOrParcel.status = NOT_MOUNTED;
351 }
352 }).catch(function (err) {
353 if (hardFail) {
354 var transformedErr = transformErr(err, appOrParcel);
355 appOrParcel.status = SKIP_BECAUSE_BROKEN;
356 throw transformedErr;
357 } else {
358 handleAppError(err, appOrParcel);
359 appOrParcel.status = SKIP_BECAUSE_BROKEN;
360 }
361 });
362 }
363 });
364 }
365
366 var beforeFirstMountFired = false;
367 var firstMountFired = false;
368 function toMountPromise(appOrParcel, hardFail) {
369 return Promise.resolve().then(function () {
370 if (appOrParcel.status !== NOT_MOUNTED) {
371 return appOrParcel;
372 }
373
374 if (!beforeFirstMountFired) {
375 window.dispatchEvent(new customEvent("single-spa:before-first-mount"));
376 beforeFirstMountFired = true;
377 }
378
379 return reasonableTime(appOrParcel, "mount").then(function () {
380 appOrParcel.status = MOUNTED;
381
382 if (!firstMountFired) {
383 window.dispatchEvent(new customEvent("single-spa:first-mount"));
384 firstMountFired = true;
385 }
386
387 return appOrParcel;
388 }).catch(function (err) {
389 // If we fail to mount the appOrParcel, we should attempt to unmount it before putting in SKIP_BECAUSE_BROKEN
390 // We temporarily put the appOrParcel into MOUNTED status so that toUnmountPromise actually attempts to unmount it
391 // instead of just doing a no-op.
392 appOrParcel.status = MOUNTED;
393 return toUnmountPromise(appOrParcel).then(setSkipBecauseBroken, setSkipBecauseBroken);
394
395 function setSkipBecauseBroken() {
396 if (!hardFail) {
397 handleAppError(err, appOrParcel);
398 appOrParcel.status = SKIP_BECAUSE_BROKEN;
399 return appOrParcel;
400 } else {
401 var transformedErr = transformErr(err, appOrParcel);
402 appOrParcel.status = SKIP_BECAUSE_BROKEN;
403 throw transformedErr;
404 }
405 }
406 });
407 });
408 }
409
410 function toUpdatePromise(parcel) {
411 return Promise.resolve().then(function () {
412 if (parcel.status !== MOUNTED) {
413 throw Error(formatErrorMessage(32, "Cannot update parcel '".concat(toName(parcel), "' because it is not mounted"), toName(parcel)));
414 }
415
416 parcel.status = UPDATING;
417 return reasonableTime(parcel, "update").then(function () {
418 parcel.status = MOUNTED;
419 return parcel;
420 }).catch(function (err) {
421 var transformedErr = transformErr(err, parcel);
422 parcel.status = SKIP_BECAUSE_BROKEN;
423 throw transformedErr;
424 });
425 });
426 }
427
428 var parcelCount = 0;
429 var rootParcels = {
430 parcels: {}
431 }; // This is a public api, exported to users of single-spa
432
433 function mountRootParcel() {
434 return mountParcel.apply(rootParcels, arguments);
435 }
436 function mountParcel(config, customProps) {
437 var owningAppOrParcel = this; // Validate inputs
438
439 if (!config || _typeof(config) !== "object" && typeof config !== "function") {
440 throw Error(formatErrorMessage(2, "Cannot mount parcel without a config object or config loading function"));
441 }
442
443 if (config.name && typeof config.name !== "string") {
444 throw Error(formatErrorMessage(3, "Parcel name must be a string, if provided. Was given ".concat(_typeof(config.name)), _typeof(config.name)));
445 }
446
447 if (_typeof(customProps) !== "object") {
448 throw Error(formatErrorMessage(4, "Parcel ".concat(name, " has invalid customProps -- must be an object but was given ").concat(_typeof(customProps)), name, _typeof(customProps)));
449 }
450
451 if (!customProps.domElement) {
452 throw Error(formatErrorMessage(5, "Parcel ".concat(name, " cannot be mounted without a domElement provided as a prop"), name));
453 }
454
455 var id = parcelCount++;
456 var passedConfigLoadingFunction = typeof config === "function";
457 var configLoadingFunction = passedConfigLoadingFunction ? config : function () {
458 return Promise.resolve(config);
459 }; // Internal representation
460
461 var parcel = {
462 id: id,
463 parcels: {},
464 status: passedConfigLoadingFunction ? LOADING_SOURCE_CODE : NOT_BOOTSTRAPPED,
465 customProps: customProps,
466 parentName: toName(owningAppOrParcel),
467 unmountThisParcel: function unmountThisParcel() {
468 if (parcel.status !== MOUNTED) {
469 throw Error(formatErrorMessage(6, "Cannot unmount parcel '".concat(name, "' -- it is in a ").concat(parcel.status, " status"), name, parcel.status));
470 }
471
472 return toUnmountPromise(parcel, true).then(function (value) {
473 if (parcel.parentName) {
474 delete owningAppOrParcel.parcels[parcel.id];
475 }
476
477 return value;
478 }).then(function (value) {
479 resolveUnmount(value);
480 return value;
481 }).catch(function (err) {
482 parcel.status = SKIP_BECAUSE_BROKEN;
483 rejectUnmount(err);
484 throw err;
485 });
486 }
487 }; // We return an external representation
488
489 var externalRepresentation; // Add to owning app or parcel
490
491 owningAppOrParcel.parcels[id] = parcel;
492 var loadPromise = configLoadingFunction();
493
494 if (!loadPromise || typeof loadPromise.then !== "function") {
495 throw Error(formatErrorMessage(7, "When mounting a parcel, the config loading function must return a promise that resolves with the parcel config"));
496 }
497
498 loadPromise = loadPromise.then(function (config) {
499 if (!config) {
500 throw Error(formatErrorMessage(8, "When mounting a parcel, the config loading function returned a promise that did not resolve with a parcel config"));
501 }
502
503 var name = config.name || "parcel-".concat(id);
504
505 if (!validLifecycleFn(config.bootstrap)) {
506 throw Error(formatErrorMessage(9, "Parcel ".concat(name, " must have a valid bootstrap function"), name));
507 }
508
509 if (!validLifecycleFn(config.mount)) {
510 throw Error(formatErrorMessage(10, "Parcel ".concat(name, " must have a valid mount function"), name));
511 }
512
513 if (!validLifecycleFn(config.unmount)) {
514 throw Error(formatErrorMessage(11, "Parcel ".concat(name, " must have a valid unmount function"), name));
515 }
516
517 if (config.update && !validLifecycleFn(config.update)) {
518 throw Error(formatErrorMessage(12, "Parcel ".concat(name, " provided an invalid update function"), name));
519 }
520
521 var bootstrap = flattenFnArray(config, "bootstrap");
522 var mount = flattenFnArray(config, "mount");
523 var unmount = flattenFnArray(config, "unmount");
524 parcel.status = NOT_BOOTSTRAPPED;
525 parcel.name = name;
526 parcel.bootstrap = bootstrap;
527 parcel.mount = mount;
528 parcel.unmount = unmount;
529 parcel.timeouts = ensureValidAppTimeouts(config.timeouts);
530
531 if (config.update) {
532 parcel.update = flattenFnArray(config, "update");
533
534 externalRepresentation.update = function (customProps) {
535 parcel.customProps = customProps;
536 return promiseWithoutReturnValue(toUpdatePromise(parcel));
537 };
538 }
539 }); // Start bootstrapping and mounting
540 // The .then() causes the work to be put on the event loop instead of happening immediately
541
542 var bootstrapPromise = loadPromise.then(function () {
543 return toBootstrapPromise(parcel, true);
544 });
545 var mountPromise = bootstrapPromise.then(function () {
546 return toMountPromise(parcel, true);
547 });
548 var resolveUnmount, rejectUnmount;
549 var unmountPromise = new Promise(function (resolve, reject) {
550 resolveUnmount = resolve;
551 rejectUnmount = reject;
552 });
553 externalRepresentation = {
554 mount: function mount() {
555 return promiseWithoutReturnValue(Promise.resolve().then(function () {
556 if (parcel.status !== NOT_MOUNTED) {
557 throw Error(formatErrorMessage(13, "Cannot mount parcel '".concat(name, "' -- it is in a ").concat(parcel.status, " status"), name, parcel.status));
558 } // Add to owning app or parcel
559
560
561 owningAppOrParcel.parcels[id] = parcel;
562 return toMountPromise(parcel);
563 }));
564 },
565 unmount: function unmount() {
566 return promiseWithoutReturnValue(parcel.unmountThisParcel());
567 },
568 getStatus: function getStatus() {
569 return parcel.status;
570 },
571 loadPromise: promiseWithoutReturnValue(loadPromise),
572 bootstrapPromise: promiseWithoutReturnValue(bootstrapPromise),
573 mountPromise: promiseWithoutReturnValue(mountPromise),
574 unmountPromise: promiseWithoutReturnValue(unmountPromise)
575 };
576 return externalRepresentation;
577 }
578
579 function promiseWithoutReturnValue(promise) {
580 return promise.then(function () {
581 return null;
582 });
583 }
584
585 function getProps(appOrParcel) {
586 var result = assign({}, appOrParcel.customProps, {
587 name: toName(appOrParcel),
588 mountParcel: mountParcel.bind(appOrParcel),
589 singleSpa: singleSpa
590 });
591
592 if (isParcel(appOrParcel)) {
593 result.unmountSelf = appOrParcel.unmountThisParcel;
594 }
595
596 return result;
597 }
598
599 var defaultWarningMillis = 1000;
600 var globalTimeoutConfig = {
601 bootstrap: {
602 millis: 4000,
603 dieOnTimeout: false,
604 warningMillis: defaultWarningMillis
605 },
606 mount: {
607 millis: 3000,
608 dieOnTimeout: false,
609 warningMillis: defaultWarningMillis
610 },
611 unmount: {
612 millis: 3000,
613 dieOnTimeout: false,
614 warningMillis: defaultWarningMillis
615 },
616 unload: {
617 millis: 3000,
618 dieOnTimeout: false,
619 warningMillis: defaultWarningMillis
620 },
621 update: {
622 millis: 3000,
623 dieOnTimeout: false,
624 warningMillis: defaultWarningMillis
625 }
626 };
627 function setBootstrapMaxTime(time, dieOnTimeout, warningMillis) {
628 if (typeof time !== "number" || time <= 0) {
629 throw Error(formatErrorMessage(16, "bootstrap max time must be a positive integer number of milliseconds"));
630 }
631
632 globalTimeoutConfig.bootstrap = {
633 millis: time,
634 dieOnTimeout: dieOnTimeout,
635 warningMillis: warningMillis || defaultWarningMillis
636 };
637 }
638 function setMountMaxTime(time, dieOnTimeout, warningMillis) {
639 if (typeof time !== "number" || time <= 0) {
640 throw Error(formatErrorMessage(17, "mount max time must be a positive integer number of milliseconds"));
641 }
642
643 globalTimeoutConfig.mount = {
644 millis: time,
645 dieOnTimeout: dieOnTimeout,
646 warningMillis: warningMillis || defaultWarningMillis
647 };
648 }
649 function setUnmountMaxTime(time, dieOnTimeout, warningMillis) {
650 if (typeof time !== "number" || time <= 0) {
651 throw Error(formatErrorMessage(18, "unmount max time must be a positive integer number of milliseconds"));
652 }
653
654 globalTimeoutConfig.unmount = {
655 millis: time,
656 dieOnTimeout: dieOnTimeout,
657 warningMillis: warningMillis || defaultWarningMillis
658 };
659 }
660 function setUnloadMaxTime(time, dieOnTimeout, warningMillis) {
661 if (typeof time !== "number" || time <= 0) {
662 throw Error(formatErrorMessage(19, "unload max time must be a positive integer number of milliseconds"));
663 }
664
665 globalTimeoutConfig.unload = {
666 millis: time,
667 dieOnTimeout: dieOnTimeout,
668 warningMillis: warningMillis || defaultWarningMillis
669 };
670 }
671 function reasonableTime(appOrParcel, lifecycle) {
672 var timeoutConfig = appOrParcel.timeouts[lifecycle];
673 var warningPeriod = timeoutConfig.warningMillis;
674 var type = objectType(appOrParcel);
675 return new Promise(function (resolve, reject) {
676 var finished = false;
677 var errored = false;
678 appOrParcel[lifecycle](getProps(appOrParcel)).then(function (val) {
679 finished = true;
680 resolve(val);
681 }).catch(function (val) {
682 finished = true;
683 reject(val);
684 });
685 setTimeout(function () {
686 return maybeTimingOut(1);
687 }, warningPeriod);
688 setTimeout(function () {
689 return maybeTimingOut(true);
690 }, timeoutConfig.millis);
691 var errMsg = formatErrorMessage(31, "Lifecycle function ".concat(lifecycle, " for ").concat(type, " ").concat(toName(appOrParcel), " lifecycle did not resolve or reject for ").concat(timeoutConfig.millis, " ms."), lifecycle, type, toName(appOrParcel), timeoutConfig.millis);
692
693 function maybeTimingOut(shouldError) {
694 if (!finished) {
695 if (shouldError === true) {
696 errored = true;
697
698 if (timeoutConfig.dieOnTimeout) {
699 reject(Error(errMsg));
700 } else {
701 console.error(errMsg); //don't resolve or reject, we're waiting this one out
702 }
703 } else if (!errored) {
704 var numWarnings = shouldError;
705 var numMillis = numWarnings * warningPeriod;
706 console.warn(errMsg);
707
708 if (numMillis + warningPeriod < timeoutConfig.millis) {
709 setTimeout(function () {
710 return maybeTimingOut(numWarnings + 1);
711 }, warningPeriod);
712 }
713 }
714 }
715 }
716 });
717 }
718 function ensureValidAppTimeouts(timeouts) {
719 var result = {};
720
721 for (var key in globalTimeoutConfig) {
722 result[key] = assign({}, globalTimeoutConfig[key], timeouts && timeouts[key] || {});
723 }
724
725 return result;
726 }
727
728 function toLoadPromise(app) {
729 return Promise.resolve().then(function () {
730 if (app.status !== NOT_LOADED && app.status !== LOAD_ERROR) {
731 return app;
732 }
733
734 app.status = LOADING_SOURCE_CODE;
735 var appOpts, isUserErr;
736 return Promise.resolve().then(function () {
737 var loadPromise = app.loadImpl(getProps(app));
738
739 if (!smellsLikeAPromise(loadPromise)) {
740 // The name of the app will be prepended to this error message inside of the handleAppError function
741 isUserErr = true;
742 throw Error(formatErrorMessage(33, "single-spa loading function did not return a promise. Check the second argument to registerApplication('".concat(toName(app), "', loadingFunction, activityFunction)"), toName(app)));
743 }
744
745 return loadPromise.then(function (val) {
746 app.loadErrorTime = null;
747 appOpts = val;
748 var validationErrMessage, validationErrCode;
749
750 if (_typeof(appOpts) !== "object") {
751 validationErrCode = 34;
752
753 {
754 validationErrMessage = "does not export anything";
755 }
756 }
757
758 if (!validLifecycleFn(appOpts.bootstrap)) {
759 validationErrCode = 35;
760
761 {
762 validationErrMessage = "does not export a bootstrap function or array of functions";
763 }
764 }
765
766 if (!validLifecycleFn(appOpts.mount)) {
767 validationErrCode = 36;
768
769 {
770 validationErrMessage = "does not export a bootstrap function or array of functions";
771 }
772 }
773
774 if (!validLifecycleFn(appOpts.unmount)) {
775 validationErrCode = 37;
776
777 {
778 validationErrMessage = "does not export a bootstrap function or array of functions";
779 }
780 }
781
782 var type = objectType(appOpts);
783
784 if (validationErrCode) {
785 var appOptsStr;
786
787 try {
788 appOptsStr = JSON.stringify(appOpts);
789 } catch (_unused) {}
790
791 console.error(formatErrorMessage(validationErrCode, "The loading function for single-spa ".concat(type, " '").concat(toName(app), "' resolved with the following, which does not have bootstrap, mount, and unmount functions"), type, toName(app), appOptsStr), appOpts);
792 handleAppError(validationErrMessage, app);
793 app.status = SKIP_BECAUSE_BROKEN;
794 return app;
795 }
796
797 if (appOpts.devtools && appOpts.devtools.overlays) {
798 app.devtools.overlays = assign({}, app.devtools.overlays, appOpts.devtools.overlays);
799 }
800
801 app.status = NOT_BOOTSTRAPPED;
802 app.bootstrap = flattenFnArray(appOpts, "bootstrap");
803 app.mount = flattenFnArray(appOpts, "mount");
804 app.unmount = flattenFnArray(appOpts, "unmount");
805 app.unload = flattenFnArray(appOpts, "unload");
806 app.timeouts = ensureValidAppTimeouts(appOpts.timeouts);
807 return app;
808 });
809 }).catch(function (err) {
810 handleAppError(err, app);
811
812 if (isUserErr) {
813 app.status = SKIP_BECAUSE_BROKEN;
814 } else {
815 app.status = LOAD_ERROR;
816 app.loadErrorTime = new Date().getTime();
817 }
818
819 return app;
820 });
821 });
822 }
823
824 /* We capture navigation event listeners so that we can make sure
825 * that application navigation listeners are not called until
826 * single-spa has ensured that the correct applications are
827 * unmounted and mounted.
828 */
829
830 var capturedEventListeners = {
831 hashchange: [],
832 popstate: []
833 };
834 var routingEventsListeningTo = ["hashchange", "popstate"];
835 function navigateToUrl(obj) {
836 var url;
837
838 if (typeof obj === "string") {
839 url = obj;
840 } else if (this && this.href) {
841 url = this.href;
842 } else if (obj && obj.currentTarget && obj.currentTarget.href && obj.preventDefault) {
843 url = obj.currentTarget.href;
844 obj.preventDefault();
845 } else {
846 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"));
847 }
848
849 var current = parseUri(window.location.href);
850 var destination = parseUri(url);
851
852 if (url.indexOf("#") === 0) {
853 window.location.hash = destination.hash;
854 } else if (current.host !== destination.host && destination.host) {
855 {
856 window.location.href = url;
857 }
858 } else if (destination.pathname === current.pathname && destination.search === current.pathname) {
859 window.location.hash = destination.hash;
860 } else {
861 // different path, host, or query params
862 window.history.pushState(null, null, url);
863 }
864 }
865 function callCapturedEventListeners(eventArguments) {
866 var _this = this;
867
868 if (eventArguments) {
869 var eventType = eventArguments[0].type;
870
871 if (routingEventsListeningTo.indexOf(eventType) >= 0) {
872 capturedEventListeners[eventType].forEach(function (listener) {
873 try {
874 // The error thrown by application event listener should not break single-spa down.
875 // Just like https://github.com/single-spa/single-spa/blob/85f5042dff960e40936f3a5069d56fc9477fac04/src/navigation/reroute.js#L140-L146 did
876 listener.apply(_this, eventArguments);
877 } catch (e) {
878 setTimeout(function () {
879 throw e;
880 });
881 }
882 });
883 }
884 }
885 }
886
887 function urlReroute() {
888 reroute([], arguments);
889 } // We will trigger an app change for any routing events.
890
891
892 window.addEventListener("hashchange", urlReroute);
893 window.addEventListener("popstate", urlReroute); // Monkeypatch addEventListener so that we can ensure correct timing
894
895 var originalAddEventListener = window.addEventListener;
896 var originalRemoveEventListener = window.removeEventListener;
897
898 window.addEventListener = function (eventName, fn) {
899 if (typeof fn === "function") {
900 if (routingEventsListeningTo.indexOf(eventName) >= 0 && !find(capturedEventListeners[eventName], function (listener) {
901 return listener === fn;
902 })) {
903 capturedEventListeners[eventName].push(fn);
904 return;
905 }
906 }
907
908 return originalAddEventListener.apply(this, arguments);
909 };
910
911 window.removeEventListener = function (eventName, listenerFn) {
912 if (typeof listenerFn === "function") {
913 if (routingEventsListeningTo.indexOf(eventName) >= 0) {
914 capturedEventListeners[eventName] = capturedEventListeners[eventName].filter(function (fn) {
915 return fn !== listenerFn;
916 });
917 return;
918 }
919 }
920
921 return originalRemoveEventListener.apply(this, arguments);
922 };
923
924 var originalPushState = window.history.pushState;
925
926 window.history.pushState = function (state) {
927 var result = originalPushState.apply(this, arguments);
928 urlReroute(createPopStateEvent(state));
929 return result;
930 };
931
932 var originalReplaceState = window.history.replaceState;
933
934 window.history.replaceState = function (state) {
935 var result = originalReplaceState.apply(this, arguments);
936 urlReroute(createPopStateEvent(state));
937 return result;
938 };
939
940 function createPopStateEvent(state) {
941 // https://github.com/single-spa/single-spa/issues/224 and https://github.com/single-spa/single-spa-angular/issues/49
942 // We need a popstate event even though the browser doesn't do one by default when you call replaceState, so that
943 // all the applications can reroute.
944 try {
945 return new PopStateEvent("popstate", {
946 state: state
947 });
948 } catch (err) {
949 // IE 11 compatibility https://github.com/single-spa/single-spa/issues/299
950 // https://docs.microsoft.com/en-us/openspecs/ie_standards/ms-html5e/bd560f47-b349-4d2c-baa8-f1560fb489dd
951 var evt = document.createEvent("PopStateEvent");
952 evt.initPopStateEvent("popstate", false, false, state);
953 return evt;
954 }
955 }
956 /* For convenience in `onclick` attributes, we expose a global function for navigating to
957 * whatever an <a> tag's href is.
958 */
959
960
961 window.singleSpaNavigate = navigateToUrl;
962
963 function parseUri(str) {
964 var anchor = document.createElement("a");
965 anchor.href = str;
966 return anchor;
967 }
968
969 var hasInitialized = false;
970 function ensureJQuerySupport() {
971 var jQuery = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.jQuery;
972
973 if (!jQuery) {
974 if (window.$ && window.$.fn && window.$.fn.jquery) {
975 jQuery = window.$;
976 }
977 }
978
979 if (jQuery && !hasInitialized) {
980 var originalJQueryOn = jQuery.fn.on;
981 var originalJQueryOff = jQuery.fn.off;
982
983 jQuery.fn.on = function (eventString, fn) {
984 return captureRoutingEvents.call(this, originalJQueryOn, window.addEventListener, eventString, fn, arguments);
985 };
986
987 jQuery.fn.off = function (eventString, fn) {
988 return captureRoutingEvents.call(this, originalJQueryOff, window.removeEventListener, eventString, fn, arguments);
989 };
990
991 hasInitialized = true;
992 }
993 }
994
995 function captureRoutingEvents(originalJQueryFunction, nativeFunctionToCall, eventString, fn, originalArgs) {
996 if (typeof eventString !== "string") {
997 return originalJQueryFunction.apply(this, originalArgs);
998 }
999
1000 var eventNames = eventString.split(/\s+/);
1001 eventNames.forEach(function (eventName) {
1002 if (routingEventsListeningTo.indexOf(eventName) >= 0) {
1003 nativeFunctionToCall(eventName, fn);
1004 eventString = eventString.replace(eventName, "");
1005 }
1006 });
1007
1008 if (eventString.trim() === "") {
1009 return this;
1010 } else {
1011 return originalJQueryFunction.apply(this, originalArgs);
1012 }
1013 }
1014
1015 var appsToUnload = {};
1016 function toUnloadPromise(app) {
1017 return Promise.resolve().then(function () {
1018 var unloadInfo = appsToUnload[toName(app)];
1019
1020 if (!unloadInfo) {
1021 /* No one has called unloadApplication for this app,
1022 */
1023 return app;
1024 }
1025
1026 if (app.status === NOT_LOADED) {
1027 /* This app is already unloaded. We just need to clean up
1028 * anything that still thinks we need to unload the app.
1029 */
1030 finishUnloadingApp(app, unloadInfo);
1031 return app;
1032 }
1033
1034 if (app.status === UNLOADING) {
1035 /* Both unloadApplication and reroute want to unload this app.
1036 * It only needs to be done once, though.
1037 */
1038 return unloadInfo.promise.then(function () {
1039 return app;
1040 });
1041 }
1042
1043 if (app.status !== NOT_MOUNTED) {
1044 /* The app cannot be unloaded until it is unmounted.
1045 */
1046 return app;
1047 }
1048
1049 app.status = UNLOADING;
1050 return reasonableTime(app, "unload").then(function () {
1051 finishUnloadingApp(app, unloadInfo);
1052 return app;
1053 }).catch(function (err) {
1054 errorUnloadingApp(app, unloadInfo, err);
1055 return app;
1056 });
1057 });
1058 }
1059
1060 function finishUnloadingApp(app, unloadInfo) {
1061 delete appsToUnload[toName(app)]; // Unloaded apps don't have lifecycles
1062
1063 delete app.bootstrap;
1064 delete app.mount;
1065 delete app.unmount;
1066 delete app.unload;
1067 app.status = NOT_LOADED;
1068 /* resolve the promise of whoever called unloadApplication.
1069 * This should be done after all other cleanup/bookkeeping
1070 */
1071
1072 unloadInfo.resolve();
1073 }
1074
1075 function errorUnloadingApp(app, unloadInfo, err) {
1076 delete appsToUnload[toName(app)]; // Unloaded apps don't have lifecycles
1077
1078 delete app.bootstrap;
1079 delete app.mount;
1080 delete app.unmount;
1081 delete app.unload;
1082 handleAppError(err, app);
1083 app.status = SKIP_BECAUSE_BROKEN;
1084 unloadInfo.reject(err);
1085 }
1086
1087 function addAppToUnload(app, promiseGetter, resolve, reject) {
1088 appsToUnload[toName(app)] = {
1089 app: app,
1090 resolve: resolve,
1091 reject: reject
1092 };
1093 Object.defineProperty(appsToUnload[toName(app)], "promise", {
1094 get: promiseGetter
1095 });
1096 }
1097 function getAppUnloadInfo(appName) {
1098 return appsToUnload[appName];
1099 }
1100 function getAppsToUnload() {
1101 return Object.keys(appsToUnload).map(function (appName) {
1102 return appsToUnload[appName].app;
1103 }).filter(isntActive);
1104 }
1105
1106 var apps = [];
1107 function getMountedApps() {
1108 return apps.filter(isActive).map(toName);
1109 }
1110 function getAppNames() {
1111 return apps.map(toName);
1112 } // used in devtools, not (currently) exposed as a single-spa API
1113
1114 function getRawAppData() {
1115 return [].concat(apps);
1116 }
1117 function getAppStatus(appName) {
1118 var app = find(apps, function (app) {
1119 return toName(app) === appName;
1120 });
1121 return app ? app.status : null;
1122 }
1123 function registerApplication(appName, applicationOrLoadingFn, activityFn) {
1124 var customProps = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1125 if (typeof appName !== "string" || appName.length === 0) throw Error(formatErrorMessage(20, "The first argument to registerApplication must be a non-empty string 'appName'"));
1126 if (getAppNames().indexOf(appName) !== -1) throw Error(formatErrorMessage(21, "There is already an app declared with name ".concat(appName), appName));
1127 if (_typeof(customProps) !== "object" || Array.isArray(customProps)) throw Error(formatErrorMessage(22, "customProps must be an object"));
1128 if (!applicationOrLoadingFn) throw Error(formatErrorMessage(23, "The application or loading function is required"));
1129 var loadImpl;
1130
1131 if (typeof applicationOrLoadingFn !== "function") {
1132 // applicationOrLoadingFn is an application
1133 loadImpl = function loadImpl() {
1134 return Promise.resolve(applicationOrLoadingFn);
1135 };
1136 } else {
1137 // applicationOrLoadingFn is a loadingFn
1138 loadImpl = applicationOrLoadingFn;
1139 }
1140
1141 if (typeof activityFn !== "function") throw Error(formatErrorMessage(24, "The activityFunction argument must be a function"));
1142 apps.push({
1143 loadErrorTime: null,
1144 name: appName,
1145 loadImpl: loadImpl,
1146 activeWhen: activityFn,
1147 status: NOT_LOADED,
1148 parcels: {},
1149 devtools: {
1150 overlays: {
1151 options: {},
1152 selectors: []
1153 }
1154 },
1155 customProps: customProps
1156 });
1157 ensureJQuerySupport();
1158 reroute();
1159 }
1160 function checkActivityFunctions(location) {
1161 return apps.filter(function (app) {
1162 return app.activeWhen(location);
1163 }).map(toName);
1164 }
1165 function getAppsToLoad() {
1166 return apps.filter(notSkipped).filter(withoutLoadErrors).filter(isntLoaded).filter(shouldBeActive);
1167 }
1168 function getAppsToUnmount() {
1169 return apps.filter(notSkipped).filter(isActive).filter(shouldntBeActive);
1170 }
1171 function getAppsToMount() {
1172 return apps.filter(notSkipped).filter(isntActive).filter(isLoaded).filter(shouldBeActive);
1173 }
1174 function unregisterApplication(appName) {
1175 if (!apps.find(function (app) {
1176 return toName(app) === appName;
1177 })) {
1178 throw Error(formatErrorMessage(25, "Cannot unregister application '".concat(appName, "' because no such application has been registered"), appName));
1179 }
1180
1181 return unloadApplication(appName).then(function () {
1182 var appIndex = apps.findIndex(function (app) {
1183 return toName(app) === appName;
1184 });
1185 apps.splice(appIndex, 1);
1186 });
1187 }
1188 function unloadApplication(appName) {
1189 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
1190 waitForUnmount: false
1191 };
1192
1193 if (typeof appName !== "string") {
1194 throw Error(formatErrorMessage(26, "unloadApplication requires a string 'appName'"));
1195 }
1196
1197 var app = find(apps, function (App) {
1198 return toName(App) === appName;
1199 });
1200
1201 if (!app) {
1202 throw Error(formatErrorMessage(27, "Could not unload application '".concat(appName, "' because no such application has been registered"), appName));
1203 }
1204
1205 var appUnloadInfo = getAppUnloadInfo(toName(app));
1206
1207 if (opts && opts.waitForUnmount) {
1208 // We need to wait for unmount before unloading the app
1209 if (appUnloadInfo) {
1210 // Someone else is already waiting for this, too
1211 return appUnloadInfo.promise;
1212 } else {
1213 // We're the first ones wanting the app to be resolved.
1214 var promise = new Promise(function (resolve, reject) {
1215 addAppToUnload(app, function () {
1216 return promise;
1217 }, resolve, reject);
1218 });
1219 return promise;
1220 }
1221 } else {
1222 /* We should unmount the app, unload it, and remount it immediately.
1223 */
1224 var resultPromise;
1225
1226 if (appUnloadInfo) {
1227 // Someone else is already waiting for this app to unload
1228 resultPromise = appUnloadInfo.promise;
1229 immediatelyUnloadApp(app, appUnloadInfo.resolve, appUnloadInfo.reject);
1230 } else {
1231 // We're the first ones wanting the app to be resolved.
1232 resultPromise = new Promise(function (resolve, reject) {
1233 addAppToUnload(app, function () {
1234 return resultPromise;
1235 }, resolve, reject);
1236 immediatelyUnloadApp(app, resolve, reject);
1237 });
1238 }
1239
1240 return resultPromise;
1241 }
1242 }
1243
1244 function immediatelyUnloadApp(app, resolve, reject) {
1245 toUnmountPromise(app).then(toUnloadPromise).then(function () {
1246 resolve();
1247 setTimeout(function () {
1248 // reroute, but the unload promise is done
1249 reroute();
1250 });
1251 }).catch(reject);
1252 }
1253
1254 var appChangeUnderway = false,
1255 peopleWaitingOnAppChange = [];
1256 function triggerAppChange() {
1257 // Call reroute with no arguments, intentionally
1258 return reroute();
1259 }
1260 function reroute() {
1261 var pendingPromises = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
1262 var eventArguments = arguments.length > 1 ? arguments[1] : undefined;
1263
1264 if (appChangeUnderway) {
1265 return new Promise(function (resolve, reject) {
1266 peopleWaitingOnAppChange.push({
1267 resolve: resolve,
1268 reject: reject,
1269 eventArguments: eventArguments
1270 });
1271 });
1272 }
1273
1274 appChangeUnderway = true;
1275 var wasNoOp = true;
1276
1277 if (isStarted()) {
1278 return performAppChanges();
1279 } else {
1280 return loadApps();
1281 }
1282
1283 function loadApps() {
1284 return Promise.resolve().then(function () {
1285 var loadPromises = getAppsToLoad().map(toLoadPromise);
1286
1287 if (loadPromises.length > 0) {
1288 wasNoOp = false;
1289 }
1290
1291 return Promise.all(loadPromises).then(finishUpAndReturn).catch(function (err) {
1292 callAllEventListeners();
1293 throw err;
1294 });
1295 });
1296 }
1297
1298 function performAppChanges() {
1299 return Promise.resolve().then(function () {
1300 window.dispatchEvent(new customEvent("single-spa:before-routing-event", getCustomEventDetail()));
1301 var unloadPromises = getAppsToUnload().map(toUnloadPromise);
1302 var unmountUnloadPromises = getAppsToUnmount().map(toUnmountPromise).map(function (unmountPromise) {
1303 return unmountPromise.then(toUnloadPromise);
1304 });
1305 var allUnmountPromises = unmountUnloadPromises.concat(unloadPromises);
1306
1307 if (allUnmountPromises.length > 0) {
1308 wasNoOp = false;
1309 }
1310
1311 var unmountAllPromise = Promise.all(allUnmountPromises);
1312 var appsToLoad = getAppsToLoad();
1313 /* We load and bootstrap apps while other apps are unmounting, but we
1314 * wait to mount the app until all apps are finishing unmounting
1315 */
1316
1317 var loadThenMountPromises = appsToLoad.map(function (app) {
1318 return toLoadPromise(app).then(toBootstrapPromise).then(function (app) {
1319 return unmountAllPromise.then(function () {
1320 return toMountPromise(app);
1321 });
1322 });
1323 });
1324
1325 if (loadThenMountPromises.length > 0) {
1326 wasNoOp = false;
1327 }
1328 /* These are the apps that are already bootstrapped and just need
1329 * to be mounted. They each wait for all unmounting apps to finish up
1330 * before they mount.
1331 */
1332
1333
1334 var mountPromises = getAppsToMount().filter(function (appToMount) {
1335 return appsToLoad.indexOf(appToMount) < 0;
1336 }).map(function (appToMount) {
1337 return toBootstrapPromise(appToMount).then(function () {
1338 return unmountAllPromise;
1339 }).then(function () {
1340 return toMountPromise(appToMount);
1341 });
1342 });
1343
1344 if (mountPromises.length > 0) {
1345 wasNoOp = false;
1346 }
1347
1348 return unmountAllPromise.catch(function (err) {
1349 callAllEventListeners();
1350 throw err;
1351 }).then(function () {
1352 /* Now that the apps that needed to be unmounted are unmounted, their DOM navigation
1353 * events (like hashchange or popstate) should have been cleaned up. So it's safe
1354 * to let the remaining captured event listeners to handle about the DOM event.
1355 */
1356 callAllEventListeners();
1357 return Promise.all(loadThenMountPromises.concat(mountPromises)).catch(function (err) {
1358 pendingPromises.forEach(function (promise) {
1359 return promise.reject(err);
1360 });
1361 throw err;
1362 }).then(function () {
1363 return finishUpAndReturn(false);
1364 });
1365 });
1366 });
1367 }
1368
1369 function finishUpAndReturn() {
1370 var callEventListeners = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1371 var returnValue = getMountedApps();
1372
1373 if (callEventListeners) {
1374 callAllEventListeners();
1375 }
1376
1377 pendingPromises.forEach(function (promise) {
1378 return promise.resolve(returnValue);
1379 });
1380
1381 try {
1382 var appChangeEventName = wasNoOp ? "single-spa:no-app-change" : "single-spa:app-change";
1383 window.dispatchEvent(new customEvent(appChangeEventName, getCustomEventDetail()));
1384 window.dispatchEvent(new customEvent("single-spa:routing-event", getCustomEventDetail()));
1385 } catch (err) {
1386 /* We use a setTimeout because if someone else's event handler throws an error, single-spa
1387 * needs to carry on. If a listener to the event throws an error, it's their own fault, not
1388 * single-spa's.
1389 */
1390 setTimeout(function () {
1391 throw err;
1392 });
1393 }
1394 /* Setting this allows for subsequent calls to reroute() to actually perform
1395 * a reroute instead of just getting queued behind the current reroute call.
1396 * We want to do this after the mounting/unmounting is done but before we
1397 * resolve the promise for the `reroute` function.
1398 */
1399
1400
1401 appChangeUnderway = false;
1402
1403 if (peopleWaitingOnAppChange.length > 0) {
1404 /* While we were rerouting, someone else triggered another reroute that got queued.
1405 * So we need reroute again.
1406 */
1407 var nextPendingPromises = peopleWaitingOnAppChange;
1408 peopleWaitingOnAppChange = [];
1409 reroute(nextPendingPromises);
1410 }
1411
1412 return returnValue;
1413 }
1414 /* We need to call all event listeners that have been delayed because they were
1415 * waiting on single-spa. This includes haschange and popstate events for both
1416 * the current run of performAppChanges(), but also all of the queued event listeners.
1417 * We want to call the listeners in the same order as if they had not been delayed by
1418 * single-spa, which means queued ones first and then the most recent one.
1419 */
1420
1421
1422 function callAllEventListeners() {
1423 pendingPromises.forEach(function (pendingPromise) {
1424 callCapturedEventListeners(pendingPromise.eventArguments);
1425 });
1426 callCapturedEventListeners(eventArguments);
1427 }
1428
1429 function getCustomEventDetail() {
1430 var result = {
1431 detail: {}
1432 };
1433
1434 if (eventArguments && eventArguments[0]) {
1435 result.detail.originalEvent = eventArguments[0];
1436 }
1437
1438 return result;
1439 }
1440 }
1441
1442 var started = false;
1443 function start() {
1444 started = true;
1445 reroute();
1446 }
1447 function isStarted() {
1448 return started;
1449 }
1450 setTimeout(function () {
1451 if (!started) {
1452 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."));
1453 }
1454 }, 5000);
1455
1456 var devtools = {
1457 getRawAppData: getRawAppData,
1458 reroute: reroute,
1459 NOT_LOADED: NOT_LOADED,
1460 toLoadPromise: toLoadPromise,
1461 toBootstrapPromise: toBootstrapPromise,
1462 unregisterApplication: unregisterApplication
1463 };
1464
1465 if (window && window.__SINGLE_SPA_DEVTOOLS__) {
1466 window.__SINGLE_SPA_DEVTOOLS__.exposedMethods = devtools;
1467 }
1468
1469 exports.BOOTSTRAPPING = BOOTSTRAPPING;
1470 exports.LOADING_SOURCE_CODE = LOADING_SOURCE_CODE;
1471 exports.LOAD_ERROR = LOAD_ERROR;
1472 exports.MOUNTED = MOUNTED;
1473 exports.MOUNTING = MOUNTING;
1474 exports.NOT_BOOTSTRAPPED = NOT_BOOTSTRAPPED;
1475 exports.NOT_LOADED = NOT_LOADED;
1476 exports.NOT_MOUNTED = NOT_MOUNTED;
1477 exports.SKIP_BECAUSE_BROKEN = SKIP_BECAUSE_BROKEN;
1478 exports.UNMOUNTING = UNMOUNTING;
1479 exports.UPDATING = UPDATING;
1480 exports.addErrorHandler = addErrorHandler;
1481 exports.checkActivityFunctions = checkActivityFunctions;
1482 exports.ensureJQuerySupport = ensureJQuerySupport;
1483 exports.getAppNames = getAppNames;
1484 exports.getAppStatus = getAppStatus;
1485 exports.getMountedApps = getMountedApps;
1486 exports.mountRootParcel = mountRootParcel;
1487 exports.navigateToUrl = navigateToUrl;
1488 exports.registerApplication = registerApplication;
1489 exports.removeErrorHandler = removeErrorHandler;
1490 exports.setBootstrapMaxTime = setBootstrapMaxTime;
1491 exports.setMountMaxTime = setMountMaxTime;
1492 exports.setUnloadMaxTime = setUnloadMaxTime;
1493 exports.setUnmountMaxTime = setUnmountMaxTime;
1494 exports.start = start;
1495 exports.triggerAppChange = triggerAppChange;
1496 exports.unloadApplication = unloadApplication;
1497
1498 Object.defineProperty(exports, '__esModule', { value: true });
1499
1500})));
1501//# sourceMappingURL=single-spa.dev.js.map