UNPKG

ng-dynamic-mf

Version:

[![npm](https://img.shields.io/npm/v/ng-dynamic-mf?color=%2300d26a&style=for-the-badge)](https://www.npmjs.com/package/ng-dynamic-mf) [![Sonar Quality Gate](https://img.shields.io/sonar/quality_gate/LoaderB0T_ng-dynamic-mf?server=https%3A%2F%2Fsonarcloud

261 lines (248 loc) 10.5 kB
import { DOCUMENT } from '@angular/common'; import * as i0 from '@angular/core'; import { inject, Injectable, Pipe } from '@angular/core'; import { environment, ɵinitializeEnvironment as _initializeEnvironment, ɵreuseEnvironment as _reuseEnvironment } from 'ng-dynamic-mf/environment'; import * as i1 from '@angular/router'; class HtmlHeadService { constructor() { this._document = inject(DOCUMENT); this._knownElements = new Set(); } addElement(element) { const head = this._document.getElementsByTagName('head')[0]; const el = this._document.createElement(element.type); switch (element.type) { case 'link': { if (this._knownElements.has(element.href)) { return; } const link = el; link.rel = element.rel; link.href = element.href; this._knownElements.add(element.href); break; } case 'script': { if (this._knownElements.has(element.src)) { return; } const script = el; script.src = element.src; script.crossOrigin = element.crossorigin ?? null; if (element.data) { Object.keys(element.data).forEach(key => { script.setAttribute(`data-${key}`, element.data[key]); }); } this._knownElements.add(element.src); break; } } head.appendChild(el); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: HtmlHeadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: HtmlHeadService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: HtmlHeadService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); /** * Add this to your imports of your angular module to automatically add all remote modules to the app. */ const loadedModules = []; function join(...paths) { return paths.map(p => normalizePath(p)).join('/'); } function normalizePath(path) { return path .replace(/(?<!:)\/+/g, '/') // replace every occurence of slashes except the one after the protocol (eg http:// or https://) .replace(/\/$/, '') // remove trailing slash .replace(/^\//, ''); // remove leading slash } const basePaths = {}; const basePath = (moduleName) => { return basePaths[moduleName] ?? `${location.origin}`; }; const resourceMapper = (moduleName, relativePathFromApp) => { return `${join(basePath(moduleName), relativePathFromApp)}`; }; const loadModule = async (moduleToLoad, loadRemoteModule, mfOrNf) => { fixModuleToLoadUrl(moduleToLoad); const remoteEntryFileName = mfOrNf === 'nf' ? 'remoteEntry.json' : 'remoteEntry.js'; const hash = moduleToLoad.hash ? `?${moduleToLoad.hash}` : ''; let loadedModule; try { loadedModule = await loadRemoteModule({ exposedModule: './Module', remoteEntry: `${join(moduleToLoad.url, remoteEntryFileName)}${hash}`, }); } catch (error) { console.error(`Module not loaded: ${moduleToLoad.name}`, error); return; } basePaths[moduleToLoad.name] = moduleToLoad.url; loadedModules.push(loadedModule[moduleToLoad.ngModuleName]); if (moduleToLoad.hasGlobalStyles) { const head = document.getElementsByTagName('head')[0]; const link = document.createElement('link'); link.id = `global-style-${moduleToLoad.name}`; link.rel = 'stylesheet'; link.type = 'text/css'; link.href = resourceMapper(moduleToLoad.name, moduleToLoad.globalStyleBundleName ?? 'global-styles.css'); link.media = 'all'; link.onerror = e => { console.error(`Error loading global styles for module: ${moduleToLoad.name}`, e); }; head.appendChild(link); } if (!environment.production) { console.debug(`Loaded module: ${moduleToLoad.name}`); } }; function fixModuleToLoadUrl(moduleToLoad) { if (!moduleToLoad.url.startsWith('http')) { if (moduleToLoad.url.startsWith('/')) { moduleToLoad.url = `.${moduleToLoad.url}`; } else if (!moduleToLoad.url.startsWith('./')) { moduleToLoad.url = `./${moduleToLoad.url}`; } } } const initializeAppInternal = async (settings, loadRemoteModule, mfOrNf) => { const actualSettings = { loadEnvironment: 'loadAndReuse', modulePath: '/modules.json', environmentPath: '/environment.json', ...settings, }; const doLoadEnvironment = actualSettings.loadEnvironment === 'loadAndReuse' || actualSettings.loadEnvironment === 'load'; const fetchModules = settings.type === 'host' ? fetch(actualSettings.modulePath, { cache: 'no-cache' }) .then(x => x.json()) .catch(() => { throw new Error('Failed to load modules.json'); }) : Promise.resolve([]); const fetchEnvironment = doLoadEnvironment ? fetch(actualSettings.environmentPath, { cache: 'no-cache' }) .then(x => x.json()) .catch(() => { throw new Error('Failed to load environment.json'); }) : Promise.resolve({}); const [moduleDefs, env] = (await Promise.all([fetchModules, fetchEnvironment])); if (doLoadEnvironment) { _initializeEnvironment(env, actualSettings.loadEnvironment === 'load'); } if (actualSettings.loadEnvironment === 'reuse') { _reuseEnvironment(); } if (settings.type === 'host') { const moduleMap = {}; moduleDefs.modules.forEach(module => { moduleMap[module.name] = module.url; }); await Promise.all(moduleDefs.modules.map(moduleToLoad => loadModule(moduleToLoad, loadRemoteModule, mfOrNf))); if (!environment.production) { console.debug('Loaded modules:', moduleDefs.modules.map(x => x.name), loadedModules); } } }; class ResourceMapPipe { transform(value, moduleName) { if (!moduleName) { throw new Error('The module name is required'); } return resourceMapper(moduleName, value); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ResourceMapPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); } static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.0.3", ngImport: i0, type: ResourceMapPipe, isStandalone: true, name: "resourceMap" }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ResourceMapPipe, decorators: [{ type: Pipe, args: [{ name: 'resourceMap', }] }] }); const findParentOfRouteRecursive = (routes, path, level = 0) => { const value = findParentOfRouteRecursiveImpl(routes, path, level); if (value === true) { return undefined; } return value; }; const findParentOfRouteRecursiveImpl = (routes, path, level = 0) => { for (const route of routes) { if (route.path === path) { if (level === 0) { throw new Error('The entry point cannot be at the root of the routing configuration.' + "You don't need to use this method if you are using the entry point at the root of the routing configuration."); } return true; } if (route.children) { const found = findParentOfRouteRecursiveImpl(route.children, path, level + 1); if (found === true) { return route; } else if (found) { return found; } } } return undefined; }; const isAlreadyInConfig = (existingRoutes, routeConfig) => { if (routeConfig.length === 0) { return true; } for (const route of routeConfig) { const existingRoute = existingRoutes.find(r => r.path === route.path); if (existingRoute) { return isAlreadyInConfig(existingRoute.children || [], route.children || []); } } return false; }; class RouterEntryService { constructor(router) { this._router = router; } registerRoutes(routeConfig, entryPointName = '#module-entry-point#') { const hostRoutes = this._router.config; const outletName = entryPointName; const foundOutlet = findParentOfRouteRecursive(hostRoutes, outletName); if (!foundOutlet) { throw new Error(`Could not find outlet "${outletName}" in router config.`); } const duplicate = isAlreadyInConfig(foundOutlet.children, routeConfig); if (duplicate) { return; } const indexInOutlet = foundOutlet.children?.findIndex(route => route.path === entryPointName) ?? 0; foundOutlet.children = [ ...foundOutlet.children.slice(0, indexInOutlet), ...routeConfig, ...foundOutlet.children.slice(indexInOutlet), ]; this._router.resetConfig(hostRoutes); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: RouterEntryService, deps: [{ token: i1.Router }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: RouterEntryService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: RouterEntryService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: () => [{ type: i1.Router }] }); /** * Generated bundle index. Do not edit. */ export { HtmlHeadService, ResourceMapPipe, RouterEntryService, basePath, basePaths, initializeAppInternal, join, loadModule, loadedModules, normalizePath, resourceMapper }; //# sourceMappingURL=ng-dynamic-mf.mjs.map