feat: move non-serialized internal values out of scope array and into props

This commit is contained in:
Michael Rawlings 2021-11-08 12:23:42 -08:00
parent d2e723b5df
commit 0bda22cd98
No known key found for this signature in database
GPG Key ID: B9088328804D407C
11 changed files with 74 additions and 88 deletions

View File

@ -6,9 +6,9 @@
{
"name": "*",
"individual": {
"min": 11962,
"gzip": 5140,
"brotli": 4628
"min": 11615,
"gzip": 5073,
"brotli": 4574
}
}
]

View File

@ -1,5 +1,5 @@
# Write
<!M^ROOT><body><!M#6 ROOT 6><button><!M#1 ROOT 7>0</button></body><!M/ROOT><script>(M$h=[]).push((b,s)=>({ROOT:["ROOT",,,,,,,,0]}),["counter",6,"ROOT",])</script>
<!M^ROOT><body><!M#2 ROOT 2><button><!M#1 ROOT 3>0</button></body><!M/ROOT><script>(M$h=[]).push((b,s)=>({ROOT:[,,,,0]}),["counter",2,"ROOT",])</script>
# Render "End"
@ -8,13 +8,13 @@
<html>
<head />
<body>
<!--M#6 ROOT 6-->
<!--M#2 ROOT 2-->
<button>
<!--M#1 ROOT 7-->
<!--M#1 ROOT 3-->
0
</button>
<script>
(M$h=[]).push((b,s)=&gt;({ROOT:["ROOT",,,,,,,,0]}),["counter",6,"ROOT",])
(M$h=[]).push((b,s)=&gt;({ROOT:[,,,,0]}),["counter",2,"ROOT",])
</script>
</body>
<!--M/ROOT-->
@ -43,13 +43,13 @@ inserted #document/html1/body1/script2/#text0
<html>
<head />
<body>
<!--M#6 ROOT 6-->
<!--M#2 ROOT 2-->
<button>
<!--M#1 ROOT 7-->
<!--M#1 ROOT 3-->
0
</button>
<script>
(M$h=[]).push((b,s)=&gt;({ROOT:["ROOT",,,,,,,,0]}),["counter",6,"ROOT",])
(M$h=[]).push((b,s)=&gt;({ROOT:[,,,,0]}),["counter",2,"ROOT",])
</script>
</body>
<!--M/ROOT-->
@ -70,13 +70,13 @@ container.querySelector("button").click();
<html>
<head />
<body>
<!--M#6 ROOT 6-->
<!--M#2 ROOT 2-->
<button>
<!--M#1 ROOT 7-->
<!--M#1 ROOT 3-->
1
</button>
<script>
(M$h=[]).push((b,s)=&gt;({ROOT:["ROOT",,,,,,,,0]}),["counter",6,"ROOT",])
(M$h=[]).push((b,s)=&gt;({ROOT:[,,,,0]}),["counter",2,"ROOT",])
</script>
</body>
<!--M/ROOT-->
@ -97,13 +97,13 @@ container.querySelector("button").click();
<html>
<head />
<body>
<!--M#6 ROOT 6-->
<!--M#2 ROOT 2-->
<button>
<!--M#1 ROOT 7-->
<!--M#1 ROOT 3-->
2
</button>
<script>
(M$h=[]).push((b,s)=&gt;({ROOT:["ROOT",,,,,,,,0]}),["counter",6,"ROOT",])
(M$h=[]).push((b,s)=&gt;({ROOT:[,,,,0]}),["counter",2,"ROOT",])
</script>
</body>
<!--M/ROOT-->
@ -124,13 +124,13 @@ container.querySelector("button").click();
<html>
<head />
<body>
<!--M#6 ROOT 6-->
<!--M#2 ROOT 2-->
<button>
<!--M#1 ROOT 7-->
<!--M#1 ROOT 3-->
3
</button>
<script>
(M$h=[]).push((b,s)=&gt;({ROOT:["ROOT",,,,,,,,0]}),["counter",6,"ROOT",])
(M$h=[]).push((b,s)=&gt;({ROOT:[,,,,0]}),["counter",2,"ROOT",])
</script>
</body>
<!--M/ROOT-->

View File

@ -6,7 +6,6 @@ export default (
currentScope: Scope,
currentOffset: number
) => {
currentScope[0] = "ROOT";
write("<body>");
counter(_input, currentScope, currentOffset);
write("</body>");
@ -27,5 +26,5 @@ const counter = (
)}${count}</button>`
);
writeScope(currentScope);
writeCall("counter", currentOffset, currentScope[0]);
writeCall("counter", currentOffset, currentScope.___id);
};

View File

@ -9,14 +9,15 @@ export type HydrateInstance = [
];
export type Scope = [
string, // ID
Node | number | undefined, // START_NODE
Node | number | undefined, // END_NODE
Set<number | Scope> | undefined, // CLEANUP
Scope | undefined, // OWNER_SCOPE
number | undefined, // OWNER_OFFSET
...unknown[]
] & {
___id: string;
___startNode: Node | number | undefined;
___endNode: Node | number | undefined;
___cleanup: Set<number | Scope> | undefined;
} & {
___insertBefore: (
this: Scope,
parent: Node & ParentNode,
@ -30,13 +31,9 @@ export type Scope = [
};
export const enum ScopeOffsets {
ID = 0,
START_NODE = 1,
END_NODE = 2,
CLEANUP = 3,
OWNER_SCOPE = 4,
OWNER_OFFSET = 5,
BEGIN_DATA = 6,
OWNER_SCOPE = 0,
OWNER_OFFSET = 1,
BEGIN_DATA = 2,
}
export const enum HydrateSymbols {

View File

@ -46,7 +46,7 @@ export function queueInBranch(
export function getConditionalFirstNode(
this: Scope,
conditionalIndex: number = this[ScopeOffsets.START_NODE] as number,
conditionalIndex: number = this.___startNode as number,
last?: boolean
) {
const scope = this[
@ -62,11 +62,7 @@ export function getConditionalFirstNode(
}
export function getConditionalLastNode(this: Scope) {
return getConditionalFirstNode.call(
this,
this[ScopeOffsets.END_NODE] as number,
true
);
return getConditionalFirstNode.call(this, this.___endNode as number, true);
}
export function setConditionalRenderer(
@ -179,7 +175,7 @@ export function queueForEach(
export function getLoopFirstNode(
this: Scope,
loopIndex: number = this[ScopeOffsets.START_NODE] as number,
loopIndex: number = this.___startNode as number,
last?: boolean
) {
const scopes = this[
@ -195,11 +191,7 @@ export function getLoopFirstNode(
}
export function getLoopLastNode(this: Scope) {
return getLoopFirstNode.call(
this,
this[ScopeOffsets.END_NODE] as number,
true
);
return getLoopFirstNode.call(this, this.___endNode as number, true);
}
export function setLoopOf<T>(

View File

@ -1,5 +1,5 @@
import type { Renderer } from "./renderer";
import { Scope, ScopeOffsets } from "../common/types";
import { Scope } from "../common/types";
import { onDestroy, read, write } from "./scope";
import { withQueueNext } from "./queue";
@ -25,10 +25,10 @@ export type DOMMethods = {
export const staticNodeMethods: DOMMethods = {
___insertBefore(parent, nextSibling) {
parent.insertBefore(this[ScopeOffsets.START_NODE] as Node, nextSibling);
parent.insertBefore(this.___startNode as Node, nextSibling);
},
___remove() {
(this[ScopeOffsets.START_NODE] as ChildNode).remove();
(this.___startNode as ChildNode).remove();
},
___getParentNode() {
return this.___getFirstNode().parentNode!;
@ -37,27 +37,27 @@ export const staticNodeMethods: DOMMethods = {
return this.___getLastNode().nextSibling;
},
___getFirstNode() {
return this[ScopeOffsets.START_NODE] as ChildNode;
return this.___startNode as ChildNode;
},
___getLastNode() {
return this[ScopeOffsets.END_NODE] as ChildNode;
return this.___endNode as ChildNode;
},
};
// export const staticNodePropertiesDef = {
// ___insertBefore: {
// value(parent, nextSibling) {
// parent.insertBefore(this[ScopeOffsets.START_NODE] as Node, nextSibling);
// parent.insertBefore(this.___startNode as Node, nextSibling);
// }
// },
// ___remove: {
// value() {
// (this[ScopeOffsets.START_NODE] as ChildNode).remove();
// (this.___startNode as ChildNode).remove();
// }
// },
// ___parentNode: {
// get() {
// return this[ScopeOffsets.START_NODE].parentNode;
// return this.___startNode.parentNode;
// },
// },
// ___afterNode: {

View File

@ -1,4 +1,4 @@
import { Scope, ScopeOffsets, HydrateSymbols } from "../common/types";
import { Scope, HydrateSymbols } from "../common/types";
import { bind, runWithScope } from "./scope";
type HydrateFn = () => void;
@ -66,8 +66,10 @@ export function init(runtimeId = "M" /* [a-zA-Z0-9]+ */) {
if (storedScope !== scope) {
if (storedScope) {
Object.assign(scope, storedScope);
} else {
scope.___id = scopeId;
scopeLookup[scopeId] = scope;
}
scopeLookup[scopeId] = scope;
if (currentScope === storedScope) {
currentScope = scope;
}
@ -83,7 +85,7 @@ export function init(runtimeId = "M" /* [a-zA-Z0-9]+ */) {
// eslint-disable-next-line no-constant-condition
if ("MARKO_DEBUG") {
const [offset, scopeId, index] = data.split(" ");
if (scopeId !== currentScope[ScopeOffsets.ID]) {
if (scopeId !== currentScope.___id) {
throw new Error("INVALID_MARKER_NESTING: " + nodeValue);
}
if (parseInt(offset) + currentOffset !== parseInt(index)) {
@ -96,22 +98,23 @@ export function init(runtimeId = "M" /* [a-zA-Z0-9]+ */) {
currentScope[(currentOffset += offset)] = node;
} else if (token === HydrateSymbols.SCOPE_START) {
if (currentScope) {
stack.push(currentScope[ScopeOffsets.ID] as string, currentOffset);
stack.push(currentScope.___id, currentOffset);
}
currentScope = scopeLookup[data]!;
currentOffset = 0;
if (!currentScope) {
scopeLookup[data] = currentScope = [data] as unknown as Scope;
scopeLookup[data] = currentScope = [] as unknown as Scope;
currentScope.___id = data;
}
currentScope[ScopeOffsets.START_NODE] = currentNode;
currentScope.___startNode = currentNode;
} else if (token === HydrateSymbols.SCOPE_END) {
// eslint-disable-next-line no-constant-condition
if ("MARKO_DEBUG") {
if (data !== currentScope[ScopeOffsets.ID]) {
if (data !== currentScope.___id) {
throw new Error("SCOPE_END_MISMATCH: " + nodeValue);
}
}
currentScope[ScopeOffsets.END_NODE] = currentNode;
currentScope.___endNode = currentNode;
currentOffset = stack.pop() as number;
currentScope = scopeLookup[stack.pop() as string]!;
// eslint-disable-next-line no-constant-condition

View File

@ -1,4 +1,4 @@
import { Scope, ScopeOffsets } from "../common/types";
import { Scope } from "../common/types";
import {
runWithScope,
currentScope,
@ -129,8 +129,8 @@ function findQueueIndex(scope: Scope, sortValue: number) {
function compareQueue(index: number, scope: Scope, sortValue: number) {
return (
compare(
(queuedFns[index + QueueOffsets.SCOPE] as Scope)[ScopeOffsets.ID],
scope[ScopeOffsets.ID]
(queuedFns[index + QueueOffsets.SCOPE] as Scope).___id,
scope.___id
) || (queuedFns[index + QueueOffsets.SORT_VALUE] as number) - sortValue
);
}

View File

@ -36,21 +36,21 @@ type RenderResult<I extends Input> = Node & {
export function initRenderer(renderer: Renderer, scope: Scope) {
const dom = renderer.___clone();
scope[ScopeOffsets.START_NODE] =
scope.___startNode =
dom.nodeType === NodeType.DocumentFragment ? dom.firstChild! : dom;
scope[ScopeOffsets.END_NODE] =
scope.___endNode =
dom.nodeType === NodeType.DocumentFragment ? dom.lastChild! : dom;
walk(scope[ScopeOffsets.START_NODE] as Node, renderer.___walks!, scope);
walk(scope.___startNode as Node, renderer.___walks!, scope);
if (renderer.___render) {
runWithScope(renderer.___render, ScopeOffsets.BEGIN_DATA, scope);
}
if (renderer.___dynamicStartNodeMethod) {
scope.___getFirstNode = renderer.___dynamicStartNodeMethod;
scope[ScopeOffsets.START_NODE] = renderer.___dynamicStartNodeOffset!;
scope.___startNode = renderer.___dynamicStartNodeOffset!;
}
if (renderer.___dynamicEndNodeMethod) {
scope.___getLastNode = renderer.___dynamicEndNodeMethod;
scope[ScopeOffsets.END_NODE] = renderer.___dynamicEndNodeOffset!;
scope.___endNode = renderer.___dynamicEndNodeOffset!;
}
return dom;
}

View File

@ -9,7 +9,7 @@ let scopeId = 0;
export function createScope(size: number, methods: DOMMethods): Scope {
const scope = new Array(size) as Scope;
scope[ScopeOffsets.ID] = "" + scopeId++;
scope.___id = "" + scopeId++;
scope[ScopeOffsets.OWNER_SCOPE] = currentScope;
scope[ScopeOffsets.OWNER_OFFSET] = currentOffset;
return Object.assign(scope, methods);
@ -17,8 +17,7 @@ export function createScope(size: number, methods: DOMMethods): Scope {
const emptyScope = createScope(0, staticNodeMethods);
export function getEmptyScope(marker?: Comment) {
emptyScope[ScopeOffsets.START_NODE] = emptyScope[ScopeOffsets.END_NODE] =
marker;
emptyScope.___startNode = emptyScope.___endNode = marker;
return emptyScope;
}
@ -106,9 +105,9 @@ export function runInChild(fn: () => void, offset: number) {
}
export function destroyScope(scope: Scope) {
scope[ScopeOffsets.OWNER_SCOPE]?.[ScopeOffsets.CLEANUP]?.delete(scope);
scope[ScopeOffsets.OWNER_SCOPE]?.___cleanup?.delete(scope);
const cleanup = scope[ScopeOffsets.CLEANUP];
const cleanup = scope.___cleanup;
if (cleanup) {
for (const instance of cleanup) {
if (typeof instance === "number") {
@ -124,11 +123,11 @@ export function destroyScope(scope: Scope) {
export function onDestroy(localIndex: number) {
const parentScope = currentScope[ScopeOffsets.OWNER_SCOPE];
if (parentScope) {
(parentScope[ScopeOffsets.CLEANUP] =
parentScope[ScopeOffsets.CLEANUP] || new Set()).add(currentScope);
(parentScope.___cleanup = parentScope.___cleanup || new Set()).add(
currentScope
);
}
(currentScope[ScopeOffsets.CLEANUP] =
currentScope[ScopeOffsets.CLEANUP] || new Set()).add(
(currentScope.___cleanup = currentScope.___cleanup || new Set()).add(
currentOffset + localIndex
);
}

View File

@ -43,7 +43,9 @@ export function createRenderer(renderer: Renderer, hydrateRoot?: boolean) {
try {
let renderedPromises: typeof $_promises;
try {
const scope = hydrateRoot ? (["ROOT"] as any as Scope) : nullScope;
const scope = hydrateRoot
? (Object.assign([], { ___id: "ROOT" }) as any as Scope)
: nullScope;
hydrateRoot && write(markScopeStart(scope));
renderer(input, scope, ScopeOffsets.BEGIN_DATA);
hydrateRoot && write(markScopeEnd(scope));
@ -74,7 +76,7 @@ export function writeCall(fnId: string, offset: number, scopeId: string) {
export function writeScope(scope: Scope) {
$_buffer!.scopes = $_buffer!.scopes || {};
$_buffer!.scopes[scope[ScopeOffsets.ID]] = scope;
$_buffer!.scopes[scope.___id] = scope;
}
export function fork<T>(
@ -254,25 +256,19 @@ export function markScopeOffset(index: number, scope: Scope) {
lastIndex.set(scope, index);
// eslint-disable-next-line no-constant-condition
if ("MARKO_DEBUG") {
return `<!${runtimeId}${HydrateSymbols.SCOPE_OFFSET}${offset} ${
scope[ScopeOffsets.ID]
} ${index}>`;
return `<!${runtimeId}${HydrateSymbols.SCOPE_OFFSET}${offset} ${scope.___id} ${index}>`;
}
return `<!${runtimeId}${HydrateSymbols.SCOPE_OFFSET}${offset}>`;
}
export function markScopeStart(scope: Scope) {
return `<!${runtimeId}${HydrateSymbols.SCOPE_START}${
scope[ScopeOffsets.ID]
}>`;
return `<!${runtimeId}${HydrateSymbols.SCOPE_START}${scope.___id}>`;
}
export function markScopeEnd(scope: Scope) {
// eslint-disable-next-line no-constant-condition
if ("MARKO_DEBUG") {
return `<!${runtimeId}${HydrateSymbols.SCOPE_END}${
scope[ScopeOffsets.ID]
}>`;
return `<!${runtimeId}${HydrateSymbols.SCOPE_END}${scope.___id}>`;
}
return `<!${runtimeId}${HydrateSymbols.SCOPE_END}>`;
}