ng-dynamic-mf
Version:
[](https://www.npmjs.com/package/ng-dynamic-mf) [ • 10.5 kB
JavaScript
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