@v4fire/client
Version:
V4Fire client core library
139 lines (108 loc) • 3.48 kB
text/typescript
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
import { identity } from 'core/functools';
import * as c from 'core/component/const';
import { createMeta, fillMeta, attachTemplatesToMeta } from 'core/component/meta';
import { getInfoFromConstructor } from 'core/component/reflection';
import { getComponent, ComponentEngine } from 'core/component/engines';
import { registerParentComponents } from 'core/component/register/helpers';
import type { ComponentOptions } from 'core/component/interface';
/**
* Registers a new component
*
* @decorator
* @param [opts] - additional options
*
* @example
* ```js
* @component()
* class Button {
*
* }
* ```
*/
export function component(opts?: ComponentOptions): Function {
return (target) => {
const
componentInfo = getInfoFromConstructor(target, opts),
componentParams = componentInfo.params;
c.initEmitter
.emit('bindConstructor', componentInfo.name);
if (!Object.isTruly(componentInfo.name) || componentParams.root || componentInfo.isAbstract) {
regComponent();
} else {
const initList = c.componentInitializers[componentInfo.name] ?? [];
c.componentInitializers[componentInfo.name] = initList;
initList.push(regComponent);
}
// If we have a smart component,
// we need to compile 2 components in the runtime
if (Object.isPlainObject(componentParams.functional)) {
component({
...opts,
name: `${componentInfo.name}-functional`,
functional: true
})(target);
}
function regComponent(): void {
// Lazy initializing of parent components
registerParentComponents(componentInfo);
const
{parentMeta} = componentInfo;
const
meta = createMeta(componentInfo),
componentName = componentInfo.name;
if (componentInfo.params.name == null || !componentInfo.isSmart) {
c.components.set(target, meta);
}
c.components.set(componentName, meta);
c.initEmitter.emit(`constructor.${componentName}`, {meta, parentMeta});
if (componentInfo.isAbstract || meta.params.functional === true) {
fillMeta(meta, target);
if (!componentInfo.isAbstract) {
loadTemplate(meta.component)(identity);
}
} else if (meta.params.root) {
c.rootComponents[componentName] = new Promise(loadTemplate(getComponent(meta)));
} else {
const
c = ComponentEngine.component(componentName, loadTemplate(getComponent(meta), true)(identity));
if (Object.isPromise(c)) {
c.catch(stderr);
}
}
// Function that waits till a component template is loaded
function loadTemplate(component: object, lazy: boolean = false): (resolve: Function) => any {
return promiseCb;
function promiseCb(resolve: Function) {
if (meta.params.tpl === false) {
return attachTemplatesAndResolve();
}
return waitComponentTemplates();
function waitComponentTemplates() {
const
fns = TPLS[meta.componentName];
if (fns) {
return attachTemplatesAndResolve(fns);
}
if (lazy) {
return promiseCb;
}
requestIdleCallback(waitComponentTemplates, {timeout: 50});
}
function attachTemplatesAndResolve(tpls?: Dictionary) {
attachTemplatesToMeta(meta, tpls);
// @ts-ignore (access)
component.staticRenderFns = meta.component.staticRenderFns;
return resolve(component);
}
}
}
}
};
}