diff --git a/.sizes.json b/.sizes.json index d0ecb94b5..7ac4ef996 100644 --- a/.sizes.json +++ b/.sizes.json @@ -6,9 +6,9 @@ { "name": "*", "individual": { - "min": 11962, - "gzip": 5140, - "brotli": 4628 + "min": 11615, + "gzip": 5073, + "brotli": 4574 } } ] diff --git a/packages/runtime/src/__tests__/__snapshots__/runtime/basic-counter/ssr-hydrate.expected.md b/packages/runtime/src/__tests__/__snapshots__/runtime/basic-counter/ssr-hydrate.expected.md index 9100fdd82..a997d3d24 100644 --- a/packages/runtime/src/__tests__/__snapshots__/runtime/basic-counter/ssr-hydrate.expected.md +++ b/packages/runtime/src/__tests__/__snapshots__/runtime/basic-counter/ssr-hydrate.expected.md @@ -1,5 +1,5 @@ # Write - + # Render "End" @@ -8,13 +8,13 @@ - + @@ -43,13 +43,13 @@ inserted #document/html1/body1/script2/#text0 - + @@ -70,13 +70,13 @@ container.querySelector("button").click(); - + @@ -97,13 +97,13 @@ container.querySelector("button").click(); - + @@ -124,13 +124,13 @@ container.querySelector("button").click(); - + diff --git a/packages/runtime/src/__tests__/fixtures/basic-counter/server.ts b/packages/runtime/src/__tests__/fixtures/basic-counter/server.ts index 708db8a22..25dee5b3a 100644 --- a/packages/runtime/src/__tests__/fixtures/basic-counter/server.ts +++ b/packages/runtime/src/__tests__/fixtures/basic-counter/server.ts @@ -6,7 +6,6 @@ export default ( currentScope: Scope, currentOffset: number ) => { - currentScope[0] = "ROOT"; write(""); counter(_input, currentScope, currentOffset); write(""); @@ -27,5 +26,5 @@ const counter = ( )}${count}` ); writeScope(currentScope); - writeCall("counter", currentOffset, currentScope[0]); + writeCall("counter", currentOffset, currentScope.___id); }; diff --git a/packages/runtime/src/common/types.ts b/packages/runtime/src/common/types.ts index 2a7fb9411..c3a681a43 100644 --- a/packages/runtime/src/common/types.ts +++ b/packages/runtime/src/common/types.ts @@ -9,14 +9,15 @@ export type HydrateInstance = [ ]; export type Scope = [ - string, // ID - Node | number | undefined, // START_NODE - Node | number | undefined, // END_NODE - Set | undefined, // CLEANUP Scope | undefined, // OWNER_SCOPE number | undefined, // OWNER_OFFSET ...unknown[] ] & { + ___id: string; + ___startNode: Node | number | undefined; + ___endNode: Node | number | undefined; + ___cleanup: Set | 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 { diff --git a/packages/runtime/src/dom/control-flow.ts b/packages/runtime/src/dom/control-flow.ts index 2c30c5444..ee8f1948e 100644 --- a/packages/runtime/src/dom/control-flow.ts +++ b/packages/runtime/src/dom/control-flow.ts @@ -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( diff --git a/packages/runtime/src/dom/dom.ts b/packages/runtime/src/dom/dom.ts index 48218ebfb..fdf8f514a 100644 --- a/packages/runtime/src/dom/dom.ts +++ b/packages/runtime/src/dom/dom.ts @@ -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: { diff --git a/packages/runtime/src/dom/hydrate.ts b/packages/runtime/src/dom/hydrate.ts index f35d72f58..38766d620 100644 --- a/packages/runtime/src/dom/hydrate.ts +++ b/packages/runtime/src/dom/hydrate.ts @@ -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 diff --git a/packages/runtime/src/dom/queue.ts b/packages/runtime/src/dom/queue.ts index b87a8bfb3..250c9775c 100644 --- a/packages/runtime/src/dom/queue.ts +++ b/packages/runtime/src/dom/queue.ts @@ -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 ); } diff --git a/packages/runtime/src/dom/renderer.ts b/packages/runtime/src/dom/renderer.ts index ccc6fd510..3e574dd88 100644 --- a/packages/runtime/src/dom/renderer.ts +++ b/packages/runtime/src/dom/renderer.ts @@ -36,21 +36,21 @@ type RenderResult = 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; } diff --git a/packages/runtime/src/dom/scope.ts b/packages/runtime/src/dom/scope.ts index b03fcb477..45e004e8e 100644 --- a/packages/runtime/src/dom/scope.ts +++ b/packages/runtime/src/dom/scope.ts @@ -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 ); } diff --git a/packages/runtime/src/html/writer.ts b/packages/runtime/src/html/writer.ts index 18e995e2c..e2baa3ecf 100644 --- a/packages/runtime/src/html/writer.ts +++ b/packages/runtime/src/html/writer.ts @@ -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( @@ -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 ``; + return ``; } return ``; } export function markScopeStart(scope: Scope) { - return ``; + return ``; } export function markScopeEnd(scope: Scope) { // eslint-disable-next-line no-constant-condition if ("MARKO_DEBUG") { - return ``; + return ``; } return ``; }