marko
Version:
UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.
232 lines (207 loc) • 7.55 kB
JavaScript
var beginComponent = require("@internal/components-beginComponent");
var endComponent = require("@internal/components-endComponent");
var registry = require("@internal/components-registry");
var componentsUtil = require("@internal/components-util");
var getComponentsContext =
require("../ComponentsContext").___getComponentsContext;
var componentLookup = componentsUtil.___componentLookup;
var modernRenderer = require("../renderer");
var resolveComponentKey = modernRenderer.___resolveComponentKey;
var trackAsyncComponents = modernRenderer.___trackAsyncComponents;
// eslint-disable-next-line no-constant-binary-expression
var complain = "MARKO_DEBUG" && require("complain");
function createRendererFunc(templateRenderFunc, componentProps) {
var typeName = componentProps.t;
//var assignedId = componentProps.id;
var isSplit = componentProps.s === true;
var isImplicit = componentProps.i === true;
return function renderer(input, out, assignedId, renderingLogic) {
trackAsyncComponents(out);
var componentsContext = getComponentsContext(out);
var parentLegacyComponentDef = componentsContext.___legacyComponentDef;
if (isImplicit && parentLegacyComponentDef) {
templateRenderFunc(
input,
out,
parentLegacyComponentDef,
parentLegacyComponentDef.___component,
parentLegacyComponentDef.___component.___rawState,
out.global,
);
return;
}
var widgetBody = input.renderBody;
var widgetState = input.widgetState;
var widgetConfig = input.widgetConfig;
var globalComponentsContext = componentsContext.___globalContext;
var component = globalComponentsContext.___rerenderComponent;
var isRerender = component !== undefined;
var id = assignedId;
var isExisting;
var parentComponentDef = componentsContext.___componentDef;
var ownerComponentDef = out.___assignedComponentDef;
var ownerComponentId = ownerComponentDef && ownerComponentDef.id;
var key = out.___assignedKey;
var customEvents = out.___assignedCustomEvents;
out.___assignedComponentDef = null;
if (component) {
id = component.id;
isExisting = true;
globalComponentsContext.___rerenderComponent = null;
} else {
if (key != null) {
id = id || resolveComponentKey(key.toString(), parentComponentDef);
} else if (parentComponentDef) {
id = parentComponentDef.___nextComponentId();
} else {
id = globalComponentsContext.___nextComponentId();
}
}
if (registry.___isServer && typeName) {
if (renderingLogic) delete renderingLogic.onRender;
component = registry.___createComponent(
renderingLogic,
id,
input,
out,
typeName,
customEvents,
ownerComponentId,
);
if (isSplit || widgetState) {
component.input = null;
} else if (input.widgetProps) {
// eslint-disable-next-line no-constant-condition
if ("MARKO_DEBUG") {
complain(
"Possible performance impact: this widget does not contain state, but is marked as a stateful widget. This will result in additional hydration data serialized. In order for marko to identify this as a split widget, w-bind should use a widget.js with defineWidget rather than index.js with defineComponent.",
{ location: typeName, level: 1 },
);
}
component.input = input.widgetProps;
}
} else {
if (!component) {
if (isRerender) {
// Look in in the DOM to see if a component with the same ID and type already exists.
component = componentLookup[id];
if (component && component.___type !== typeName) {
component = undefined;
}
}
if (component) {
isExisting = true;
} else {
isExisting = false;
// We need to create a new instance of the component
if (typeName) {
component = registry.___createComponent(typeName, id);
}
}
}
}
var isFakeComponent = false;
if (!component) {
isFakeComponent = true;
component = {
id: id,
___keyedElements: {},
};
} else {
component.___updateQueued = true;
if (widgetState) {
component.state = widgetState;
}
}
component.widgetConfig = widgetConfig;
component.___widgetBody = widgetBody || component.___widgetBody;
var componentDef = beginComponent(
componentsContext,
component,
key,
ownerComponentDef,
isSplit,
isFakeComponent,
);
componentsContext.___legacyComponentDef = componentDef;
// This is a hack, but we have to swap out the component instance stored with this node
var vComponentNode = out.___parent;
componentDef.___component = isFakeComponent ? null : component;
componentDef.___isExisting = isExisting;
componentDef.___isLegacy = true;
componentDef.t = function (typeName) {
if (typeName) {
if (registry.___isServer) {
var oldComponent = component;
if (renderingLogic) delete renderingLogic.onRender;
component = registry.___createComponent(
renderingLogic || {},
id,
input,
out,
typeName,
customEvents,
ownerComponentId,
);
if (isSplit || widgetState) {
component.input = null;
} else if (input.widgetProps) {
// eslint-disable-next-line no-constant-condition
if ("MARKO_DEBUG") {
complain(
"Possible performance impact: this widget does not contain state, but is marked as a stateful widget. This will result in additional hydration data serialized. In order for marko to identify this as a split widget, w-bind should use a widget.js with defineWidget rather than index.js with defineComponent.",
{ location: typeName, level: 1 },
);
}
component.input = input.widgetProps;
}
Object.assign(component, oldComponent);
beginComponent(
componentsContext,
component,
key,
ownerComponentDef,
isSplit,
false,
this,
);
} else {
vComponentNode.___component = component = registry.___createComponent(
typeName,
component.id,
);
}
this.___component = component;
}
return component;
};
if (!registry.___isServer) {
component.___legacyRender && component.___legacyRender();
}
// Render the template associated with the component using the final template
// data that we constructed
templateRenderFunc(
input,
out,
componentDef,
component,
component.___rawState,
out.global,
);
if (customEvents && componentDef.___component) {
if (registry.___isServer) {
componentDef.___customEvents = customEvents;
componentDef.___scope = ownerComponentId;
} else {
componentDef.___component.___setCustomEvents(
customEvents,
ownerComponentId,
);
}
}
endComponent(out, componentDef);
componentsContext.___componentDef = parentComponentDef;
componentsContext.___legacyComponentDef = parentLegacyComponentDef;
};
}
module.exports = createRendererFunc;