- Render widgets on NodeJS, where DOM is absent.
- Optimize rendering of Widgets at scale (1000s of TreeViewNodes).
- Avoid all Node references from Widget through the end of renderUI().
- bindUI()/syncUI() will still have Node references (to bind events and incrementally update DOM).
A boundingBox/contentBox Node instance won't be present for initializer/attr setters/attr getters/HTML_PARSER, so needs to be opt-in.
-
Component Developer can opt-in, if they have a 100% string rendered component (e.g. TreeViewNode)
In this case, get("boundingBox") etc. needs to be documented accordingly for the end user.
-
Environment can opt-in (e.g. NodeJS - conditional loading)
Example:
Y.WidgetStringRenderer = function() {...};
Y.WidgetStringRenderer.prototype = {
// override what needs to be overridden in Y.Widget to support string template based rendering.
}
Y.Foo = Y.Base.create("foo", Y.Widget, [Y.WidgetStringRenderer]);
It'll use Handlebar style templates as opposed to substitute, for forward compatibility.
However we should maybe look into a "handlebars-core" to satisfy the kweight nitpickers. We've been asked to break out less than 3KB chunks before which is where handlebars-base-min.js currently is.
"handlebars-core" could provide basic {{ }} and {{{ }}} support, and also maybe provide substitute compatibility (how to identify single { tokens, from content in a handlebars template?).
We'll need to break up the render()
phase, into the renderUI() portion and the bind/syncUI() portion
render()
renderUI() : No Node references
bindUI() : Node references
syncUI() : Node references
Not sure what the method split should be yet. Options are below, first one is my leading candidate
TreeView use case:
// While iterating 1000s treeview nodes ...
treeviewNode.renderHTML(buffer); // only renderUI() - is it OK that render event is not fired?
// I think so. Nothing is in the DOM yet.
// Once injected into the DOM ...
treeviewNode.render(); // renderUI() [if not invoked before], bindUI(), syncUI()
NodeJS use case:
// On Server
calendar.renderHTML();
// On Client
calendar.render();
Or,
treeviewNode.render();
treeviewNode.bind(); // How about if they want to do it all at once in render(); bind() and Y.bind() confusion
Or,
treeviewNode.renderHTML();
treeviewNode.bind();
Or,
treeviewNode.renderUI() // When do we fire/set render state?
treeviewNode.bindUI()
treeviewNode.syncUI()
Widget will generate node instance from rendered template content for boundingBox, contentBox
Y.TreeViewNode = Y.Base.create("treeViewNode", Y.Widget, [Y.Parent, Y.Child, Y.WidgetStringRenderer]);
// In Parent.render() ...
var buffer = [];
for (i = 0; i < children.length; i++) {
child.renderHTML(buffer);
}
var allChildrenHTML = buffer.join("");
// calendar-nodejs, or maybe just widget-base-nodejs
Y.Calendar = Y.Base.create("calendar", Y.Widget, [Y.WidgetStringRenderer]);
var buffer = []
calendar.renderHTML(buffer);
var calendarHTML = buffer.join("");
We can add sugar in the future (render straight into a template for example). Not enough time for Sprint 1.
calendar.renderHTML(template, token);
Thanks for the feeedback.
Further discussion below...
I personally don't have a k-weight nitpick. We've seen pushback from (the usual) customers in the past, looking to cut a couple of KB here, and a couple there, which was the only thing behind the thought I had. I agree, that it's worth pushing back for the sake of keeping the imported Handlebars pure.
The goal of this extension is to provide a version of Widget's base rendering API which is not Node dependent, either for use on NodeJS, or to help optimize rendering at scale.
I don't see it using any of the current Y.View API, or an explicit Model binding.
We've decided (in prior TreeView design discussions) that there's value in the Parent/Child Widget API as it exists today, for TreeNodes.
Given that decision, there are 2 optimizations which can help with performance.
a) Provide a purely off DOM, string based rendering path for Child Widgets.
b) Apply a flyweight pattern so we're not creating a full blown Widget instance for each TreeNode.
WidgetStringRenderer aims to address a) and b) is still on the table as an option down the road.
If we want to revisit that decision and change TreeNode to be something other than a Widget, then that's a different discussion, which we should reopen separately (and soon, although if it's not Widget based, we'll have Sprint 2 to implement it).