├── public └── index.html ├── .gitignore ├── dist ├── index.html └── bundle.js ├── src ├── index.js └── root-config.js ├── webpack.config.js ├── README.md ├── single-spa.config.js └── package.json /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { registerApplication, start } from "single-spa"; 2 | import { constructApplications, constructRoutes, constructLayoutEngine } from "single-spa-layout"; 3 | import layout from "./root-config"; 4 | 5 | const routes = constructRoutes(layout); 6 | const applications = constructApplications({ routes, loadApp: (name) => System.import(name) }); 7 | const layoutEngine = constructLayoutEngine({ routes, applications }); 8 | 9 | applications.forEach(registerApplication); 10 | layoutEngine.activate(); 11 | start(); 12 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 2 | 3 | module.exports = { 4 | entry: "./src/index.js", 5 | output: { 6 | filename: "bundle.js", 7 | publicPath: "/", 8 | }, 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.js$/, 13 | exclude: /node_modules/, 14 | loader: "babel-loader", 15 | }, 16 | ], 17 | }, 18 | plugins: [ 19 | new HtmlWebpackPlugin({ 20 | template: "./public/index.html", 21 | }), 22 | ], 23 | devServer: { 24 | historyApiFallback: true, 25 | port: 9000, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multi-Tenant-CMS 2 | 3 | Using microfrontends with Webpack Module Federation and Single-SPA 4 | 5 | ## Main Single-SPA Orchestration Repository 6 | ## Purpose: 7 | This repository will serve as the root application for orchestrating all the microfrontends, handling routing, and registering each microfrontend. 8 | ## Content: 9 | This will include the configuration of Single-SPA, handling the global navigation, and managing shared dependencies. 10 | 11 | MicroFrontend Root page for integrating [CMS React Editorial](https://github.com/AaqibhafeezKhan/cms-react-editorial) , [CMS Vue Media](https://github.com/AaqibhafeezKhan/cms-vue-media) , [CMS Angular Auth](https://github.com/AaqibhafeezKhan/cms-angular-auth) and [CMS Svelte Collab](https://github.com/AaqibhafeezKhan/cms-svelte-collab) 12 | 13 | -------------------------------------------------------------------------------- /single-spa.config.js: -------------------------------------------------------------------------------- 1 | import { registerApplication, start } from 'single-spa'; 2 | 3 | registerApplication( 4 | 'react-editorial', 5 | () => System.import('https://AaqibhafeezKhan.github.io/cms-react-editorial/main.js'), 6 | pathPrefix('/editorial') 7 | ); 8 | 9 | registerApplication( 10 | 'vue-media', 11 | () => System.import('https://AaqibhafeezKhan.github.io/cms-vue-media/main.js'), 12 | pathPrefix('/media-library') 13 | ); 14 | 15 | registerApplication( 16 | 'angular-auth', 17 | () => System.import('https://AaqibhafeezKhan.github.io/cms-angular-auth/main.js'), 18 | pathPrefix('/auth') 19 | ); 20 | 21 | registerApplication( 22 | 'svelte-collab', 23 | () => System.import('https://AaqibhafeezKhan.github.io/cms-svelte-collab/main.js'), 24 | pathPrefix('/collab') 25 | ); 26 | 27 | 28 | start(); 29 | -------------------------------------------------------------------------------- /src/root-config.js: -------------------------------------------------------------------------------- 1 | export default ` 2 | 3 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | `; 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cms-root-orchestration", 3 | "version": "1.0.0", 4 | "description": "Orchestration layer for microfrontends in CMS using Single-SPA", 5 | "main": "index.js", 6 | "homepage": "https://AaqibhafeezKhan.github.io/cms-root-orchestration", 7 | "scripts": { 8 | "predeploy": "npm run build", 9 | "deploy": "gh-pages -d dist", 10 | "start": "webpack serve --mode development", 11 | "build": "webpack --mode production" 12 | }, 13 | "dependencies": { 14 | "single-spa": "^5.9.3", 15 | "single-spa-layout": "^1.0.0" 16 | }, 17 | "devDependencies": { 18 | "@babel/core": "^7.25.8", 19 | "@babel/preset-env": "^7.25.8", 20 | "babel-loader": "^8.4.1", 21 | "gh-pages": "^6.2.0", 22 | "html-webpack-plugin": "^5.3.1", 23 | "webpack": "^5.24.3", 24 | "webpack-cli": "^4.5.0", 25 | "webpack-dev-server": "^3.11.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /dist/bundle.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";var t={d:(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})}};t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),t.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),t.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var e={};t.r(e),t.d(e,{BOOTSTRAPPING:()=>v,LOADING_SOURCE_CODE:()=>h,LOAD_ERROR:()=>P,MOUNTED:()=>y,MOUNTING:()=>g,NOT_BOOTSTRAPPED:()=>m,NOT_LOADED:()=>d,NOT_MOUNTED:()=>w,SKIP_BECAUSE_BROKEN:()=>T,UNLOADING:()=>O,UNMOUNTING:()=>E,UPDATING:()=>b,addErrorHandler:()=>s,checkActivityFunctions:()=>Nt,ensureJQuerySupport:()=>pt,getAppNames:()=>Ot,getAppStatus:()=>Pt,getMountedApps:()=>Et,mountRootParcel:()=>H,navigateToUrl:()=>ot,pathToActiveWhen:()=>Ct,registerApplication:()=>Tt,removeErrorHandler:()=>l,setBootstrapMaxTime:()=>J,setMountMaxTime:()=>Q,setUnloadMaxTime:()=>z,setUnmountMaxTime:()=>V,start:()=>Rt,triggerAppChange:()=>_t,unloadApplication:()=>St,unregisterApplication:()=>At});var n=Object.freeze({__proto__:null,get start(){return Rt},get ensureJQuerySupport(){return pt},get setBootstrapMaxTime(){return J},get setMountMaxTime(){return Q},get setUnmountMaxTime(){return V},get setUnloadMaxTime(){return z},get registerApplication(){return Tt},get unregisterApplication(){return At},get getMountedApps(){return Et},get getAppStatus(){return Pt},get unloadApplication(){return St},get checkActivityFunctions(){return Nt},get getAppNames(){return Ot},get pathToActiveWhen(){return Ct},get navigateToUrl(){return ot},get triggerAppChange(){return _t},get addErrorHandler(){return s},get removeErrorHandler(){return l},get mountRootParcel(){return H},get NOT_LOADED(){return d},get LOADING_SOURCE_CODE(){return h},get NOT_BOOTSTRAPPED(){return m},get BOOTSTRAPPING(){return v},get NOT_MOUNTED(){return w},get MOUNTING(){return g},get UPDATING(){return b},get LOAD_ERROR(){return P},get MOUNTED(){return y},get UNLOADING(){return O},get UNMOUNTING(){return E},get SKIP_BECAUSE_BROKEN(){return T}});function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var i=("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==t.g?t.g:"undefined"!=typeof self?self:{}).CustomEvent,a=function(){try{var t=new i("cat",{detail:{foo:"bar"}});return"cat"===t.type&&"bar"===t.detail.foo}catch(t){}return!1}()?i:"undefined"!=typeof document&&"function"==typeof document.createEvent?function(t,e){var n=document.createEvent("CustomEvent");return e?n.initCustomEvent(t,e.bubbles,e.cancelable,e.detail):n.initCustomEvent(t,!1,!1,void 0),n}:function(t,e){var n=document.createEventObject();return n.type=t,e?(n.bubbles=Boolean(e.bubbles),n.cancelable=Boolean(e.cancelable),n.detail=e.detail):(n.bubbles=!1,n.cancelable=!1,n.detail=void 0),n},u=[];function c(t,e,n){var r=p(t,e,n);u.length?u.forEach((function(t){return t(r)})):setTimeout((function(){throw r}))}function s(t){if("function"!=typeof t)throw Error(f(28,!1));u.push(t)}function l(t){if("function"!=typeof t)throw Error(f(29,!1));var e=!1;return u=u.filter((function(n){var r=n===t;return e=e||r,!r})),e}function f(t,e){for(var n=arguments.length,r=new Array(n>2?n-2:0),o=2;o0;t--)for(var e in arguments[t])"__proto__"!==e&&(arguments[t-1][e]=arguments[t][e]);return arguments[0]}function M(t,e){for(var n=0;n=0&&nt[n].forEach((function(n){try{n.apply(e,t)}catch(t){setTimeout((function(){throw t}))}}))}}function at(){It([],arguments)}function ut(t,e){return function(){var n=window.location.href,r=t.apply(this,arguments),o=window.location.href;return tt&&n===o||(Bt()?window.dispatchEvent(function(t,e){var n;try{n=new PopStateEvent("popstate",{state:t})}catch(e){(n=document.createEvent("PopStateEvent")).initPopStateEvent("popstate",!1,!1,t)}return n.singleSpa=!0,n.singleSpaTrigger=e,n}(window.history.state,e)):It([])),r}}if(et){window.addEventListener("hashchange",at),window.addEventListener("popstate",at);var ct=window.addEventListener,st=window.removeEventListener;window.addEventListener=function(t,e){if(!("function"==typeof e&&rt.indexOf(t)>=0)||M(nt[t],(function(t){return t===e})))return ct.apply(this,arguments);nt[t].push(e)},window.removeEventListener=function(t,e){if(!("function"==typeof e&&rt.indexOf(t)>=0))return st.apply(this,arguments);nt[t]=nt[t].filter((function(t){return t!==e}))},window.history.pushState=ut(window.history.pushState,"pushState"),window.history.replaceState=ut(window.history.replaceState,"replaceState"),window.singleSpaNavigate?console.warn(f(41,!1)):window.singleSpaNavigate=ot}function lt(t){var e=document.createElement("a");return e.href=t,e}var ft=!1;function pt(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window.jQuery;if(t||window.$&&window.$.fn&&window.$.fn.jquery&&(t=window.$),t&&!ft){var e=t.fn.on,n=t.fn.off;t.fn.on=function(t,n){return dt.call(this,e,window.addEventListener,t,n,arguments)},t.fn.off=function(t,e){return dt.call(this,n,window.removeEventListener,t,e,arguments)},ft=!0}}function dt(t,e,n,r,o){return"string"!=typeof n?t.apply(this,o):(n.split(/\s+/).forEach((function(t){rt.indexOf(t)>=0&&(e(t,r),n=n.replace(t,""))})),""===n.trim()?this:t.apply(this,o))}var ht={};function mt(t){return Promise.resolve().then((function(){var e=ht[S(t)];if(!e)return t;if(t.status===d)return vt(t,e),t;if(t.status===O)return e.promise.then((function(){return t}));if(t.status!==w&&t.status!==P)return t;var n=t.status===P?Promise.resolve():X(t,"unload");return t.status=O,n.then((function(){return vt(t,e),t})).catch((function(n){return function(t,e,n){delete ht[S(t)],delete t.bootstrap,delete t.mount,delete t.unmount,delete t.unload,c(n,t,T),e.reject(n)}(t,e,n),t}))}))}function vt(t,e){delete ht[S(t)],delete t.bootstrap,delete t.mount,delete t.unmount,delete t.unload,t.status=d,e.resolve()}function wt(t,e,n,r){ht[S(t)]={app:t,resolve:n,reject:r},Object.defineProperty(ht[S(t)],"promise",{get:e})}function gt(t){return ht[t]}var yt=[];function bt(){var t=[],e=[],n=[],r=[],o=(new Date).getTime();return yt.forEach((function(i){var a=i.status!==T&&A(i);switch(i.status){case P:a&&o-i.loadErrorTime>=200&&n.push(i);break;case d:case h:a&&n.push(i);break;case m:case w:!a&>(S(i))?t.push(i):a&&r.push(i);break;case y:a||e.push(i)}})),{appsToUnload:t,appsToUnmount:e,appsToLoad:n,appsToMount:r}}function Et(){return yt.filter(N).map(S)}function Ot(){return yt.map(S)}function Pt(t){var e=M(yt,(function(e){return S(e)===t}));return e?e.status:null}function Tt(t,e,n,o){var i=function(t,e,n,o){var i,a={name:null,loadApp:null,activeWhen:null,customProps:null};return"object"===r(t)?(function(t){if(Array.isArray(t)||null===t)throw Error(f(39,!1));var e=["name","app","activeWhen","customProps"],n=Object.keys(t).reduce((function(t,n){return e.indexOf(n)>=0?t:t.concat(n)}),[]);if(0!==n.length)throw Error(f(38,!1,e.join(", "),n.join(", ")));if("string"!=typeof t.name||0===t.name.length)throw Error(f(20,!1));if("object"!==r(t.app)&&"function"!=typeof t.app)throw Error(f(20,!1));var o=function(t){return"string"==typeof t||"function"==typeof t};if(!(o(t.activeWhen)||Array.isArray(t.activeWhen)&&t.activeWhen.every(o)))throw Error(f(24,!1));if(!Lt(t.customProps))throw Error(f(22,!1))}(t),a.name=t.name,a.loadApp=t.app,a.activeWhen=t.activeWhen,a.customProps=t.customProps):(function(t,e,n,r){if("string"!=typeof t||0===t.length)throw Error(f(20,!1));if(!e)throw Error(f(23,!1));if("function"!=typeof n)throw Error(f(24,!1));if(!Lt(r))throw Error(f(22,!1))}(t,e,n,o),a.name=t,a.loadApp=e,a.activeWhen=n,a.customProps=o),a.loadApp="function"!=typeof(i=a.loadApp)?function(){return Promise.resolve(i)}:i,a.customProps=function(t){return t||{}}(a.customProps),a.activeWhen=function(t){var e=Array.isArray(t)?t:[t];return e=e.map((function(t){return"function"==typeof t?t:Ct(t)})),function(t){return e.some((function(e){return e(t)}))}}(a.activeWhen),a}(t,e,n,o);if(-1!==Ot().indexOf(i.name))throw Error(f(21,!1,i.name));yt.push(C({loadErrorTime:null,status:d,parcels:{},devtools:{overlays:{options:{},selectors:[]}}},i)),et&&(pt(),It())}function Nt(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window.location;return yt.filter((function(e){return e.activeWhen(t)})).map(S)}function At(t){if(0===yt.filter((function(e){return S(e)===t})).length)throw Error(f(25,!1,t));return St(t).then((function(){var e=yt.map(S).indexOf(t);yt.splice(e,1)}))}function St(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{waitForUnmount:!1};if("string"!=typeof t)throw Error(f(26,!1));var n=M(yt,(function(e){return S(e)===t}));if(!n)throw Error(f(27,!1,t));var r,o=gt(S(n));if(e&&e.waitForUnmount){if(o)return o.promise;var i=new Promise((function(t,e){wt(n,(function(){return i}),t,e)}));return i}return o?(r=o.promise,jt(n,o.resolve,o.reject)):r=new Promise((function(t,e){wt(n,(function(){return r}),t,e),jt(n,t,e)})),r}function jt(t,e,n){U(t).then(mt).then((function(){e(),setTimeout((function(){It()}))})).catch(n)}function Lt(t){return!t||"function"==typeof t||"object"===r(t)&&null!==t&&!Array.isArray(t)}function Ct(t,e){var n=function(t,e){var n=0,r=!1,o="^";"/"!==t[0]&&(t="/"+t);for(var i=0;i0&&void 0!==arguments[0]?arguments[0]:[],e=arguments.length>1?arguments[1]:void 0;if(Mt)return new Promise((function(t,n){Dt.push({resolve:t,reject:n,eventArguments:e})}));var n,r=bt(),i=r.appsToUnload,u=r.appsToUnmount,c=r.appsToLoad,s=r.appsToMount,l=!1,f=xt,p=xt=window.location.href;return Bt()?(Mt=!0,n=i.concat(c,u,s),Promise.resolve().then((function(){if(window.dispatchEvent(new a(0===n.length?"single-spa:before-no-app-change":"single-spa:before-app-change",g(!0))),window.dispatchEvent(new a("single-spa:before-routing-event",g(!0,{cancelNavigation:h}))),l)return window.dispatchEvent(new a("single-spa:before-mount-routing-event",g(!0))),m(),void ot(f);var e=i.map(mt),r=u.map(U).map((function(t){return t.then(mt)})).concat(e),o=Promise.all(r);o.then((function(){window.dispatchEvent(new a("single-spa:before-mount-routing-event",g(!0)))}));var p=c.map((function(t){return Z(t).then((function(t){return Ut(t,o)}))})),d=s.filter((function(t){return c.indexOf(t)<0})).map((function(t){return Ut(t,o)}));return o.catch((function(t){throw v(),t})).then((function(){return v(),Promise.all(p.concat(d)).catch((function(e){throw t.forEach((function(t){return t.reject(e)})),e})).then(m)}))}))):(n=c,Promise.resolve().then((function(){var t=c.map(Z);return Promise.all(t).then(v).then((function(){return[]})).catch((function(t){throw v(),t}))})));function h(){l=!0}function m(){var e=Et();t.forEach((function(t){return t.resolve(e)}));try{var r=0===n.length?"single-spa:no-app-change":"single-spa:app-change";window.dispatchEvent(new a(r,g())),window.dispatchEvent(new a("single-spa:routing-event",g()))}catch(t){setTimeout((function(){throw t}))}if(Mt=!1,Dt.length>0){var o=Dt;Dt=[],It(o)}return e}function v(){t.forEach((function(t){it(t.eventArguments)})),it(e)}function g(){var t,r=arguments.length>0&&void 0!==arguments[0]&&arguments[0],a=arguments.length>1?arguments[1]:void 0,h={},m=(o(t={},y,[]),o(t,w,[]),o(t,d,[]),o(t,T,[]),t);r?(c.concat(s).forEach((function(t,e){g(t,y)})),i.forEach((function(t){g(t,d)})),u.forEach((function(t){g(t,w)}))):n.forEach((function(t){g(t)}));var v={detail:{newAppStatuses:h,appsByNewStatus:m,totalAppChanges:n.length,originalEvent:null==e?void 0:e[0],oldUrl:f,newUrl:p,navigationIsCanceled:l}};return a&&C(v.detail,a),v;function g(t,e){var n=S(t);e=e||Pt(n),h[n]=e,(m[e]=m[e]||[]).push(n)}}}function Ut(t,e){return A(t)?I(t).then((function(t){return e.then((function(){return A(t)?B(t):t}))})):e.then((function(){return t}))}var Wt=!1;function Rt(t){var e;Wt=!0,t&&t.urlRerouteOnly&&(e=t.urlRerouteOnly,tt=e),et&&It()}function Bt(){return Wt}et&&setTimeout((function(){Wt||console.warn(f(1,!1))}),5e3);var Gt={getRawAppData:function(){return[].concat(yt)},reroute:It,NOT_LOADED:d,toLoadPromise:Z,toBootstrapPromise:I,unregisterApplication:At};function kt(t){return(kt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function Ht(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function $t(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function Ft(t){for(var e=1;et.length)&&(e=t.length);for(var n=0,r=new Array(e);n0&&console.warn(Error("Invalid ".concat(t,": received invalid properties '").concat(i.join(", "),"', but valid properties are ").concat(n.join(", "))))}}function Yt(t,e){var n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if("string"!=typeof e||n&&""===e.trim())throw Error("Invalid ".concat(t,": received '").concat(e,"', but expected a").concat(n?" non-blank":""," string"))}function Zt(t,e){if(Yt(t,e),e.indexOf("/")<0)throw Error("Invalid ".concat(t,": received '").concat(e,"', but expected an absolute path that starts with /"))}function te(t,e,n){if(!Array.isArray(e)&&("object"!==kt(kt(e))||"number"!==e.length))throw Error("Invalid ".concat(t,": received '").concat(e,"', but expected an array"));for(var r=arguments.length,o=new Array(r>3?r-3:0),i=3;i1&&(n=n.slice(0,n.length-1)),n}function ne(t,e){for(var n=0;n0)throw Error(" elements must not have childNodes. You must put in a closing - self closing is not allowed");var r={type:"application",name:ie(t,"name")},o=ie(t,"loader");if(o)if(e.loaders&&e.loaders.hasOwnProperty(o))r.loader=e.loaders[o];else if(Qt)throw Error("Application loader '".concat(o,"' was not defined in the htmlLayoutData"));var i=ie(t,"error");if(i)if(e.errors&&e.errors.hasOwnProperty(i))r.error=e.errors[i];else if(Qt)throw Error("Application error handler '".concat(o,"' was not defined in the htmlLayoutData"));return ce(t,r,e),[r]}if("route"===t.nodeName.toLowerCase()){var a={type:"route",routes:[]},u=ie(t,"path");u&&(a.path=u),ae(t,"default")&&(a.default=!0),ae(t,"exact")&&(a.exact=!0),ce(t,a,e);for(var c=0;c0){t.routes=[];for(var l=0;l1&&void 0!==arguments[1]?arguments[1]:location)["hash"===t.mode?"hash":"pathname"]}function ve(t){try{return new URL(t)}catch(n){var e=document.createElement("a");return e.href=t,e}}function we(t){var e=[],n=Nt(t?ve(t):location);return Ot().forEach((function(t){n.indexOf(t)<0&&e.push(t)})),e}function ge(t,e,n,r){r.forEach((function(r){"application"===r.type?(t[r.name]||(t[r.name]=[]),t[r.name].push({activeWhen:e,props:ye(n,r.props),loader:r.loader})):"route"===r.type?ge(t,r.activeWhen,ye(n,r.props),r.routes):r.routes&&ge(t,e,n,r.routes)}))}function ye(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Ft(Ft({},t),e)}function be(){return!0}const Ee=function(t,e){if(t&&t.nodeName||"string"==typeof t){if(Qt&&!e&&window.singleSpaLayoutData&&(e=window.singleSpaLayoutData),"string"==typeof t){if(!Qt)throw Error("calling constructRoutes with a string on the server is not yet supported");if(!(t=(new DOMParser).parseFromString(t,"text/html").documentElement.querySelector("single-spa-router")))throw Error("constructRoutes should be called with a string HTML document that contains a element.")}t=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if("template"===t.nodeName.toLowerCase()&&(t=(t.content||t).querySelector("single-spa-router")),"single-spa-router"!==t.nodeName.toLowerCase())throw Error("single-spa-layout: The HTMLElement passed to constructRoutes must be or a