@j2inn/app
Version:
J2 Innovations core application framework
127 lines (126 loc) • 4.88 kB
JavaScript
/*
* Copyright (c) 2021, J2 Innovations. All Rights Reserved
*/
/* eslint @typescript-eslint/no-explicit-any: "off" */
import { HNamespace } from 'haystack-core';
import { ResourceElement } from './ResourceElement';
/**
* Loads the default exported module from some JS with the defined scope and module.
*
* @param scope The scope of the module to load.
* @param module The name of the module to load.
* @returns The loaded component.
*/
export function loadDefault(scope, module) {
return async () => {
// Initializes the share scope. This fills it with known provided modules
// from this build and all remotes.
await __webpack_init_sharing__('default');
const wnd = window;
const container = wnd[scope]; // or get the container somewhere else.
// Initialize the container, it may provide shared modules
await container.init(__webpack_share_scopes__.default);
const factory = await wnd[scope].get(module);
return factory();
};
}
function isCss(url) {
return url.toLowerCase().endsWith('.css');
}
/**
* Asynchronously load the dynamic resource at runtime and wait for it to load.
*
* @param url The URL to load.
* @returns A promise that's resolved once the resource has loaded.
*/
export async function loadDynamicResource(url, type = ScriptTagType.javascript) {
globalThis.FIN_RESOURCE_PROMISE_CACHE ??= {};
let promise = globalThis.FIN_RESOURCE_PROMISE_CACHE[url];
if (!promise) {
promise = globalThis.FIN_RESOURCE_PROMISE_CACHE[url] =
new Promise((resolve, reject) => {
let element;
if (isCss(url)) {
element = document.createElement('link');
element.href = url;
element.rel = 'stylesheet';
}
else {
element = document.createElement('script');
element.src = url;
element.type = type;
element.async = true;
}
const resource = new ResourceElement(element);
document.head.appendChild(element);
const loadHandler = () => {
resource.removeListeners(loadHandler, loadErrorHandler);
resolve(resource);
};
const loadErrorHandler = () => {
resource.removeListeners(loadHandler, loadErrorHandler);
reject(new Error('Resource loading failed'));
};
resource.addListeners(loadHandler, loadErrorHandler);
});
}
return promise;
}
export async function loadDynamicResources(urls, type = ScriptTagType.javascript) {
return Promise.all(urls.map((url) => loadDynamicResource(url, type)));
}
/**
* Returns the pod name.
*
* @param def The def dict.
* @returns The name of the pod the resource was loaded from.
*/
export function getPodName(def) {
return HNamespace.getFeatureName(def.get('lib') ?? '');
}
/**
* Returns the remote entry point for an app.
*
* @param app The FIN app to get the remote entry point from.
* @param ui The FIN app view to load the remote entry point from.
* @param path The remote path to load. Defaults to `remoteEntry.js`.
* @returns The remote entry point.
*/
export function getRemoteEntry(app, ui, path = 'remoteEntry.js') {
const appName = HNamespace.getFeatureName(app.defName);
// Find the POD file the resource needs to be loaded from.
const podName = HNamespace.getFeatureName((ui ?? app).get('lib') ?? '');
// If the application is running in debug mode then attempt to
// also load the remote entry from the other debug server if
// specified.
return typeof DEBUG === 'boolean' &&
DEBUG &&
typeof DEBUG_REMOTES === 'object' &&
DEBUG_REMOTES[podName]
? `${DEBUG_REMOTES[podName]}/${path}`
: `/api/apps/${appName}/files/${podName}/dist/${path}`;
}
/**
* Returns properties with values that can be rendered nicely as strings.
* All objects and functions are excluded. All keys are made lowercase.
*
* @param props The properties to convert.
* @returns The properties as strings.
*/
export function toStringProps(props) {
return Object.keys(props).reduce((obj, key) => {
const value = props[key];
const type = typeof value;
if (type === 'string' || type === 'boolean' || type === 'number') {
obj[key.toLowerCase()] = String(value);
}
return obj;
}, {});
}
export var ScriptTagType;
(function (ScriptTagType) {
ScriptTagType["module"] = "module";
ScriptTagType["importmap"] = "importmap";
ScriptTagType["javascript"] = "text/javascript";
ScriptTagType["json"] = "application/json";
})(ScriptTagType || (ScriptTagType = {}));