Skip to content

Commit

Permalink
perf: misc improvements (#1535)
Browse files Browse the repository at this point in the history
* perf: attr & escape helper optimization

* perf: optimize server component

* perf: dynamic tag perf improvements

* perf: prevent escaping json attrs, optimize nonce

* perf: legacy widget & dynamic tag key serialization improvement

* perf: prevent serializing component props for legacy components

* fix: auto key regexp for dynamic tag

* perf: prevent creating constructors for implicit components
  • Loading branch information
DylanPiercey committed Mar 30, 2020
1 parent d3850f1 commit ff82248
Show file tree
Hide file tree
Showing 22 changed files with 253 additions and 225 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use strict";

var attr = require("../../../../runtime/html/helpers/attr");
var escapeXmlAttr = require("../../../../runtime/html/helpers/escape-xml").d;
var escapeDoubleQuotes = require("../../../../runtime/html/helpers/escape-xml")
.d;

function isStringLiteral(node) {
return node.type === "Literal" && typeof node.value === "string";
Expand Down Expand Up @@ -75,7 +76,7 @@ function generateCodeForExpressionAttr(name, value, escape, codegen) {
for (let i = 0; i < flattenedConcats.length; i++) {
var part = flattenedConcats[i];
if (isStringLiteral(part)) {
part.value = escapeXmlAttr(part.value);
part.value = escapeDoubleQuotes(part.value);
} else if (part.type !== "Literal") {
if (isNoEscapeXml(part)) {
part = codegen.builder.functionCall(context.helper("str"), [part]);
Expand Down
1 change: 0 additions & 1 deletion packages/marko/src/runtime/components/Component.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ function Component(id) {
this.___dirty = false;
this.___settingInput = false;
this.___document = undefined;
this.___keySequence = undefined;

var ssrKeyedElements = keyedElementsByComponentId[id];

Expand Down
14 changes: 9 additions & 5 deletions packages/marko/src/runtime/components/ComponentDef.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,14 @@ function ComponentDef(component, componentId, componentsContext) {
this.___flags = 0;

this.___nextIdIndex = 0; // The unique integer to use for the next scoped ID

this.___keySequence = null;
}

ComponentDef.prototype = {
___nextKey: function(key) {
var keySequence =
this.___keySequence || (this.___keySequence = new KeySequence());
return keySequence.___nextKey(key);
return (
this.___keySequence || (this.___keySequence = new KeySequence())
).___nextKey(key);
},

/**
Expand Down Expand Up @@ -90,7 +89,7 @@ ComponentDef.prototype.nk = ComponentDef.prototype.___nextKey;
ComponentDef.___deserialize = function(o, types, global, registry) {
var id = o[0];
var typeName = types[o[1]];
var input = o[2];
var input = o[2] || null;
var extra = o[3];

var isLegacy = extra.l;
Expand Down Expand Up @@ -133,6 +132,11 @@ ComponentDef.___deserialize = function(o, types, global, registry) {
if (componentProps) {
extend(component, componentProps);
}

if (isLegacy) {
component.widgetConfig = extra.c;
component.___legacyBody = extra.a;
}
}

component.___input = input;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
var nextComponentIdProvider = require("./util").___nextComponentIdProvider;
var KeySequence = require("./KeySequence");

function GlobalComponentsContext(out) {
this.___renderedComponentsById = {};
this.___rerenderComponent = undefined;
this.___nextComponentId = nextComponentIdProvider(out);
}

GlobalComponentsContext.prototype = {
___createKeySequence: function() {
return new KeySequence();
}
};

module.exports = GlobalComponentsContext;
25 changes: 8 additions & 17 deletions packages/marko/src/runtime/components/KeySequence.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
function KeySequence() {
this.___lookup = {};
this.___lookup = Object.create(null);
}

KeySequence.prototype = {
___nextKey: function(key) {
// var len = key.length;
// var lastChar = key[len-1];
// if (lastChar === ']') {
// key = key.substring(0, len-2);
// }
var lookup = this.___lookup;
KeySequence.prototype.___nextKey = function(key) {
var lookup = this.___lookup;

var currentIndex = lookup[key]++;
if (!currentIndex) {
lookup[key] = 1;
currentIndex = 0;
return key;
} else {
return key + "_" + currentIndex;
}
if (lookup[key]) {
return key + "_" + lookup[key]++;
}

lookup[key] = 1;
return key;
};

module.exports = KeySequence;
30 changes: 9 additions & 21 deletions packages/marko/src/runtime/components/ServerComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,16 @@ class ServerComponent {
this.id = id;
this.___customEvents = customEvents;
this.___scope = scope;
this.___updatedInput = undefined;
this.___input = undefined;
this.___state = undefined;
this.typeName = typeName;
this.___bubblingDomEvents = undefined; // Used to keep track of bubbling DOM events for components rendered on the server
this.___bubblingDomEventsExtraArgsCount = 0;

if (this.onCreate !== undefined) {
this.onCreate(input, out);
}

if (this.onInput !== undefined) {
var updatedInput = this.onInput(input, out) || input;

if (this.___input === undefined) {
this.___input = updatedInput;
}

this.___updatedInput = updatedInput;
} else {
this.___input = this.___updatedInput = input;
}

if (this.onRender !== undefined) {
this.onRender(out);
this.onCreate(input, out);
this.___updatedInput = this.onInput(input, out) || input;
if (this.___input === undefined) {
this.___input = this.___updatedInput;
}
this.onRender(out);
}

set input(newInput) {
Expand Down Expand Up @@ -77,6 +61,10 @@ class ServerComponent {
return id + "-" + nestedId;
}
}

onCreate() {}
onInput() {}
onRender() {}
}

ServerComponent.prototype.getElId = ServerComponent.prototype.elId;
Expand Down
16 changes: 1 addition & 15 deletions packages/marko/src/runtime/components/dom-data.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
var counter = 0;
var seed = "M" + Math.random().toFixed(5);
var WeakMap =
global.WeakMap ||
function WeakMap() {
var id = seed + counter++;
return {
get: function(ref) {
return ref[id];
},
set: function(ref, value) {
ref[id] = value;
}
};
};
var WeakMap = require("../helpers/_weak-map");

module.exports = {
___vPropsByDOMNode: new WeakMap(),
Expand Down
67 changes: 35 additions & 32 deletions packages/marko/src/runtime/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,38 +25,37 @@ function addComponentsFromContext(componentsContext, componentsToHydrate) {
var id = componentDef.id;
var component = componentDef.___component;
var flags = componentDef.___flags;
var isLegacy = componentDef.___isLegacy;

var state = component.state;
var input = component.input;
var input = component.input || 0;
var typeName = component.typeName;
var customEvents = component.___customEvents;
var scope = component.___scope;
var bubblingDomEvents = component.___bubblingDomEvents;

component.___state = undefined; // We don't use `delete` to avoid V8 deoptimization
component.___input = undefined; // We don't use `delete` to avoid V8 deoptimization
component.typeName = undefined;
component.id = undefined;
component.___customEvents = undefined;
component.___scope = undefined;
component.___bubblingDomEvents = undefined;
component.___bubblingDomEventsExtraArgsCount = undefined;
component.___updatedInput = undefined;
component.___updateQueued = undefined;

if (!typeName) {
continue;
}

var hasProps = false;

let componentKeys = Object.keys(component);
for (let i = 0, len = componentKeys.length; i < len; i++) {
let key = componentKeys[i];

if (component[key] !== undefined) {
hasProps = true;
break;
if (!isLegacy) {
component.___state = undefined; // We don't use `delete` to avoid V8 deoptimization
component.___input = undefined; // We don't use `delete` to avoid V8 deoptimization
component.typeName = undefined;
component.id = undefined;
component.___customEvents = undefined;
component.___scope = undefined;
component.___bubblingDomEvents = undefined;
component.___bubblingDomEventsExtraArgsCount = undefined;
component.___updatedInput = undefined;
component.___updateQueued = undefined;

const componentKeys = Object.keys(component);
for (let i = componentKeys.length; i--; ) {
const componentKey = componentKeys[i];

if (component[componentKey] !== undefined) {
hasProps = true;
break;
}
}
}

Expand All @@ -66,16 +65,15 @@ function addComponentsFromContext(componentsContext, componentsToHydrate) {
// Update state properties with an `undefined` value to have a `null`
// value so that the property name will be serialized down to the browser.
// This ensures that we add the proper getter/setter for the state property.
const stateKeys = Object.keys(state);
for (let i = stateKeys.length; i--; ) {
const stateKey = stateKeys[i];

let stateKeys = Object.keys(state);
for (let i = 0, len = stateKeys.length; i < len; i++) {
let key = stateKeys[i];

if (state[key] === undefined) {
if (state[stateKey] === undefined) {
if (undefinedPropNames) {
undefinedPropNames.push(key);
undefinedPropNames.push(stateKey);
} else {
undefinedPropNames = [key];
undefinedPropNames = [stateKey];
}
}
}
Expand All @@ -86,14 +84,19 @@ function addComponentsFromContext(componentsContext, componentsToHydrate) {
d: componentDef.___domEvents,
e: customEvents,
f: flags ? flags : undefined,
l: componentDef.___isLegacy,
p: customEvents && scope, // Only serialize scope if we need to attach custom events
r: componentDef.___boundary,
r: componentDef.___boundary && 1,
s: state,
u: undefinedPropNames,
w: hasProps ? component : undefined
};

if (isLegacy) {
extra.l = 1;
extra.c = component.widgetConfig;
extra.a = component.___legacyBody;
}

componentsToHydrate.push([
id, // 0 = id
typeName, // 1 = type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function createRendererFunc(templateRenderFunc, componentProps) {
if (registry.___isServer && typeName) {
if (renderingLogic) delete renderingLogic.onRender;
component = registry.___createComponent(
renderingLogic || {},
renderingLogic,
id,
input,
out,
Expand Down
28 changes: 13 additions & 15 deletions packages/marko/src/runtime/components/registry.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
const copyProps = require("raptor-util/copyProps");
const SERVER_WIDGET_KEY = Symbol();
const constructorCache = new Map();
const BaseServerComponent = require("./ServerComponent");

function createServerComponentClass(renderingLogic) {
Expand All @@ -24,22 +24,20 @@ function createComponent(
customEvents,
scope
) {
var ServerComponent = renderingLogic[SERVER_WIDGET_KEY];
if (!ServerComponent) {
ServerComponent = renderingLogic[
SERVER_WIDGET_KEY
] = createServerComponentClass(renderingLogic);
let ServerComponent;

if (renderingLogic) {
ServerComponent = constructorCache.get(renderingLogic);

if (!ServerComponent) {
ServerComponent = createServerComponentClass(renderingLogic);
constructorCache.set(renderingLogic, ServerComponent);
}
} else {
ServerComponent = BaseServerComponent;
}

var component = new ServerComponent(
id,
input,
out,
typeName,
customEvents,
scope
);
return component;
return new ServerComponent(id, input, out, typeName, customEvents, scope);
}

exports.___isServer = true;
Expand Down
5 changes: 2 additions & 3 deletions packages/marko/src/runtime/components/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,12 @@ function createRendererFunc(
componentProps,
renderingLogic
) {
renderingLogic = renderingLogic || {};
var onInput = renderingLogic.onInput;
var onInput = renderingLogic && renderingLogic.onInput;
var typeName = componentProps.___type;
var isSplit = componentProps.___split === true;
var isImplicitComponent = componentProps.___implicit === true;

var shouldApplySplitMixins = isSplit;
var shouldApplySplitMixins = renderingLogic && isSplit;

return function renderer(input, out) {
trackAsyncComponents(out);
Expand Down
15 changes: 15 additions & 0 deletions packages/marko/src/runtime/helpers/_weak-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var counter = 0;
var seed = "M" + Math.random().toFixed(5);
module.exports =
global.WeakMap ||
function WeakMap() {
var id = seed + counter++;
return {
get: function(ref) {
return ref[id];
},
set: function(ref, value) {
ref[id] = value;
}
};
};

0 comments on commit ff82248

Please sign in to comment.