Code size reductions

This commit is contained in:
Patrick Steele-Idem 2017-02-25 16:00:05 -07:00
parent 9b6a288d83
commit e7a56395e8
29 changed files with 186 additions and 154 deletions

View File

@ -104,15 +104,14 @@ function processUpdateHandlers(component, stateChanges, oldState) {
// Otherwise, there are handlers for all of the changed properties
// so apply the updates using those handlers
for (var i=0, len=handlers.length; i<len; i++) {
var handler = handlers[i];
handlers.forEach(function(handler, i) {
var propertyName = handler[0];
handlerMethod = handler[1];
var newValue = stateChanges[propertyName];
var oldValue = oldState[propertyName];
handlerMethod.call(component, newValue, oldValue);
}
});
emitLifecycleEvent(component, 'update');
@ -259,28 +258,25 @@ Component.prototype = componentProto = {
return;
}
var i, len;
var els = this.els;
this.$__destroyShallow();
var rootComponents = this.$__rootComponents;
if (rootComponents) {
for (i=0, len=rootComponents.length; i<len; i++) {
rootComponents[i].destroy();
}
rootComponents.forEach(function(rootComponent) {
rootComponent.$__destroy();
});
}
for (i=0, len=els.length; i<len; i++) {
var el = els[i];
els.forEach(function(el) {
destroyElRecursive(el);
var parentNode = el.parentNode;
if (parentNode) {
parentNode.removeChild(el);
}
}
});
},
$__destroyShallow: function() {
@ -430,7 +426,7 @@ Component.prototype = componentProto = {
// then we should rerender
if (this.shouldUpdate(input, state) !== false) {
this.doUpdate();
this.$__rerender();
}
}
@ -456,21 +452,17 @@ Component.prototype = componentProto = {
return true;
},
doUpdate: function() {
this.rerender();
},
$__emitLifecycleEvent: function(eventType, eventArg1, eventArg2) {
emitLifecycleEvent(this, eventType, eventArg1, eventArg2);
},
rerender: function(input) {
$__rerender: function(input) {
if (input) {
this.input = input;
}
var self = this;
var renderer = self.renderer;
var renderer = self.$__renderer;
if (!renderer) {
throw TypeError();
@ -604,18 +596,20 @@ Component.prototype = componentProto = {
var finalCustomEvents = this.$__customEvents = {};
this.$__scope = scope;
for (var i=0, len=customEvents.length; i<len; i+=3) {
var eventType = customEvents[i];
var targetMethodName = customEvents[i+1];
var extraArgs = customEvents[i+2];
customEvents.forEach(function(customEvent) {
var eventType = customEvent[0];
var targetMethodName = customEvent[1];
var extraArgs = customEvent[2];
finalCustomEvents[eventType] = [targetMethodName, extraArgs];
}
});
}
}
};
componentProto.elId = componentProto.getElId;
componentProto.$__update = componentProto.update;
componentProto.$__destroy = componentProto.destroy;
// Add all of the following DOM methods to Component.prototype:
// - appendTo(referenceEl)
@ -631,9 +625,9 @@ domInsert(
var elCount = els.length;
if (elCount > 1) {
var fragment = component.$__document.createDocumentFragment();
for (var i=0; i<elCount; i++) {
fragment.appendChild(els[i]);
}
els.forEach(function(el) {
fragment.appendChild(el);
});
return fragment;
} else {
return els[0];

View File

@ -58,13 +58,14 @@ ComponentDef.prototype = {
* (e.g. "myParentId-foo[0]", "myParentId-foo[1]", etc.)
*/
elId: function (nestedId) {
var id = this.id;
if (nestedId == null) {
return this.id;
return id;
} else {
if (typeof nestedId === 'string' && repeatedRegExp.test(nestedId)) {
return nextRepeatedId(this.$__out, this.id, nestedId);
return nextRepeatedId(this.$__out, id, nestedId);
} else {
return this.id + '-' + nestedId;
return id + '-' + nestedId;
}
}
},
@ -77,25 +78,24 @@ ComponentDef.prototype = {
* @param {String} elId The DOM element ID of the DOM element that the event listener needs to be added too
*/
e: function(type, targetMethod, elId, extraArgs) {
if (!targetMethod) {
if (targetMethod) {
// The event handler method is allowed to be conditional. At render time if the target
// method is null then we do not attach any direct event listeners.
return;
(this.$__domEvents || (this.$__domEvents = [])).push([
type,
targetMethod,
elId,
extraArgs]);
}
var domEvents = this.$__domEvents;
this.$__domEvents = (domEvents || (this.$__domEvents = [])).concat([
type,
targetMethod,
elId,
extraArgs]);
},
/**
* Returns the next auto generated unique ID for a nested DOM element or nested DOM component
*/
$__nextId: function() {
return this.id ?
this.id + '-w' + (this.$__nextIdIndex++) :
var id = this.id;
return id ?
id + '-w' + (this.$__nextIdIndex++) :
nextComponentId(this.$__out);
},
@ -126,9 +126,9 @@ ComponentDef.$__deserialize = function(o, types) {
if (state) {
var undefinedPropNames = extra.u;
if (undefinedPropNames) {
for(var i=0; i<undefinedPropNames.length; i++) {
state[undefinedPropNames[i]] = undefined;
}
undefinedPropNames.forEach(function(undefinedPropName) {
state[undefinedPropName] = undefined;
});
}
// We go through the setter here so that we convert the state object
// to an instance of `State`

View File

@ -44,7 +44,7 @@ module.exports = function defineComponent(def, renderer) {
proto.onCreate = proto.onCreate || ComponentClass;
proto.constructor = def.constructor = Component;
// proto.constructor = def.constructor = Component;
// Set a flag on the constructor function to make it clear this is
// a component so that we can short-circuit this work later
@ -53,7 +53,7 @@ module.exports = function defineComponent(def, renderer) {
function State() { BaseState.apply(this, arguments); }
inherit(State, BaseState);
proto.$__State = State;
proto.renderer = renderer;
proto.$__renderer = renderer;
return Component;
};

View File

@ -7,7 +7,7 @@ function getEventAttribute(el, attrName) {
var virtualAttrs = el._vattrs;
if (virtualAttrs) {
return el._vattrs[attrName];
return virtualAttrs[attrName];
} else {
var attrValue = el.getAttribute(attrName);
if (attrValue) {
@ -29,7 +29,6 @@ function delegateEvent(node, target, event) {
var targetComponent = componentLookup[targetComponentId];
if (!targetComponent) {
return;
}

View File

@ -52,11 +52,6 @@ function initComponent(componentDef, doc) {
component.$__document = doc;
var isExisting = componentDef.$__isExisting;
var i;
var len;
var eventType;
var targetMethodName;
var extraArgs;
var id = component.id;
var rootIds = componentDef.$__roots;
@ -65,8 +60,8 @@ function initComponent(componentDef, doc) {
var rootComponents;
var els = [];
for (i=0, len=rootIds.length; i<len; i++) {
var rootId = rootIds[i];
rootIds.forEach(function(rootId) {
var nestedId = id + '-' + rootId;
var rootComponent = componentLookup[nestedId];
if (rootComponent) {
@ -83,7 +78,7 @@ function initComponent(componentDef, doc) {
els.push(rootEl);
}
}
}
});
component.el = els[0];
component.els = els;
@ -103,15 +98,16 @@ function initComponent(componentDef, doc) {
if (domEvents) {
var eventListenerHandles = [];
for (i=0, len=domEvents.length; i<len; i+=4) {
eventType = domEvents[i];
targetMethodName = domEvents[i+1];
var eventEl = getElementById(doc, domEvents[i+2]);
extraArgs = domEvents[i+3];
domEvents.forEach(function(domEventArgs) {
// The event mapping is for a direct DOM event (not a custom event and not for bubblign dom events)
var eventType = domEventArgs[0];
var targetMethodName = domEventArgs[1];
var eventEl = getElementById(doc, domEventArgs[2]);
var extraArgs = domEventArgs[3];
// The event mapping is for a DOM event (not a custom event)
addDOMEventListeners(component, eventEl, eventType, targetMethodName, extraArgs, eventListenerHandles);
}
});
if (eventListenerHandles.length) {
component.$__domEventListenerHandles = eventListenerHandles;
@ -158,18 +154,17 @@ function initClientRendered(componentDefs, doc) {
* of the component IDs.
*/
function initServerRendered(renderedComponents, doc) {
var i=0, len;
if (!arguments.length) {
if (!renderedComponents) {
renderedComponents = win.$components;
win.$components = {
concat: initServerRendered
};
if (renderedComponents && (len=renderedComponents.length)) {
for (; i<len; i++) {
initServerRendered(renderedComponents[i], doc);
}
if (renderedComponents) {
renderedComponents.forEach(function(renderedComponent) {
initServerRendered(renderedComponent, doc);
});
}
return;
}
@ -182,14 +177,10 @@ function initServerRendered(renderedComponents, doc) {
var componentDefs = renderedComponents.w;
var typesArray = renderedComponents.t;
if (!doc) {
doc = defaultDocument;
}
for (len=componentDefs.length; i<len; i++) {
var componentDef = ComponentDef.$__deserialize(componentDefs[i], typesArray);
initComponent(componentDef, doc);
}
componentDefs.forEach(function(componentDef) {
componentDef = ComponentDef.$__deserialize(componentDef, typesArray);
initComponent(componentDef, doc || defaultDocument);
});
}
exports.$__initClientRendered = initClientRendered;

View File

@ -137,7 +137,7 @@ module.exports = function defineWidget(def, renderer) {
if (renderer) {
// Add the rendering related methods as statics on the
// new component constructor function
Component.renderer = proto.renderer = renderer;
Component.renderer = proto.$__renderer = renderer;
Component.render = renderer.render;
Component.renderSync = renderer.renderSync;
}

View File

@ -25,6 +25,14 @@ exports.initWidgets = modern.init;
if (Widget) {
var WidgetProto = Widget.prototype;
WidgetProto.setProps = WidgetProto.$__setInput;
WidgetProto.rerender = function(newInput) {
if (newInput) {
this.input = newInput;
}
this.forceUpdate();
this.update();
};
}
var RenderResult = require('../../runtime/RenderResult');

View File

@ -6,12 +6,10 @@ var loaded = {};
var componentTypes = {};
function register(typeName, def) {
if (typeof def === 'function') {
// We do this to kick off registering of nested components
// but we don't use the return value just yet since there
// is a good chance that it resulted in a circular dependency
def();
}
// We do this to kick off registering of nested components
// but we don't use the return value just yet since there
// is a good chance that it resulted in a circular dependency
def();
registered[typeName] = def;
delete loaded[typeName];
@ -21,21 +19,22 @@ function register(typeName, def) {
function load(typeName) {
var target = loaded[typeName];
if (target === undefined) {
if (!target) {
target = registered[typeName];
if (typeof target === 'function') {
if (target) {
target = target();
}
if (!target) {
} else {
target = loadComponent(typeName); // Assume the typeName has been fully resolved already
}
loaded[typeName] = target || null;
if (!target) {
throw Error('Not found: ' + typeName);
}
loaded[typeName] = target;
}
if (target == null) {
throw new Error('Unable to load: ' + typeName);
}
return target;
}
@ -48,9 +47,7 @@ function getComponentClass(typeName) {
ComponentClass = load(typeName);
if (ComponentClass.Component) {
ComponentClass = ComponentClass.Component;
}
ComponentClass = ComponentClass.Component || ComponentClass;
if (!ComponentClass.$__isComponent) {
ComponentClass = defineComponent(ComponentClass, ComponentClass.renderer);
@ -66,14 +63,7 @@ function getComponentClass(typeName) {
function createComponent(typeName, id) {
var ComponentClass = getComponentClass(typeName);
var component;
if (typeof ComponentClass === 'function') {
// The component is a constructor function that we can invoke to create a new instance of the component
component = new ComponentClass(id);
} else if (ComponentClass.initComponent) {
component = ComponentClass;
}
return component;
return new ComponentClass(id);
}
exports.$__register = register;

View File

@ -10,7 +10,7 @@ var extend = require('raptor-util/extend');
var WIDGETS_BEGIN_ASYNC_ADDED_KEY = '$wa';
function resolveComponentKey(out, key, scope) {
if (key.charAt(0) === '#') {
if (key.charAt(0) == '#') {
return key.substring(1);
} else {
var resolvedId;

View File

@ -24,9 +24,7 @@ class ComponentArgs {
this.customEvents = [];
}
this.customEvents.push(eventType);
this.customEvents.push(targetMethod);
this.customEvents.push(extraArgs);
this.customEvents.push([eventType, targetMethod, extraArgs]);
}
compile(transformHelper) {

View File

@ -66,7 +66,7 @@ function updateComponents(queue) {
// since we will still get to them at the end
for (var i=0; i<queue.length; i++) {
var component = queue[i];
component.update(); // Do the actual component update
component.$__update(); // Do the actual component update
}
// Clear out the queue by setting the length to zero

View File

@ -93,9 +93,11 @@ function getElementById(doc, id) {
function attachBubblingEvent(componentDef, handlerMethodName, extraArgs) {
if (handlerMethodName) {
var id = componentDef.id;
return extraArgs ?
[handlerMethodName, componentDef.id, extraArgs] :
[handlerMethodName, componentDef.id];
[handlerMethodName, id, extraArgs] :
[handlerMethodName, id];
}
}

View File

@ -145,6 +145,7 @@
"ca",
"d",
"e",
"id",
"n",
"r",
"sa",

View File

@ -1,11 +1,6 @@
var domInsert = require('./dom-insert');
var EMPTY_ARRAY = [];
function checkAddedToDOM(result, method) {
if (!result.$__components) {
throw Error('Not added to DOM');
}
}
function getComponentDefs(result) {
var componentDefs = result.$__components;
@ -25,30 +20,23 @@ module.exports = RenderResult;
var proto = RenderResult.prototype = {
getComponent: function() {
checkAddedToDOM(this, 'getComponent');
var rerenderComponentInfo = this.$__out.global.$w;
var rerenderComponent = rerenderComponentInfo && rerenderComponentInfo[0];
if (rerenderComponent) {
return rerenderComponent;
}
return getComponentDefs(this)[0].$__component;
return this.getComponents()[0];
},
getComponents: function(selector) {
checkAddedToDOM(this, 'getComponents');
if (!this.$__components) {
throw Error('Not added to DOM');
}
var componentDefs = getComponentDefs(this);
var components = [];
var i;
for (i = 0; i < componentDefs.length; i++) {
var component = componentDefs[i].$__component;
componentDefs.forEach(function(componentDef) {
var component = componentDef.$__component;
if (!selector || selector(component)) {
components.push(component);
}
}
});
return components;
},
@ -74,9 +62,6 @@ var proto = RenderResult.prototype = {
toString: function() {
return this.$__out.toString();
},
toJSON: function() {
return this.$__out.$__getOutput();
},
document: typeof document !== 'undefined' && document
};

View File

@ -4,7 +4,7 @@ var destroyComponentForEl = componentsUtil.$__destroyComponentForEl;
var destroyElRecursive = componentsUtil.$__destroyElRecursive;
function resolveEl(el) {
if (typeof el === 'string') {
if (typeof el == 'string') {
var elId = el;
el = document.getElementById(elId);
if (!el) {
@ -47,7 +47,7 @@ module.exports = function(target, getEl, afterInsert) {
var curChild = referenceEl.firstChild;
while(curChild) {
var nextSibling = curChild.nextSibling; // Just in case the DOM changes while removing
if (curChild.nodeType === 1) {
if (curChild.nodeType == 1) {
beforeRemove(curChild);
}
curChild = nextSibling;

View File

@ -91,7 +91,7 @@ module.exports = function(target, renderer) {
finalOut = out;
shouldEnd = false;
extend(out.global, globalData);
} else if (typeof out === 'function') {
} else if (typeof out == 'function') {
finalOut = createOut(globalData);
callback = out;
} else {

View File

@ -12,7 +12,8 @@ module.exports = function(helpers) {
expect(component.getEl).to.be.a('function');
expect(component.destroy).to.be.a('function');
expect(component.isDestroyed).to.be.a('function');
expect(component.rerender).to.be.a('function');
expect(component.update).to.be.a('function');
expect(component.forceUpdate).to.be.a('function');
expect(component.appendTo).to.be.a('function');
expect(component.replace).to.be.a('function');
expect(component.replaceChildrenOf).to.be.a('function');

View File

@ -0,0 +1,13 @@
class {
emitTestEvent1() {
this.emit('testEvent1');
}
emitTestEvent2() {
this.emit('testEvent2');
}
};
<div class="bar">
[app-bar]
</div>

View File

@ -0,0 +1,24 @@
import { expect } from 'chai';
class {
constructor() {
this.testEvent1Fired = false;
this.testEvent2Fired = false;
}
handleTestEvent1(arg1, arg2) {
expect(arg1).to.equal('a');
expect(arg2).to.equal('b');
this.testEvent1Fired = true;
}
handleTestEvent2(arg1, arg2) {
expect(arg1).to.equal('c');
expect(arg2).to.equal('d');
this.testEvent2Fired = true;
}
}
<div>
<app-bar key="bar" on-testEvent1('handleTestEvent1', 'a', 'b') on-testEvent2('handleTestEvent2', 'c', 'd')/>
</div>

View File

@ -0,0 +1,15 @@
var expect = require('chai').expect;
module.exports = function(helpers) {
var component = helpers.mount(require('./index'), {});
component.getComponent('bar').emitTestEvent1();
expect(component.testEvent1Fired).to.equal(true);
component.getComponent('bar').emitTestEvent2();
expect(component.testEvent2Fired).to.equal(true);
};

View File

@ -12,9 +12,10 @@ module.exports = function(helpers) {
expect(component.el.querySelector('.preserve').getAttribute('data-counter')).to.equal('0');
expect(component.el.querySelector('.preserved-counter').innerHTML).to.equal('0');
component.rerender({
component.input ={
counter: ++counter
});
};
component.update();
expect(component.el.querySelector('.unpreserved-counter').innerHTML).to.equal('1');
expect(component.el.querySelector('.preserve').getAttribute('data-counter')).to.equal('1');

View File

@ -12,9 +12,11 @@ module.exports = function(helpers) {
expect(component.getEl('preserve').getAttribute('data-counter')).to.equal('0');
expect(component.el.querySelector('.preserved-counter').innerHTML).to.equal('0');
component.rerender({
component.input = {
counter: ++counter
});
};
component.update();
expect(component.el.querySelector('.unpreserved-counter').innerHTML).to.equal('1');
expect(component.getEl('preserve').getAttribute('data-counter')).to.equal('1');

View File

@ -12,9 +12,10 @@ module.exports = function(helpers) {
expect(component.el.querySelector('.preserve').getAttribute('data-counter')).to.equal('0');
expect(component.el.querySelector('.preserved-counter').innerHTML).to.equal('0');
component.rerender({
component.input ={
counter: ++counter
});
};
component.update();
expect(component.el.querySelector('.unpreserved-counter').innerHTML).to.equal('1');
expect(component.el.querySelector('.preserve').getAttribute('data-counter')).to.equal('0');

View File

@ -12,9 +12,10 @@ module.exports = function(helpers) {
expect(component.getEl('preserve').getAttribute('data-counter')).to.equal('0');
expect(component.el.querySelector('.preserved-counter').innerHTML).to.equal('0');
component.rerender({
component.input ={
counter: ++counter
});
};
component.update();
expect(component.el.querySelector('.unpreserved-counter').innerHTML).to.equal('1');
expect(component.getEl('preserve').getAttribute('data-counter')).to.equal('0');

View File

@ -7,9 +7,10 @@ module.exports = function(helpers) {
var oldId = component.id;
component.rerender({
component.input = {
label: 'Bar'
});
};
component.update();
expect(component.el.id).to.equal(oldId);
};

View File

@ -9,7 +9,8 @@ module.exports = function(helpers) {
expect(buttonComponent.el.innerHTML).to.contain('Frank');
expect(buttonComponent.el.className).to.equal('app-button app-button-small');
component.rerender({ name: 'John '});
component.input = { name: 'John '};
component.update();
expect(buttonComponent.el.innerHTML).to.contain('John');
@ -18,11 +19,12 @@ module.exports = function(helpers) {
expect(buttonComponent.el.innerHTML).to.contain('John');
expect(buttonComponent.el.className).to.equal('app-button app-button-large');
buttonComponent.rerender({
buttonComponent.input = {
size: 'small',
variant: 'secondary'
// NOTE: We aren't including renderBody() but we expect that content to be preserved
});
};
buttonComponent.update();
expect(buttonComponent.el.innerHTML).to.contain('John');
expect(buttonComponent.el.className).to.equal('app-button app-button-secondary app-button-small');

View File

@ -21,10 +21,11 @@ module.exports = function(helpers) {
var renderId = 10;
component.rerender({
component.input = {
preserveCondition: true,
renderId: renderId
});
};
component.update();
var timestamps = getTimestamps();
expect(timestamps.preserveId).to.equal('0');
@ -58,10 +59,11 @@ module.exports = function(helpers) {
renderId = 100;
// Do not preserve
component.rerender({
component.input = {
preserveCondition: false,
renderId: renderId
});
};
component.update();
timestamps = getTimestamps();
expect(timestamps.preserveId).to.equal('100');

View File

@ -3,7 +3,8 @@ module.exports = function(helpers) {
var oldChildren = helpers.nodeListToArray(component.el.childNodes);
component.rerender();
component.forceUpdate();
component.update();
var newChildren = component.el.childNodes;
helpers.checkChildrenMatch(oldChildren, newChildren);

View File

@ -15,7 +15,7 @@ module.exports = function(helpers) {
var self = component;
self.setButtonSize('small');
self.rerender();
self.update();
var newButton1El = component.getComponent('button1').el;
var newButton2El = component.getEl('button2');