From 1085a19fd26eeb7aac8ee209d852c8d536a2387d Mon Sep 17 00:00:00 2001 From: Ryan Turnquist Date: Fri, 5 Dec 2025 12:52:52 -0800 Subject: [PATCH] fix: set parent branch on async branches --- .changeset/short-shirts-help.md | 5 + .sizes.json | 28 +- .sizes/dom.js | 571 +++++++++--------- .sizes/name-cache.json | 2 +- .../__snapshots__/.name-cache.json | 29 + .../__snapshots__/csr-sanitized.expected.md | 67 ++ .../__snapshots__/csr.expected.md | 114 ++++ .../dom.expected/template.hydrate.js | 56 ++ .../__snapshots__/dom.expected/template.js | 50 ++ .../__snapshots__/html.expected/template.js | 54 ++ .../resume-sanitized.expected.md | 51 ++ .../__snapshots__/resume.expected.md | 245 ++++++++ .../__snapshots__/ssr-sanitized.expected.md | 32 + .../__snapshots__/ssr.expected.md | 184 ++++++ .../fixtures/await-cleanup/template.marko | 13 + .../__tests__/fixtures/await-cleanup/test.ts | 7 + packages/runtime-tags/src/dom/renderer.ts | 19 +- packages/runtime-tags/src/dom/resume.ts | 11 +- 18 files changed, 1223 insertions(+), 315 deletions(-) create mode 100644 .changeset/short-shirts-help.md create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/.name-cache.json create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/csr-sanitized.expected.md create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/csr.expected.md create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/dom.expected/template.hydrate.js create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/dom.expected/template.js create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/html.expected/template.js create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/resume-sanitized.expected.md create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/resume.expected.md create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/ssr-sanitized.expected.md create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/ssr.expected.md create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/template.marko create mode 100644 packages/runtime-tags/src/__tests__/fixtures/await-cleanup/test.ts diff --git a/.changeset/short-shirts-help.md b/.changeset/short-shirts-help.md new file mode 100644 index 000000000..360fef2b9 --- /dev/null +++ b/.changeset/short-shirts-help.md @@ -0,0 +1,5 @@ +--- +"@marko/runtime-tags": patch +--- + +Ensure parent branch is set on async branches diff --git a/.sizes.json b/.sizes.json index ed5deb8d1..a32316b32 100644 --- a/.sizes.json +++ b/.sizes.json @@ -7,8 +7,8 @@ { "name": "*", "total": { - "min": 20366, - "brotli": 7839 + "min": 20363, + "brotli": 7810 } }, { @@ -18,12 +18,12 @@ "brotli": 140 }, "runtime": { - "min": 4076, - "brotli": 1832 + "min": 4084, + "brotli": 1846 }, "total": { - "min": 4250, - "brotli": 1972 + "min": 4258, + "brotli": 1986 } }, { @@ -34,11 +34,11 @@ }, "runtime": { "min": 2209, - "brotli": 1163 + "brotli": 1160 }, "total": { "min": 2305, - "brotli": 1250 + "brotli": 1247 } }, { @@ -48,12 +48,12 @@ "brotli": 398 }, "runtime": { - "min": 7132, - "brotli": 3114 + "min": 7140, + "brotli": 3125 }, "total": { - "min": 7867, - "brotli": 3512 + "min": 7875, + "brotli": 3523 } }, { @@ -64,11 +64,11 @@ }, "runtime": { "min": 2361, - "brotli": 1204 + "brotli": 1208 }, "total": { "min": 2491, - "brotli": 1319 + "brotli": 1323 } } ] diff --git a/.sizes/dom.js b/.sizes/dom.js index 434a48d29..18d971b51 100644 --- a/.sizes/dom.js +++ b/.sizes/dom.js @@ -1,4 +1,4 @@ -// size: 20366 (min) 7839 (brotli) +// size: 20363 (min) 7810 (brotli) var empty = [], rest = Symbol(); function attrTag(attrs) { @@ -113,7 +113,14 @@ function handleDelegated(ev) { function stripSpacesAndPunctuation(str) { return str.replace(/[^\p{L}\p{N}]/gu, ""); } -var nextScopeId = 1e6; +var parsers = {}; +function parseHTML(html, ns) { + let parser = (parsers[ns] ||= document.createElementNS(ns, "template")); + return ((parser.innerHTML = html), parser.content || parser); +} +var isScheduled, + channel, + nextScopeId = 1e6; function createScope($global, closestBranch) { let scope = { L: nextScopeId++, H: 1, F: closestBranch, $: $global }; return (pendingScopes.push(scope), scope); @@ -147,6 +154,188 @@ function tempDetachBranch(branch) { ((fragment.namespaceURI = branch.S.parentNode.namespaceURI), insertChildNodes(fragment, null, branch.S, branch.K)); } +function schedule() { + isScheduled || ((isScheduled = 1), queueMicrotask(flushAndWaitFrame)); +} +function flushAndWaitFrame() { + (run(), requestAnimationFrame(triggerMacroTask)); +} +function triggerMacroTask() { + (channel || + ((channel = new MessageChannel()).port1.onmessage = () => { + ((isScheduled = 0), run()); + }), + channel.port2.postMessage(0)); +} +function _let(id, fn) { + let valueAccessor = decodeAccessor(id), + valueChangeAccessor = "M" + valueAccessor; + return (scope, value, valueChange) => ( + rendering + ? (((scope[valueChangeAccessor] = valueChange) && + scope[valueAccessor] !== value) || + scope.H) && + ((scope[valueAccessor] = value), fn?.(scope)) + : scope[valueChangeAccessor] + ? scope[valueChangeAccessor](value) + : scope[valueAccessor] !== (scope[valueAccessor] = value) && + fn && + (schedule(), queueRender(scope, fn, id)), + value + ); +} +function _const(valueAccessor, fn) { + return ( + (valueAccessor = decodeAccessor(valueAccessor)), + (scope, value) => { + (!(valueAccessor in scope) || scope[valueAccessor] !== value) && + ((scope[valueAccessor] = value), fn?.(scope)); + } + ); +} +function _or(id, fn, defaultPending = 1, scopeIdAccessor = "L") { + return (scope) => { + scope.H + ? id in scope + ? --scope[id] || fn(scope) + : (scope[id] = defaultPending) + : queueRender(scope, fn, id, 0, scope[scopeIdAccessor]); + }; +} +function _for_closure(ownerLoopNodeAccessor, fn) { + let scopeAccessor = + "A" + (ownerLoopNodeAccessor = decodeAccessor(ownerLoopNodeAccessor)), + ownerSignal = (ownerScope) => { + let scopes = toArray(ownerScope[scopeAccessor]); + scopes.length && + queueRender( + ownerScope, + () => { + for (let scope of scopes) !scope.H && !scope.I && fn(scope); + }, + -1, + 0, + scopes[0].L, + ); + }; + return ((ownerSignal._ = fn), ownerSignal); +} +function _if_closure(ownerConditionalNodeAccessor, branch, fn) { + let scopeAccessor = + "A" + + (ownerConditionalNodeAccessor = decodeAccessor( + ownerConditionalNodeAccessor, + )), + branchAccessor = "D" + ownerConditionalNodeAccessor, + ownerSignal = (scope) => { + let ifScope = scope[scopeAccessor]; + ifScope && + !ifScope.H && + (scope[branchAccessor] || 0) === branch && + queueRender(ifScope, fn, -1); + }; + return ((ownerSignal._ = fn), ownerSignal); +} +function subscribeToScopeSet(ownerScope, accessor, scope) { + let subscribers = (ownerScope[accessor] ||= new Set()); + subscribers.has(scope) || + (subscribers.add(scope), + $signal(scope, -1).addEventListener("abort", () => + ownerScope[accessor].delete(scope), + )); +} +function _closure(...closureSignals) { + let [{ k: ___scopeInstancesAccessor, l: ___signalIndexAccessor }] = + closureSignals; + for (let i = closureSignals.length; i--; ) closureSignals[i].q = i; + return (scope) => { + if (scope[___scopeInstancesAccessor]) + for (let childScope of scope[___scopeInstancesAccessor]) + childScope.H || + queueRender( + childScope, + closureSignals[childScope[___signalIndexAccessor]], + -1, + ); + }; +} +function _closure_get(valueAccessor, fn, getOwnerScope, resumeId) { + valueAccessor = decodeAccessor(valueAccessor); + let closureSignal = (scope) => { + ((scope[closureSignal.l] = closureSignal.q), + fn(scope), + subscribeToScopeSet( + getOwnerScope ? getOwnerScope(scope) : scope._, + closureSignal.k, + scope, + )); + }; + return ( + (closureSignal.k = "B" + valueAccessor), + (closureSignal.l = "C" + valueAccessor), + resumeId && _resume(resumeId, closureSignal), + closureSignal + ); +} +function _child_setup(setup) { + return ( + (setup._ = (scope, owner) => { + ((scope._ = owner), queueRender(scope, setup, -1)); + }), + setup + ); +} +function _var(scope, childAccessor, signal) { + scope[decodeAccessor(childAccessor)].T = (value) => signal(scope, value); +} +var _return = (scope, value) => scope.T?.(value); +function _return_change(scope, changeHandler) { + changeHandler && (scope.U = changeHandler); +} +var _var_change = (scope, value) => scope.U?.(value), + tagIdsByGlobal = new WeakMap(); +function _id({ $: $global }) { + let id = tagIdsByGlobal.get($global) || 0; + return ( + tagIdsByGlobal.set($global, id + 1), + "c" + $global.runtimeId + $global.renderId + id.toString(36) + ); +} +function _script(id, fn) { + return ( + _resume(id, fn), + (scope) => { + queueEffect(scope, fn); + } + ); +} +function _el_read(value) { + return value; +} +function* traverseAllHoisted(scope, path, curIndex = path.length - 1) { + if (scope) + if (Symbol.iterator in scope) + for (let s of scope instanceof Map ? scope.values() : scope) + yield* traverseAllHoisted(s, path, curIndex); + else + curIndex + ? yield* traverseAllHoisted(scope[path[curIndex]], path, curIndex - 1) + : yield scope[path[0]]; +} +function _hoist(...path) { + return ( + (path = path.map((p) => ("string" == typeof p ? p : decodeAccessor(p)))), + (scope) => { + let getOne = (...args) => + iterator() + .next() + .value?.(...args), + iterator = (getOne[Symbol.iterator] = () => + traverseAllHoisted(scope, path)); + return getOne; + } + ); +} var walker = document.createTreeWalker(document); function walk(startNode, walkCodes, branch) { ((walker.currentNode = startNode), walkInternal(0, walkCodes, branch)); @@ -200,6 +389,99 @@ function walkInternal(currentWalkIndex, walkCodes, scope) { } else storedMultiplier = 10 * currentMultiplier + value - 117; } } +function createBranch($global, renderer, parentScope, parentNode) { + let branch = createScope($global); + return ( + (branch._ = renderer.e || parentScope), + setParentBranch(branch, parentScope?.F), + renderer.h?.(branch, parentNode.namespaceURI), + branch + ); +} +function setParentBranch(branch, parentBranch) { + (parentBranch && + ((branch.N = parentBranch), (parentBranch.D ||= new Set()).add(branch)), + (branch.F = branch)); +} +function createAndSetupBranch($global, renderer, parentScope, parentNode) { + return setupBranch( + renderer, + createBranch($global, renderer, parentScope, parentNode), + ); +} +function setupBranch(renderer, branch) { + return (renderer.j && queueRender(branch, renderer.j, -1), branch); +} +function _content(id, template, walks, setup, params, dynamicScopesAccessor) { + ((walks = walks ? walks.replace(/[^\0-1]+$/, "") : ""), + (setup = setup ? setup._ || setup : void 0), + (params ||= void 0)); + let clone = template + ? (branch, ns) => { + ((cloneCache[ns] ||= {})[template] ||= (function (html, ns) { + let { firstChild: firstChild, lastChild: lastChild } = parseHTML( + html, + ns, + ), + parent = document.createElementNS(ns, "t"); + return ( + insertChildNodes(parent, null, firstChild, lastChild), + firstChild === lastChild && firstChild.nodeType < 8 + ? (branch, walks) => { + walk( + (branch.S = branch.K = firstChild.cloneNode(!0)), + walks, + branch, + ); + } + : (branch, walks) => { + let clone = parent.cloneNode(!0); + (walk(clone.firstChild, walks, branch), + (branch.S = clone.firstChild), + (branch.K = clone.lastChild)); + } + ); + })(template, ns))(branch, walks); + } + : (branch) => { + walk((branch.S = branch.K = new Text()), walks, branch); + }; + return (owner) => ({ + f: id, + h: clone, + e: owner, + j: setup, + b: params, + d: dynamicScopesAccessor, + }); +} +function _content_resume( + id, + template, + walks, + setup, + params, + dynamicScopesAccessor, +) { + return _resume( + id, + _content(id, template, walks, setup, params, dynamicScopesAccessor), + ); +} +function _content_closures(renderer, closureFns) { + let closureSignals = {}; + for (let key in closureFns) + closureSignals[key] = _const(+key, closureFns[key]); + return (owner, closureValues) => { + let instance = renderer(owner); + return ( + (instance.n = closureSignals), + (instance.t = closureValues), + instance + ); + }; +} +var cloneCache = {}; var branchesEnabled, isResuming, registeredValues = {}; @@ -268,7 +550,7 @@ function init(runtimeId = "M") { ((endedBranches ||= []).push( (branch = scopeLookup[branchId] ||= { L: branchId }), ), - (branch.F = branch), + setParentBranch(branch, branch.F), (branch.O = render.p?.[branchId]) && (branch.O.m = render.m), singleNode) @@ -297,8 +579,7 @@ function init(runtimeId = "M") { ? startVisit : parent.insertBefore(new Text(), visit))); for (; i && orphanBranches[--i].L > branchId; ) - ((orphanBranches[i].N = branch), - (branch.D ||= new Set()).add(orphanBranches.pop())); + setParentBranch(orphanBranches.pop(), branch); nextToken(); } (endedBranches && @@ -648,286 +929,6 @@ function normalizeBoolProp(value) { function toValueProp(it) { return it.value; } -var isScheduled, - channel, - parsers = {}; -function parseHTML(html, ns) { - let parser = (parsers[ns] ||= document.createElementNS(ns, "template")); - return ((parser.innerHTML = html), parser.content || parser); -} -function schedule() { - isScheduled || ((isScheduled = 1), queueMicrotask(flushAndWaitFrame)); -} -function flushAndWaitFrame() { - (run(), requestAnimationFrame(triggerMacroTask)); -} -function triggerMacroTask() { - (channel || - ((channel = new MessageChannel()).port1.onmessage = () => { - ((isScheduled = 0), run()); - }), - channel.port2.postMessage(0)); -} -function _let(id, fn) { - let valueAccessor = decodeAccessor(id), - valueChangeAccessor = "M" + valueAccessor; - return (scope, value, valueChange) => ( - rendering - ? (((scope[valueChangeAccessor] = valueChange) && - scope[valueAccessor] !== value) || - scope.H) && - ((scope[valueAccessor] = value), fn?.(scope)) - : scope[valueChangeAccessor] - ? scope[valueChangeAccessor](value) - : scope[valueAccessor] !== (scope[valueAccessor] = value) && - fn && - (schedule(), queueRender(scope, fn, id)), - value - ); -} -function _const(valueAccessor, fn) { - return ( - (valueAccessor = decodeAccessor(valueAccessor)), - (scope, value) => { - (!(valueAccessor in scope) || scope[valueAccessor] !== value) && - ((scope[valueAccessor] = value), fn?.(scope)); - } - ); -} -function _or(id, fn, defaultPending = 1, scopeIdAccessor = "L") { - return (scope) => { - scope.H - ? id in scope - ? --scope[id] || fn(scope) - : (scope[id] = defaultPending) - : queueRender(scope, fn, id, 0, scope[scopeIdAccessor]); - }; -} -function _for_closure(ownerLoopNodeAccessor, fn) { - let scopeAccessor = - "A" + (ownerLoopNodeAccessor = decodeAccessor(ownerLoopNodeAccessor)), - ownerSignal = (ownerScope) => { - let scopes = toArray(ownerScope[scopeAccessor]); - scopes.length && - queueRender( - ownerScope, - () => { - for (let scope of scopes) !scope.H && !scope.I && fn(scope); - }, - -1, - 0, - scopes[0].L, - ); - }; - return ((ownerSignal._ = fn), ownerSignal); -} -function _if_closure(ownerConditionalNodeAccessor, branch, fn) { - let scopeAccessor = - "A" + - (ownerConditionalNodeAccessor = decodeAccessor( - ownerConditionalNodeAccessor, - )), - branchAccessor = "D" + ownerConditionalNodeAccessor, - ownerSignal = (scope) => { - let ifScope = scope[scopeAccessor]; - ifScope && - !ifScope.H && - (scope[branchAccessor] || 0) === branch && - queueRender(ifScope, fn, -1); - }; - return ((ownerSignal._ = fn), ownerSignal); -} -function subscribeToScopeSet(ownerScope, accessor, scope) { - let subscribers = (ownerScope[accessor] ||= new Set()); - subscribers.has(scope) || - (subscribers.add(scope), - $signal(scope, -1).addEventListener("abort", () => - ownerScope[accessor].delete(scope), - )); -} -function _closure(...closureSignals) { - let [{ k: ___scopeInstancesAccessor, l: ___signalIndexAccessor }] = - closureSignals; - for (let i = closureSignals.length; i--; ) closureSignals[i].q = i; - return (scope) => { - if (scope[___scopeInstancesAccessor]) - for (let childScope of scope[___scopeInstancesAccessor]) - childScope.H || - queueRender( - childScope, - closureSignals[childScope[___signalIndexAccessor]], - -1, - ); - }; -} -function _closure_get(valueAccessor, fn, getOwnerScope, resumeId) { - valueAccessor = decodeAccessor(valueAccessor); - let closureSignal = (scope) => { - ((scope[closureSignal.l] = closureSignal.q), - fn(scope), - subscribeToScopeSet( - getOwnerScope ? getOwnerScope(scope) : scope._, - closureSignal.k, - scope, - )); - }; - return ( - (closureSignal.k = "B" + valueAccessor), - (closureSignal.l = "C" + valueAccessor), - resumeId && _resume(resumeId, closureSignal), - closureSignal - ); -} -function _child_setup(setup) { - return ( - (setup._ = (scope, owner) => { - ((scope._ = owner), queueRender(scope, setup, -1)); - }), - setup - ); -} -function _var(scope, childAccessor, signal) { - scope[decodeAccessor(childAccessor)].T = (value) => signal(scope, value); -} -var _return = (scope, value) => scope.T?.(value); -function _return_change(scope, changeHandler) { - changeHandler && (scope.U = changeHandler); -} -var _var_change = (scope, value) => scope.U?.(value), - tagIdsByGlobal = new WeakMap(); -function _id({ $: $global }) { - let id = tagIdsByGlobal.get($global) || 0; - return ( - tagIdsByGlobal.set($global, id + 1), - "c" + $global.runtimeId + $global.renderId + id.toString(36) - ); -} -function _script(id, fn) { - return ( - _resume(id, fn), - (scope) => { - queueEffect(scope, fn); - } - ); -} -function _el_read(value) { - return value; -} -function* traverseAllHoisted(scope, path, curIndex = path.length - 1) { - if (scope) - if (Symbol.iterator in scope) - for (let s of scope instanceof Map ? scope.values() : scope) - yield* traverseAllHoisted(s, path, curIndex); - else - curIndex - ? yield* traverseAllHoisted(scope[path[curIndex]], path, curIndex - 1) - : yield scope[path[0]]; -} -function _hoist(...path) { - return ( - (path = path.map((p) => ("string" == typeof p ? p : decodeAccessor(p)))), - (scope) => { - let getOne = (...args) => - iterator() - .next() - .value?.(...args), - iterator = (getOne[Symbol.iterator] = () => - traverseAllHoisted(scope, path)); - return getOne; - } - ); -} -function createBranch($global, renderer, parentScope, parentNode) { - let branch = createScope($global), - parentBranch = parentScope?.F; - return ( - (branch._ = renderer.e || parentScope), - (branch.F = branch), - parentBranch && - ((branch.N = parentBranch), (parentBranch.D ||= new Set()).add(branch)), - renderer.h?.(branch, parentNode.namespaceURI), - branch - ); -} -function createAndSetupBranch($global, renderer, parentScope, parentNode) { - return setupBranch( - renderer, - createBranch($global, renderer, parentScope, parentNode), - ); -} -function setupBranch(renderer, branch) { - return (renderer.j && queueRender(branch, renderer.j, -1), branch); -} -function _content(id, template, walks, setup, params, dynamicScopesAccessor) { - ((walks = walks ? walks.replace(/[^\0-1]+$/, "") : ""), - (setup = setup ? setup._ || setup : void 0), - (params ||= void 0)); - let clone = template - ? (branch, ns) => { - ((cloneCache[ns] ||= {})[template] ||= (function (html, ns) { - let { firstChild: firstChild, lastChild: lastChild } = parseHTML( - html, - ns, - ), - parent = document.createElementNS(ns, "t"); - return ( - insertChildNodes(parent, null, firstChild, lastChild), - firstChild === lastChild && firstChild.nodeType < 8 - ? (branch, walks) => { - walk( - (branch.S = branch.K = firstChild.cloneNode(!0)), - walks, - branch, - ); - } - : (branch, walks) => { - let clone = parent.cloneNode(!0); - (walk(clone.firstChild, walks, branch), - (branch.S = clone.firstChild), - (branch.K = clone.lastChild)); - } - ); - })(template, ns))(branch, walks); - } - : (branch) => { - walk((branch.S = branch.K = new Text()), walks, branch); - }; - return (owner) => ({ - f: id, - h: clone, - e: owner, - j: setup, - b: params, - d: dynamicScopesAccessor, - }); -} -function _content_resume( - id, - template, - walks, - setup, - params, - dynamicScopesAccessor, -) { - return _resume( - id, - _content(id, template, walks, setup, params, dynamicScopesAccessor), - ); -} -function _content_closures(renderer, closureFns) { - let closureSignals = {}; - for (let key in closureFns) - closureSignals[key] = _const(+key, closureFns[key]); - return (owner, closureValues) => { - let instance = renderer(owner); - return ( - (instance.n = closureSignals), - (instance.t = closureValues), - instance - ); - }; -} -var cloneCache = {}; function _to_text(value) { return value || 0 === value ? value + "" : ""; } diff --git a/.sizes/name-cache.json b/.sizes/name-cache.json index 68c3584b0..7c8889719 100644 --- a/.sizes/name-cache.json +++ b/.sizes/name-cache.json @@ -1 +1 @@ -{"vars":{"props":{"$empty":"e","$rest":"t","$attrTag":"n","$attrTags":"r","$attrTagIterator":"i","$_assert_hoist":"o","$forIn":"l","$forOf":"u","$forTo":"f","$forUntil":"a","$_call":"c","$stringifyClassObject":"s","$stringifyStyleObject":"d","$toDelimitedString":"h","$isEventHandler":"p","$getEventHandlerName":"g","$normalizeDynamicRenderer":"v","$decodeAccessor":"b","$toArray":"m","$push":"S","$defaultDelegator":"y","$_on":"A","$createDelegator":"N","$handleDelegated":"k","$stripSpacesAndPunctuation":"C","$nextScopeId":"_","$createScope":"w","$skipScope":"E","$findBranchWithKey":"T","$destroyBranch":"I","$destroyNestedBranches":"F","$removeAndDestroyBranch":"M","$insertBranchBefore":"x","$tempDetachBranch":"L","$walker":"$","$walk":"O","$walkInternal":"D","$branchesEnabled":"K","$isResuming":"V","$registeredValues":"G","$enableBranches":"R","$init":"B","$runResumeEffects":"H","$_resume":"U","$_var_resume":"q","$_el":"P","$_attr_input_checked":"j","$_attr_input_checked_script":"W","$_attr_input_checkedValue":"J","$_attr_input_checkedValue_script":"Q","$_attr_input_value":"X","$_attr_input_value_script":"Z","$_attr_select_value":"z","$_attr_select_value_script":"Y","$setSelectOptions":"ee","$_attr_details_or_dialog_open":"te","$_attr_details_or_dialog_open_script":"ne","$inputType":"re","$setValueAndUpdateSelection":"ie","$setCheckboxValue":"oe","$controllableDelegate":"le","$syncControllable":"ue","$handleChange":"fe","$handleFormReset":"ae","$hasValueChanged":"ce","$hasCheckboxChanged":"se","$hasSelectChanged":"de","$hasFormElementChanged":"he","$normalizeStrProp":"pe","$normalizeBoolProp":"ge","$toValueProp":"ve","$isScheduled":"be","$channel":"me","$parsers":"Se","$parseHTML":"ye","$schedule":"Ae","$flushAndWaitFrame":"Ne","$triggerMacroTask":"ke","$_let":"Ce","$_const":"_e","$_or":"we","$_for_closure":"Ee","$_if_closure":"Te","$subscribeToScopeSet":"Ie","$_closure":"Fe","$_closure_get":"Me","$_child_setup":"xe","$_var":"Le","$_return":"$e","$_return_change":"Oe","$_var_change":"De","$tagIdsByGlobal":"Ke","$_id":"Ve","$_script":"Ge","$_el_read":"Re","$traverseAllHoisted":"Be","$_hoist":"He","$createBranch":"Ue","$createAndSetupBranch":"qe","$setupBranch":"Pe","$_content":"je","$_content_resume":"We","$_content_closures":"Je","$cloneCache":"Qe","$_to_text":"Xe","$_attr":"Ze","$setAttribute":"ze","$_attr_class":"Ye","$_attr_class_items":"et","$_attr_class_item":"tt","$_attr_style":"nt","$_attr_style_items":"rt","$_attr_style_item":"it","$_text":"ot","$_text_content":"lt","$_attrs":"ut","$_attrs_content":"ft","$hasAttrAlias":"at","$_attrs_partial":"ct","$_attrs_partial_content":"st","$attrsInternal":"dt","$_attr_content":"ht","$_attrs_script":"pt","$_html":"gt","$normalizeAttrValue":"vt","$normalizeString":"bt","$_lifecycle":"mt","$removeChildNodes":"St","$insertChildNodes":"yt","$toInsertNode":"At","$_await_promise":"Nt","$_await_content":"kt","$_try":"Ct","$renderCatch":"_t","$_if":"wt","$_dynamic_tag":"Et","$_resume_dynamic_tag":"Tt","$dynamicTagScript":"It","$setConditionalRenderer":"Ft","$_for_of":"Mt","$_for_in":"xt","$_for_to":"Lt","$_for_until":"$t","$loop":"Ot","$createBranchWithTagNameOrRenderer":"Dt","$bySecondArg":"Kt","$byFirstArg":"Vt","$asyncRendersLookup":"Gt","$rendering":"Rt","$pendingRenders":"Bt","$pendingRendersLookup":"Ht","$caughtError":"Ut","$placeholderShown":"qt","$pendingEffects":"Pt","$pendingScopes":"jt","$scopeKeyOffset":"Wt","$queueRender":"Jt","$queuePendingRender":"Qt","$queueEffect":"Xt","$run":"Zt","$prepareEffects":"zt","$runEffects":"Yt","$runRenders":"en","$runRender":"tn","$_enable_catch":"nn","$$signalReset":"rn","$$signal":"on","$abort":"ln","$classIdToBranch":"un","$compat":"fn","$_template":"an","$mount":"cn","$$clickCount__script":"ta","$$clickCount":"aa","$$setup":"na","$forEach":"sn","$$if_content__setup":"sa","$$if_content__comment_comments":"ia","$$if_content__id":"ca","$$for_content__id":"la","$$for_content__input_path__OR__i":"ma","$$for_content__input_path":"oa","$$for_content__i":"ua","$$for_content__open__script":"ba","$$for_content__open":"ea","$$for_content__setup":"_a","$$for_content__comment_text":"da","$$for_content__if":"fa","$$for_content__comment_comments":"ha","$$for_content__$params":"ja","$$for_content__comment":"pa","$$for":"ra","$$input_comments":"ga","$$input_path":"ka","$_attr_nonce":"dn"}}} \ No newline at end of file +{"vars":{"props":{"$empty":"e","$rest":"t","$attrTag":"n","$attrTags":"r","$attrTagIterator":"i","$_assert_hoist":"o","$forIn":"l","$forOf":"u","$forTo":"f","$forUntil":"a","$_call":"c","$stringifyClassObject":"s","$stringifyStyleObject":"d","$toDelimitedString":"h","$isEventHandler":"p","$getEventHandlerName":"g","$normalizeDynamicRenderer":"v","$decodeAccessor":"b","$toArray":"m","$push":"S","$defaultDelegator":"y","$_on":"A","$createDelegator":"N","$handleDelegated":"k","$stripSpacesAndPunctuation":"C","$nextScopeId":"_","$createScope":"w","$skipScope":"E","$findBranchWithKey":"T","$destroyBranch":"I","$destroyNestedBranches":"F","$removeAndDestroyBranch":"M","$insertBranchBefore":"x","$tempDetachBranch":"L","$walker":"$","$walk":"O","$walkInternal":"D","$branchesEnabled":"K","$isResuming":"V","$registeredValues":"G","$enableBranches":"R","$init":"B","$runResumeEffects":"H","$_resume":"U","$_var_resume":"q","$_el":"P","$_attr_input_checked":"j","$_attr_input_checked_script":"W","$_attr_input_checkedValue":"J","$_attr_input_checkedValue_script":"Q","$_attr_input_value":"X","$_attr_input_value_script":"Z","$_attr_select_value":"z","$_attr_select_value_script":"Y","$setSelectOptions":"ee","$_attr_details_or_dialog_open":"te","$_attr_details_or_dialog_open_script":"ne","$inputType":"re","$setValueAndUpdateSelection":"ie","$setCheckboxValue":"oe","$controllableDelegate":"le","$syncControllable":"ue","$handleChange":"fe","$handleFormReset":"ae","$hasValueChanged":"ce","$hasCheckboxChanged":"se","$hasSelectChanged":"de","$hasFormElementChanged":"he","$normalizeStrProp":"pe","$normalizeBoolProp":"ge","$toValueProp":"ve","$isScheduled":"be","$channel":"me","$parsers":"Se","$parseHTML":"ye","$schedule":"Ae","$flushAndWaitFrame":"Ne","$triggerMacroTask":"ke","$_let":"Ce","$_const":"_e","$_or":"we","$_for_closure":"Ee","$_if_closure":"Te","$subscribeToScopeSet":"Ie","$_closure":"Fe","$_closure_get":"Me","$_child_setup":"xe","$_var":"Le","$_return":"$e","$_return_change":"Oe","$_var_change":"De","$tagIdsByGlobal":"Ke","$_id":"Ve","$_script":"Ge","$_el_read":"Re","$traverseAllHoisted":"Be","$_hoist":"He","$createBranch":"Ue","$createAndSetupBranch":"qe","$setupBranch":"Pe","$_content":"je","$_content_resume":"We","$_content_closures":"Je","$cloneCache":"Qe","$_to_text":"Xe","$_attr":"Ze","$setAttribute":"ze","$_attr_class":"Ye","$_attr_class_items":"et","$_attr_class_item":"tt","$_attr_style":"nt","$_attr_style_items":"rt","$_attr_style_item":"it","$_text":"ot","$_text_content":"lt","$_attrs":"ut","$_attrs_content":"ft","$hasAttrAlias":"at","$_attrs_partial":"ct","$_attrs_partial_content":"st","$attrsInternal":"dt","$_attr_content":"ht","$_attrs_script":"pt","$_html":"gt","$normalizeAttrValue":"vt","$normalizeString":"bt","$_lifecycle":"mt","$removeChildNodes":"St","$insertChildNodes":"yt","$toInsertNode":"At","$_await_promise":"Nt","$_await_content":"kt","$_try":"Ct","$renderCatch":"_t","$_if":"wt","$_dynamic_tag":"Et","$_resume_dynamic_tag":"Tt","$dynamicTagScript":"It","$setConditionalRenderer":"Ft","$_for_of":"Mt","$_for_in":"xt","$_for_to":"Lt","$_for_until":"$t","$loop":"Ot","$createBranchWithTagNameOrRenderer":"Dt","$bySecondArg":"Kt","$byFirstArg":"Vt","$asyncRendersLookup":"Gt","$rendering":"Rt","$pendingRenders":"Bt","$pendingRendersLookup":"Ht","$caughtError":"Ut","$placeholderShown":"qt","$pendingEffects":"Pt","$pendingScopes":"jt","$scopeKeyOffset":"Wt","$queueRender":"Jt","$queuePendingRender":"Qt","$queueEffect":"Xt","$run":"Zt","$prepareEffects":"zt","$runEffects":"Yt","$runRenders":"en","$runRender":"tn","$_enable_catch":"nn","$$signalReset":"rn","$$signal":"on","$abort":"ln","$classIdToBranch":"un","$compat":"fn","$_template":"an","$mount":"cn","$$clickCount__script":"ta","$$clickCount":"aa","$$setup":"na","$forEach":"sn","$$if_content__setup":"sa","$$if_content__comment_comments":"ia","$$if_content__id":"ca","$$for_content__id":"la","$$for_content__input_path__OR__i":"ma","$$for_content__input_path":"oa","$$for_content__i":"ua","$$for_content__open__script":"ba","$$for_content__open":"ea","$$for_content__setup":"_a","$$for_content__comment_text":"da","$$for_content__if":"fa","$$for_content__comment_comments":"ha","$$for_content__$params":"ja","$$for_content__comment":"pa","$$for":"ra","$$input_comments":"ga","$$input_path":"ka","$_attr_nonce":"dn","$setParentBranch":"hn"}}} \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/.name-cache.json b/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/.name-cache.json new file mode 100644 index 000000000..ff2b1f81b --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/.name-cache.json @@ -0,0 +1,29 @@ +{ + "vars": { + "props": { + "$_": "t", + "$init": "o", + "$resolveAfter": "e", + "$$await_content__setup__script": "a", + "$$await_content__setup": "r", + "$$placeholder_content": "n", + "$$await_content": "i", + "$$try_content__await_promise": "c", + "$$try_content__setup": "s", + "$$if_content__try": "m", + "$$if_content__setup": "_", + "$$if": "l", + "$$show": "u", + "$$await_content__show": "d", + "$$show__closure": "g", + "$$try_content__show": "p", + "$$await_content2__setup__script": "b", + "$$await_content2__setup": "f", + "$$await_content2": "w", + "$$try_content__await_promise2": "$", + "$$try_content__v": "k", + "$$v__closure": "x", + "$$v": "y" + } + } +} diff --git a/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/csr-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/csr-sanitized.expected.md new file mode 100644 index 000000000..0c19b5e4a --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/csr-sanitized.expected.md @@ -0,0 +1,67 @@ +# Render +```html +
Fail
Fail
"; +export const $walks = /* get, over(3), replace, over(2) */" d%c"; +import { resolveAfter } from "../../utils/resolve"; +import * as _ from "@marko/runtime-tags/debug/dom"; +_._enable_catch(); +const $await_content2__setup__script = _._script("__tests__/template.marko_5", $scope => (_.$signal($scope, 0).onabort = () => document.querySelector('#two').textContent = "Pass")); +const $await_content2__setup = $scope => { + _.$signalReset($scope, 0); + $await_content2__setup__script($scope); +}; +const $placeholder_content = _._content_resume("__tests__/template.marko_4_content", "loading...", /* over(1) */"b"); +const $await_content__show = /* @__PURE__ */_._closure_get("show", $scope => _._text($scope["#text/0"], $scope._._._.show), $scope => $scope._._._, "__tests__/template.marko_3_show"); +const $await_content__setup__script = _._script("__tests__/template.marko_3", $scope => (_.$signal($scope, 0).onabort = () => document.querySelector('#one').textContent = "Pass")); +const $await_content__setup = $scope => { + _.$signalReset($scope, 0); + $await_content__show($scope); + $await_content__setup__script($scope); +}; +const $await_content = /* @__PURE__ */_._await_content("#text/0", " ", /* get, over(1) */" b", $await_content__setup); +const $try_content__await_promise = /* @__PURE__ */_._await_promise("#text/0"); +const $await_content2 = /* @__PURE__ */_._await_content("#text/1", 0, 0, $await_content2__setup); +const $try_content__await_promise2 = /* @__PURE__ */_._await_promise("#text/1"); +const $try_content__setup = $scope => { + $await_content($scope); + $await_content2($scope); + $try_content__await_promise($scope, resolveAfter(0, 1)); + $try_content__await_promise2($scope, resolveAfter(0, 1)); +}; +const $if_content__try = /* @__PURE__ */_._try("#text/0", "", /* over(1), replace, over(1), replace, over(2) */"b%b%c", $try_content__setup); +const $if_content__setup = $scope => { + $if_content__try($scope, { + placeholder: _.attrTag({ + content: $placeholder_content($scope) + }) + }); +}; +const $if = /* @__PURE__ */_._if("#text/1", "", /* over(1), replace, over(2) */"b%c", $if_content__setup); +const $show__closure = /* @__PURE__ */_._closure($await_content__show); +const $show = /* @__PURE__ */_._let("show/2", $scope => { + $if($scope, $scope.show ? 0 : 1); + $show__closure($scope); +}); +const $setup__script = _._script("__tests__/template.marko_0", $scope => _._on($scope["#button/0"], "click", function () { + $show($scope, 0); +})); +export function $setup($scope) { + $show($scope, 1); + $setup__script($scope); +} +export default /* @__PURE__ */_._template("__tests__/template.marko", $template, $walks, $setup); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/html.expected/template.js new file mode 100644 index 000000000..ba3b29f69 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/html.expected/template.js @@ -0,0 +1,54 @@ +import { resolveAfter } from "../../utils/resolve"; +import * as _ from "@marko/runtime-tags/debug/html"; +export default _._template("__tests__/template.marko", input => { + const $scope0_id = _._scope_id(); + const $show__closures = new Set(); + let show = 1; + _._html(`${_._el_resume($scope0_id, "#button/0")}
Fail
Fail
`); + _._if(() => { + if (show) { + const $scope1_id = _._scope_id(); + _._try($scope1_id, "#text/0", _._content_resume("__tests__/template.marko_2_content", () => { + const $scope2_id = _._scope_id(); + _._await($scope2_id, "#text/0", resolveAfter(0, 1), () => { + const $scope3_id = _._scope_id(); + _._script($scope3_id, "__tests__/template.marko_3_show"); + _._html(`${_._escape(show)}${_._el_resume($scope3_id, "#text/0")}`); + _._script($scope3_id, "__tests__/template.marko_3"); + _._scope($scope3_id, { + _: _._scope_with_id($scope2_id), + "ClosureSignalIndex:show": 0 + }, "__tests__/template.marko", "9:5"); + _._resume_branch($scope3_id); + }); + _._await($scope2_id, "#text/1", resolveAfter(0, 1), () => { + const $scope5_id = _._scope_id(); + _._script($scope5_id, "__tests__/template.marko_5"); + _._resume_branch($scope5_id); + }, 0); + _._scope($scope2_id, { + _: _._scope_with_id($scope1_id) + }, "__tests__/template.marko", "7:3"); + }, $scope1_id), { + placeholder: _.attrTag({ + content: _._content_resume("__tests__/template.marko_4_content", () => { + const $scope4_id = _._scope_id(); + _._html("loading..."); + }, $scope1_id) + }) + }); + _._scope($scope1_id, { + _: _._scope_with_id($scope0_id) + }, "__tests__/template.marko", "6:1"); + return 0; + } + }, $scope0_id, "#text/1"); + _._script($scope0_id, "__tests__/template.marko_0"); + _._scope($scope0_id, { + show, + "ClosureScopes:show": $show__closures + }, "__tests__/template.marko", 0, { + show: "2:5" + }); + _._resume_branch($scope0_id); +}); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/resume-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/resume-sanitized.expected.md new file mode 100644 index 000000000..96fe26e76 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/await-cleanup/__snapshots__/resume-sanitized.expected.md @@ -0,0 +1,51 @@ +# Render +```html +
Fail
Fail
loading... +``` + +# Write +```html + 1 +``` + +# Render ASYNC +```html + + + + + +