Repository: marko-js/marko (2025-08-30T22:47:14Z)

Issue:
Cannot assign to variable because it is a constant
### Marko Version: 6.0.56

The following snippet errors with `Cannot assign to "timer" because it is a constant`. Was ok with marko@6.0.55

```
export interface Input {
  duration: number;
  value: () => void;
}

<let/timer=(0 as unknown as ReturnType<typeof setTimeout>)>

<const/reset=() => {
  if (timer) {
    clearTimeout(timer);
  }

  timer = setTimeout(() => {
    input.value();
  }, input.duration);
}>

<return=reset>
```


Discussion:

Patch:
diff --git a/.changeset/mean-queens-feel.md b/.changeset/mean-queens-feel.md
new file mode 100644
index 0000000000..b7255b12b0
--- /dev/null
+++ b/.changeset/mean-queens-feel.md
@@ -0,0 +1,5 @@
+---
+"@marko/runtime-tags": patch
+---
+
+Fix issue with mutating tag variables within an intersection.
diff --git a/.changeset/mighty-ravens-grow.md b/.changeset/mighty-ravens-grow.md
new file mode 100644
index 0000000000..c303f0ae57
--- /dev/null
+++ b/.changeset/mighty-ravens-grow.md
@@ -0,0 +1,5 @@
+---
+"@marko/runtime-tags": patch
+---
+
+Refactor function registration, ensure functions passed as return value are registered.
diff --git a/.sizes.json b/.sizes.json
index f38a347b18..c7f6a3d130 100644
--- a/.sizes.json
+++ b/.sizes.json
@@ -44,16 +44,16 @@
     {
       "name": "comments",
       "user": {
-        "min": 894,
-        "brotli": 459
+        "min": 890,
+        "brotli": 458
       },
       "runtime": {
         "min": 7019,
         "brotli": 2994
       },
       "total": {
-        "min": 7913,
-        "brotli": 3453
+        "min": 7909,
+        "brotli": 3452
       }
     },
     {
diff --git a/.sizes/comments.csr/entry.js b/.sizes/comments.csr/entry.js
index 204d456797..97b79ef00a 100644
--- a/.sizes/comments.csr/entry.js
+++ b/.sizes/comments.csr/entry.js
@@ -1,11 +1,11 @@
-// size: 894 (min) 459 (brotli)
+// size: 890 (min) 458 (brotli)
 const $setup$if$content = ($scope) => {
     ($scope[0],
       $comment_comments$if$content._($scope),
       $id$if$content._($scope));
   },
   $expr_comment_comments_id$if$content = intersection(1, ($scope) => {
-    const {
+    let {
       _: { 8: comment_comments, 11: id },
     } = $scope;
     $input$1($scope[0], { comments: comment_comments, path: id });
@@ -27,7 +27,7 @@ const $setup$if$content = ($scope) => {
     (attr($scope[0], "id", id), $id$if$content($scope));
   }),
   $expr_input_path_i$for$content = intersection(10, ($scope) => {
-    const {
+    let {
       _: { 4: input_path },
       9: i,
     } = $scope;
diff --git a/packages/runtime-tags/src/translator/core/await.ts b/packages/runtime-tags/src/translator/core/await.ts
index 9f3f74d2b2..b39827e081 100644
--- a/packages/runtime-tags/src/translator/core/await.ts
+++ b/packages/runtime-tags/src/translator/core/await.ts
@@ -14,7 +14,7 @@ import {
   BindingType,
   createBinding,
   getScopeAccessorLiteral,
-  setBindingValueExpr,
+  setBindingDownstream,
   trackParamsReferences,
 } from "../util/references";
 import { callRuntime } from "../util/runtime";
@@ -102,7 +102,7 @@ export default {
     const paramsBinding = trackParamsReferences(tagBody, BindingType.param);
 
     if (paramsBinding) {
-      setBindingValueExpr(paramsBinding, valueExtra);
+      setBindingDownstream(paramsBinding, valueExtra);
     }
 
     bodySection.upstreamExpression = valueAttr.value.extra;
diff --git a/packages/runtime-tags/src/translator/core/const.ts b/packages/runtime-tags/src/translator/core/const.ts
index 31041d2ab9..a2a38a3766 100644
--- a/packages/runtime-tags/src/translator/core/const.ts
+++ b/packages/runtime-tags/src/translator/core/const.ts
@@ -10,7 +10,7 @@ import evaluate from "../util/evaluate";
 import { isOutputDOM } from "../util/marko-config";
 import {
   BindingType,
-  setBindingValueExpr,
+  setBindingDownstream,
   trackVarReferences,
 } from "../util/references";
 import runtimeInfo from "../util/runtime-info";
@@ -63,11 +63,7 @@ export default {
 
     if (binding) {
       if (!valueExtra.nullable) binding.nullable = false;
-      setBindingValueExpr(binding, valueExtra);
-      valueExtra.downstream = {
-        bindings: binding,
-        excludeProperties: undefined,
-      };
+      setBindingDownstream(binding, valueExtra);
     }
   },
   translate: {
diff --git a/packages/runtime-tags/src/translator/core/define.ts b/packages/runtime-tags/src/translator/core/define.ts
index cd2cd72abe..10721721d3 100644
--- a/packages/runtime-tags/src/translator/core/define.ts
+++ b/packages/runtime-tags/src/translator/core/define.ts
@@ -7,7 +7,7 @@ import {
   BindingType,
   getAllTagReferenceNodes,
   mergeReferences,
-  setBindingValueExpr,
+  setBindingDownstream,
   trackParamsReferences,
   trackVarReferences,
 } from "../util/references";
@@ -54,11 +54,7 @@ export default {
     );
 
     if (varBinding) {
-      setBindingValueExpr(varBinding, tagExtra);
-      tagExtra.downstream = {
-        bindings: varBinding,
-        excludeProperties: undefined,
-      };
+      setBindingDownstream(varBinding, tagExtra);
     }
   },
   translate: {
diff --git a/packages/runtime-tags/src/translator/core/for.ts b/packages/runtime-tags/src/translator/core/for.ts
index 534c2d2693..b662419972 100644
--- a/packages/runtime-tags/src/translator/core/for.ts
+++ b/packages/runtime-tags/src/translator/core/for.ts
@@ -22,7 +22,7 @@ import {
   getScopeAccessorLiteral,
   kBranchSerializeReason,
   mergeReferences,
-  setBindingValueExpr,
+  setBindingDownstream,
   trackParamsReferences,
 } from "../util/references";
 import { callRuntime } from "../util/runtime";
@@ -106,7 +106,7 @@ export default {
       getAllTagReferenceNodes(tag.node),
     );
     if (paramsBinding) {
-      setBindingValueExpr(paramsBinding, tagExtra);
+      setBindingDownstream(paramsBinding, tagExtra);
     }
     bodySection.sectionAccessor = {
       binding: nodeBinding,
diff --git a/packages/runtime-tags/src/translator/core/id.ts b/packages/runtime-tags/src/translator/core/id.ts
index 70afead8d3..dc463b428e 100644
--- a/packages/runtime-tags/src/translator/core/id.ts
+++ b/packages/runtime-tags/src/translator/core/id.ts
@@ -11,7 +11,7 @@ import { assertNoBodyContent } from "../util/assert";
 import { isOutputHTML } from "../util/marko-config";
 import {
   BindingType,
-  setBindingValueExpr,
+  setBindingDownstream,
   trackVarReferences,
 } from "../util/references";
 import { callRuntime } from "../util/runtime";
@@ -43,7 +43,7 @@ export default {
 
     const binding = trackVarReferences(tag, BindingType.derived);
     if (binding) {
-      setBindingValueExpr(binding, false);
+      setBindingDownstream(binding, false);
     }
   },
   translate: {
diff --git a/packages/runtime-tags/src/translator/core/let.ts b/packages/runtime-tags/src/translator/core/let.ts
index f808a32e56..b5c5289f45 100644
--- a/packages/runtime-tags/src/translator/core/let.ts
+++ b/packages/runtime-tags/src/translator/core/let.ts
@@ -12,7 +12,7 @@ import { isOutputDOM } from "../util/marko-config";
 import {
   BindingType,
   mergeReferences,
-  setBindingValueExpr,
+  setBindingDownstream,
   trackVarReferences,
 } from "../util/references";
 import runtimeInfo from "../util/runtime-info";
@@ -92,7 +92,7 @@ export default {
 
     const tagSection = getOrCreateSection(tag);
     const binding = trackVarReferences(tag, BindingType.let)!;
-    setBindingValueExpr(
+    setBindingDownstream(
       binding,
       mergeReferences(tagSection, tag.node, [
         valueAttr?.value,
diff --git a/packages/runtime-tags/src/translator/core/return.ts b/packages/runtime-tags/src/translator/core/return.ts
index 446481f0ac..4f1933cc3f 100644
--- a/packages/runtime-tags/src/translator/core/return.ts
+++ b/packages/runtime-tags/src/translator/core/return.ts
@@ -71,6 +71,7 @@ export default {
     }
 
     if (attrs.valueChange) {
+      (attrs.valueChange.extra ??= {}).isEffect = true;
       // TODO: this should be based on the parent actually mutating the tag variable.
       forceSectionSerialize(
         getOrCreateSection(tag),
diff --git a/packages/runtime-tags/src/translator/util/references.ts b/packages/runtime-tags/src/translator/util/references.ts
index 169f5994e9..a46f668078 100644
--- a/packages/runtime-tags/src/translator/util/references.ts
+++ b/packages/runtime-tags/src/translator/util/references.ts
@@ -18,7 +18,6 @@ import {
   findSorted,
   forEach,
   type Many,
-  type OneMany,
   type Opt,
   push,
   Sorted,
@@ -122,10 +121,7 @@ declare module "@marko/compiler/dist/types" {
   export interface NodeExtra {
     section?: Section;
     referencedBindings?: ReferencedBindings;
-    downstream?: {
-      bindings: OneMany<Binding>;
-      excludeProperties: undefined | Set<string>;
-    };
+    downstream?: Opt<Binding>;
     binding?: Binding;
     assignment?: Binding;
     assignmentTo?: Binding;
@@ -576,10 +572,10 @@ function createBindingsAndTrackReferences(
       );
 
       if (lVal.left.extra?.binding) {
-        (lVal.right.extra ??= {}).downstream = {
-          bindings: lVal.left.extra.binding,
-          excludeProperties: undefined,
-        };
+        setBindingDownstream(
+          lVal.left.extra.binding,
+          (lVal.right.extra ??= {}),
+        );
       }
       break;
   }
@@ -734,18 +730,6 @@ export function finalizeReferences() {
     }
   }
 
-  for (const [fn, reads] of readsByFn) {
-    fn.referencedBindingsInFunction = resolveReferencedBindings(
-      fn,
-      reads,
-      intersectionsBySection,
-    );
-
-    forEach(fn.referencedBindingsInFunction, (binding) =>
-      forceBindingSerialize(binding.section, binding),
-    );
-  }
-
   for (const binding of bindings) {
     if (binding.type !== BindingType.dom && !binding.upstreamAlias) {
       pruneBinding(bindings, binding);
@@ -1080,6 +1064,19 @@ export function finalizeReferences() {
   });
 
   finalizeFunctionRegistry();
+  for (const [fn, reads] of readsByFn) {
+    fn.referencedBindingsInFunction = resolveReferencedBindings(
+      fn,
+      reads,
+      intersectionsBySection,
+    );
+    if (fn.registerId) {
+      forEach(fn.referencedBindingsInFunction, (binding) =>
+        forceBindingSerialize(binding.section, binding),
+      );
+    }
+  }
+
   mergedReferences.clear();
   readsByExpression.clear();
   readsByFn.clear();
@@ -1111,11 +1108,16 @@ export const intersectionMeta = new WeakMap<
   { id: number; scopeOffset: Binding | undefined }
 >();
 
-export function setBindingValueExpr(
+export function setBindingDownstream(
   binding: Binding,
-  valueExpr: boolean | Opt<t.NodeExtra>,
+  expr: boolean | Opt<t.NodeExtra>,
 ) {
-  bindingValueExprs.set(binding, valueExpr || false);
+  bindingValueExprs.set(binding, expr || false);
+  if (expr && expr !== true) {
+    forEach(expr, (expr) => {
+      expr.downstream = bindingUtil.add(expr.downstream, binding);
+    });
+  }
 }
 
 const resolvedSources = new WeakSet<Binding>();
@@ -1635,6 +1637,59 @@ export function getCanonicalExtra<T extends t.NodeExtra>(extra: T): T {
   return extra;
 }
 
+const couldSerializeLookup = new WeakMap<t.NodeExtra | Binding, boolean>();
+export function couldSerializeExtra(extra: t.NodeExtra) {
+  let couldSerialize = couldSerializeLookup.get(extra);
+  if (couldSerialize === undefined) {
+    couldSerializeLookup.set(
+      extra,
+      (couldSerialize =
+        extra === getProgram().node.extra?.returnValueExpr ||
+        !!find(extra.downstream, couldSerializeBinding)),
+    );
+  }
+
+  return couldSerialize;
+}
+
+export function couldSerializeBinding(binding: Binding) {
+  let couldSerialize = couldSerializeLookup.get(binding);
+  if (couldSerialize === undefined) {
+    if (getBindingSerializeReason(binding.section, binding)) {
+      couldSerialize = true;
+    } else {
+      for (const expr of binding.downstreamExpressions) {
+        if (expr.isEffect || couldSerializeExtra(expr)) {
+          couldSerialize = true;
+          break;
+        }
+      }
+
+      if (!couldSerialize) {
+        for (const alias of binding.aliases) {
+          if (couldSerializeBinding(alias)) {
+            couldSerialize = true;
+            break;
+          }
+        }
+
+        if (!couldSerialize) {
+          for (const [, propBinding] of binding.propertyAliases) {
+            if (couldSerializeBinding(propBinding)) {
+              couldSerialize = true;
+              break;
+            }
+          }
+        }
+      }
+    }
+
+    couldSerializeLookup.set(binding, (couldSerialize ??= false));
+  }
+
+  return couldSerialize;
+}
+
 function setCanonicalExtra(extra: t.NodeExtra, merged: t.NodeExtra) {
   extra.merged = merged;
 }
diff --git a/packages/runtime-tags/src/translator/util/signals.ts b/packages/runtime-tags/src/translator/util/signals.ts
index 1d722216a1..504f6a30a5 100644
--- a/packages/runtime-tags/src/translator/util/signals.ts
+++ b/packages/runtime-tags/src/translator/util/signals.ts
@@ -505,7 +505,7 @@ export function getSignalFn(signal: Signal): t.Expression {
 
   if (isIntersection && signal.renderReferencedBindings) {
     signal.render.unshift(
-      t.variableDeclaration("const", [
+      t.variableDeclaration("let", [
         t.variableDeclarator(
           createScopeReadPattern(section, signal.renderReferencedBindings),
           scopeIdentifier,
diff --git a/packages/runtime-tags/src/translator/visitors/function.ts b/packages/runtime-tags/src/translator/visitors/function.ts
index 77f6b59027..16fc9b3f70 100644
--- a/packages/runtime-tags/src/translator/visitors/function.ts
+++ b/packages/runtime-tags/src/translator/visitors/function.ts
@@ -13,12 +13,11 @@ import {
 import { isCoreTagName } from "../util/is-core-tag";
 import isInvokedFunction from "../util/is-invoked-function";
 import {
-  type Binding,
+  couldSerializeExtra,
   getCanonicalExtra,
   type RegisteredFnExtra,
 } from "../util/references";
 import { getSection } from "../util/sections";
-import { getBindingSerializeReason } from "../util/serialize-reasons";
 import { createProgramState } from "../util/state";
 import analyzeTagNameType, { TagNameType } from "../util/tag-name-type";
 import type { TemplateVisitor } from "../util/visitors";
@@ -90,14 +89,9 @@ export default {
 
 export function finalizeFunctionRegistry() {
   for (const [fnExtra, exprExtras] of getReferencesByFn()) {
-    const seenExtras = new Set<t.NodeExtra>();
     let shouldRegister = false;
     for (const exprExtra of exprExtras) {
-      const refExtra = getCanonicalExtra(exprExtra);
-      if (seenExtras.has(refExtra)) continue;
-      seenExtras.add(refExtra);
-
-      if (couldSerializeDownstream(refExtra.downstream)) {
+      if (couldSerializeExtra(getCanonicalExtra(exprExtra))) {
         shouldRegister = true;
         break;
       }
@@ -109,48 +103,6 @@ export function finalizeFunctionRegistry() {
   }
 }
 
-function couldSerializeDownstream(downstream: t.NodeExtra["downstream"]) {
-  if (downstream) {
-    return Array.isArray(downstream.bindings)
-      ? downstream.bindings.some((binding) => couldSerializeBinding(binding))
-      : couldSerializeBinding(
-          downstream.bindings,
-          downstream.excludeProperties,
-        );
-  }
-
-  return false;
-}
-
-function couldSerializeBinding(
-  binding: Binding,
-  excludeProperties?: Set<string> | undefined,
-) {
-  if (getBindingSerializeReason(binding.section, binding)) {
-    return true;
-  }
-
-  for (const expr of binding.downstreamExpressions) {
-    if (expr.isEffect || couldSerializeDownstream(expr.downstream)) {
-      return true;
-    }
-  }
-
-  for (const alias of binding.aliases) {
-    if (couldSerializeBinding(alias)) {
-      return true;
-    }
-  }
-
-  for (const [name, propBinding] of binding.propertyAliases) {
-    if (!excludeProperties?.has(name) && couldSerializeBinding(propBinding)) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
 function canIgnoreRegister(
   markoRoot: MarkoExprRootPath,
   exprRoot: t.NodePath<t.Node>,
diff --git a/packages/runtime-tags/src/translator/visitors/tag/custom-tag.ts b/packages/runtime-tags/src/translator/visitors/tag/custom-tag.ts
index 2cec7d7bd8..6599b71da6 100644
--- a/packages/runtime-tags/src/translator/visitors/tag/custom-tag.ts
+++ b/packages/runtime-tags/src/translator/visitors/tag/custom-tag.ts
@@ -11,7 +11,7 @@ import {
 } from "@marko/compiler/babel-utils";
 import path from "path";
 
-import { generateUidIdentifier } from "../../util/generate-uid";
+import { generateUid, generateUidIdentifier } from "../../util/generate-uid";
 import { getTagName } from "../../util/get-tag-name";
 import { isOutputHTML } from "../../util/marko-config";
 import {
@@ -21,6 +21,7 @@ import {
 } from "../../util/nested-attribute-tags";
 import {
   filterMap,
+  forEach,
   fromIter,
   mapToString,
   type Opt,
@@ -36,7 +37,7 @@ import {
   getScopeAccessorLiteral,
   type InputBinding,
   mergeReferences,
-  setBindingValueExpr,
+  setBindingDownstream,
   trackParamsReferences,
   trackVarReferences,
 } from "../../util/references";
@@ -157,7 +158,7 @@ export default {
 
         if (varBinding) {
           const varSerializeReason = getProgram().node.extra.returnValueExpr;
-          setBindingValueExpr(varBinding, varSerializeReason);
+          setBindingDownstream(varBinding, varSerializeReason);
           addBindingSerializeReasonExpr(
             section,
             childScopeBinding,
@@ -186,7 +187,7 @@ export default {
             childInputBinding,
             inputExpr,
           );
-          setBindingValueExpr(varBinding, varSerializeReason);
+          setBindingDownstream(varBinding, varSerializeReason);
           addBindingSerializeReasonExpr(
             section,
             childScopeBinding,
@@ -557,10 +558,7 @@ function analyzeAttrs(
       getAllTagReferenceNodes(tag.node),
     ));
 
-    extra.downstream = {
-      bindings: templateExport.binding,
-      excludeProperties: undefined,
-    };
+    setBindingDownstream(templateExport.binding, extra);
     return;
   }
 
@@ -661,10 +659,9 @@ function analyzeAttrs(
       }
 
       if (bindings) {
-        groupExtra.downstream = {
-          bindings,
-          excludeProperties: undefined,
-        };
+        forEach(bindings, (binding) => {
+          setBindingDownstream(binding, groupExtra);
+        });
       }
 
       for (const name of group) {
@@ -697,10 +694,10 @@ function analyzeAttrs(
       }
 
       seen.add(attr.name);
-      (attr.value.extra ??= {}).downstream = {
-        bindings: templateExportAttr.binding,
-        excludeProperties: undefined,
-      };
+      setBindingDownstream(
+        templateExportAttr.binding,
+        (attr.value.extra ??= {}),
+      );
     }
 
     if (spreadReferenceNodes) {
@@ -720,10 +717,21 @@ function analyzeAttrs(
       tag.node,
       spreadReferenceNodes,
     ));
-    extra.downstream = {
-      bindings: templateExport.binding,
-      excludeProperties: seen,
-    };
+    let spreadBinding = templateExport.binding;
+    if (seen.size) {
+      spreadBinding = createBinding(
+        generateUid(`${getTagName(tag)}_attrs`),
+        spreadBinding.type,
+        spreadBinding.section,
+        spreadBinding,
+        undefined,
+        fromIter(seen),
+        spreadReferenceNodes[0].loc,
+        true,
+      );
+    }
+
+    setBindingDownstream(spreadBinding, extra);
   }
 }
 
diff --git a/packages/runtime-tags/src/translator/visitors/tag/dynamic-tag.ts b/packages/runtime-tags/src/translator/visitors/tag/dynamic-tag.ts
index 1dbfa750df..e5696f0811 100644
--- a/packages/runtime-tags/src/translator/visitors/tag/dynamic-tag.ts
+++ b/packages/runtime-tags/src/translator/visitors/tag/dynamic-tag.ts
@@ -241,7 +241,7 @@ export default {
             ]),
           );
           statements.push(
-            t.variableDeclaration("const", [
+            t.variableDeclaration("let", [
               t.variableDeclarator(node.var, dynamicTagExpr),
             ]),
             t.expressionStatement(


Test patch:
diff --git a/packages/runtime-tags/src/__tests__/fixtures/at-tags-for-loop-param-intersection-closure/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/at-tags-for-loop-param-intersection-closure/__snapshots__/dom.expected/template.hydrate.js
index bd8e2222bc..a7791a473d 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/at-tags-for-loop-param-intersection-closure/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/at-tags-for-loop-param-intersection-closure/__snapshots__/dom.expected/template.hydrate.js
@@ -1,6 +1,6 @@
-// size: 306 (min) 205 (brotli)
+// size: 304 (min) 204 (brotli)
 const $expr_mult_item$item$content = _$.intersection(1, ($scope) => {
-    const {
+    let {
       _: { 3: mult },
       5: item,
     } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/at-tags-for-loop-param-intersection-closure/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/at-tags-for-loop-param-intersection-closure/__snapshots__/dom.expected/template.js
index 7520d80b04..067c6a70d2 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/at-tags-for-loop-param-intersection-closure/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/at-tags-for-loop-param-intersection-closure/__snapshots__/dom.expected/template.js
@@ -3,7 +3,7 @@ export const $walks = /* over(1), beginChild, _list_walks, endChild, get, next(1
 import * as _$ from "@marko/runtime-tags/debug/dom";
 import { $setup as _list, $input_item as _list_input_item, $template as _list_template, $walks as _list_walks } from "./tags/list/index.marko";
 const $expr_mult_item$item$content = /* @__PURE__ */_$.intersection(1, $scope => {
-  const {
+  let {
     _: {
       mult
     },
diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/attr-class/__snapshots__/dom.expected/template.js
index 4f98b47b5f..1031c2ccb0 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/attr-class/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class/__snapshots__/dom.expected/template.js
@@ -7,7 +7,7 @@ import { $setup as _customTag, $input_class as _customTag_input_class, $input_te
 const $test_content = _$.registerContent("__tests__/template.marko_1_renderer", "Hello", /* over(1) */"b");
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/3");
 const $expr_c_d = /* @__PURE__ */_$.intersection(8, $scope => {
-  const {
+  let {
     c,
     d
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-escape/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/attr-escape/__snapshots__/dom.expected/template.js
index dae689267b..a5f5fa28ad 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/attr-escape/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/attr-escape/__snapshots__/dom.expected/template.js
@@ -3,7 +3,7 @@ export const $walks = /* get, over(1) */" b";
 export const $setup = () => {};
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_input_foo_input_bar = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     input_foo,
     input_bar
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-converge-in-if/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/basic-converge-in-if/__snapshots__/dom.expected/template.js
index c3599b7b04..f350fb8160 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-converge-in-if/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-converge-in-if/__snapshots__/dom.expected/template.js
@@ -2,7 +2,7 @@ export const $template = "<!><!><!>";
 export const $walks = /* over(1), replace, over(2) */"b%c";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_a_b$if$content = /* @__PURE__ */_$.intersection(1, $scope => {
-  const {
+  let {
     _: {
       a,
       b
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-counter-multiplier/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/basic-counter-multiplier/__snapshots__/dom.expected/template.hydrate.js
index 85c7afc3ac..90cb197a8f 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-counter-multiplier/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-counter-multiplier/__snapshots__/dom.expected/template.hydrate.js
@@ -1,9 +1,9 @@
-// size: 307 (min) 179 (brotli)
+// size: 305 (min) 181 (brotli)
 const $multipliedCount = _$.value(7, ($scope, multipliedCount) =>
     _$.data($scope[3], multipliedCount),
   ),
   $expr_count_multiplier = _$.intersection(6, ($scope) => {
-    const { 4: count, 5: multiplier } = $scope;
+    let { 4: count, 5: multiplier } = $scope;
     $multipliedCount($scope, count * multiplier);
   }),
   $count_effect = _$.effect("a0", ($scope, { 4: count }) =>
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-counter-multiplier/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/basic-counter-multiplier/__snapshots__/dom.expected/template.js
index b1ef5381d9..0140e37675 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-counter-multiplier/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-counter-multiplier/__snapshots__/dom.expected/template.js
@@ -3,7 +3,7 @@ export const $walks = /* get, next(1), over(1), replace, out(1), get, over(1), n
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $multipliedCount = /* @__PURE__ */_$.value("multipliedCount", ($scope, multipliedCount) => _$.data($scope["#text/3"], multipliedCount));
 const $expr_count_multiplier = /* @__PURE__ */_$.intersection(6, $scope => {
-  const {
+  let {
     count,
     multiplier
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-inert-collapsible-tree/__snapshots__/dom.expected/tags/comments.js b/packages/runtime-tags/src/__tests__/fixtures/basic-inert-collapsible-tree/__snapshots__/dom.expected/tags/comments.js
index 810adbc202..4d08824aff 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-inert-collapsible-tree/__snapshots__/dom.expected/tags/comments.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-inert-collapsible-tree/__snapshots__/dom.expected/tags/comments.js
@@ -9,7 +9,7 @@ const $setup$if$content = $scope => {
   $id$if$content._($scope);
 };
 const $expr_comment_comments_id$if$content = /* @__PURE__ */_$.intersection(1, $scope => {
-  const {
+  let {
     _: {
       comment_comments,
       id
@@ -28,7 +28,7 @@ const $id$for$content = /* @__PURE__ */_$.value("id", ($scope, id) => {
   $id$if$content($scope);
 });
 const $expr_input_path_i$for$content = /* @__PURE__ */_$.intersection(10, $scope => {
-  const {
+  let {
     _: {
       input_path
     },
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-member-expression-computed/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/basic-member-expression-computed/__snapshots__/dom.expected/template.hydrate.js
index c4808a112a..509a2e1739 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-member-expression-computed/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-member-expression-computed/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 277 (min) 192 (brotli)
+// size: 275 (min) 194 (brotli)
 const $expr_items_index_effect = _$.effect(
     "a0",
     ($scope, { 3: items, 5: index }) =>
@@ -9,7 +9,7 @@ const $expr_items_index_effect = _$.effect(
       }),
   ),
   $expr_items_index = _$.intersection(6, ($scope) => {
-    const { 3: items, 5: index } = $scope;
+    let { 3: items, 5: index } = $scope;
     (_$.data($scope[1], items[index]), $expr_items_index_effect($scope));
   }),
   $items = _$.state(3, ($scope, items) => {
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-member-expression-computed/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/basic-member-expression-computed/__snapshots__/dom.expected/template.js
index 4515ddcc42..e4c8565efe 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-member-expression-computed/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-member-expression-computed/__snapshots__/dom.expected/template.js
@@ -10,7 +10,7 @@ const $expr_items_index_effect = _$.effect("__tests__/template.marko_0_items_ind
   $index($scope, index = (index + 1) % newItems.length);
 }));
 const $expr_items_index = /* @__PURE__ */_$.intersection(6, $scope => {
-  const {
+  let {
     items,
     index
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-for/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-for/__snapshots__/dom.expected/template.hydrate.js
index eb9b7cdbcd..56f02f70fe 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-for/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-for/__snapshots__/dom.expected/template.hydrate.js
@@ -1,10 +1,10 @@
-// size: 528 (min) 302 (brotli)
+// size: 526 (min) 301 (brotli)
 const $name = _$.value(3, ($scope, name) => _$.data($scope[0], name)),
   $setup$for$content = ($scope) => {
     ($scope[0], $outer$for$content._($scope));
   },
   $expr_outer_inner$for$content = _$.intersection(3, ($scope) => {
-    const {
+    let {
       _: { 2: outer },
       2: inner,
     } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-for/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-for/__snapshots__/dom.expected/template.js
index 921336206b..c742665a74 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-for/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-for/__snapshots__/dom.expected/template.js
@@ -7,7 +7,7 @@ const $setup$for$content = $scope => {
   $outer$for$content._($scope);
 };
 const $expr_outer_inner$for$content = /* @__PURE__ */_$.intersection(3, $scope => {
-  const {
+  let {
     _: {
       outer
     },
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-params/__snapshots__/dom.expected/tags/child.js b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-params/__snapshots__/dom.expected/tags/child.js
index 44f7cca2af..fe74494072 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-params/__snapshots__/dom.expected/tags/child.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-params/__snapshots__/dom.expected/tags/child.js
@@ -4,7 +4,7 @@ export const $setup = () => {};
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0", 0, 0, 1);
 const $expr_content_value = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     content,
     value
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-params/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-params/__snapshots__/dom.expected/template.hydrate.js
index d92a127e05..3569694576 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-params/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-params/__snapshots__/dom.expected/template.hydrate.js
@@ -1,7 +1,7 @@
-// size: 597 (min) 333 (brotli)
+// size: 595 (min) 322 (brotli)
 const $dynamicTag = _$.dynamicTag(0, 0, 0, 1),
   $expr_content_value = _$.intersection(5, ($scope) => {
-    const { 3: content, 4: value } = $scope;
+    let { 3: content, 4: value } = $scope;
     $dynamicTag($scope, content, () => [value]);
   }),
   $content = _$.value(3, $expr_content_value),
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-scope-for/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-scope-for/__snapshots__/dom.expected/template.hydrate.js
index abf9a0d993..cee72599cc 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-scope-for/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-scope-for/__snapshots__/dom.expected/template.hydrate.js
@@ -1,6 +1,6 @@
-// size: 238 (min) 164 (brotli)
+// size: 236 (min) 169 (brotli)
 const $expr_selected_num$for$content = _$.intersection(4, ($scope) => {
-  const {
+  let {
     _: { 1: selected },
     3: num,
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-scope-for/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-scope-for/__snapshots__/dom.expected/template.js
index c90df86b55..dcda2e2bb5 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/basic-nested-scope-for/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/basic-nested-scope-for/__snapshots__/dom.expected/template.js
@@ -2,7 +2,7 @@ export const $template = "<!><!><!>";
 export const $walks = /* over(1), replace, over(2) */"b%c";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_selected_num$for$content = /* @__PURE__ */_$.intersection(4, $scope => {
-  const {
+  let {
     _: {
       selected
     },
diff --git a/packages/runtime-tags/src/__tests__/fixtures/batched-updates/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/batched-updates/__snapshots__/dom.expected/template.hydrate.js
index c53b74951e..6c6435ad72 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/batched-updates/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/batched-updates/__snapshots__/dom.expected/template.hydrate.js
@@ -1,11 +1,11 @@
-// size: 185 (min) 140 (brotli)
+// size: 183 (min) 142 (brotli)
 const $expr_a_b_effect = _$.effect("a0", ($scope, { 2: a, 3: b }) =>
     _$.on($scope[0], "click", function () {
       ($a($scope, ++a), $b($scope, ++b));
     }),
   ),
   $expr_a_b = _$.intersection(4, ($scope) => {
-    const { 2: a, 3: b } = $scope;
+    let { 2: a, 3: b } = $scope;
     (_$.data($scope[1], a + b), $expr_a_b_effect($scope));
   }),
   $a = _$.state(2, $expr_a_b),
diff --git a/packages/runtime-tags/src/__tests__/fixtures/batched-updates/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/batched-updates/__snapshots__/dom.expected/template.js
index 2155c733d8..a8a5583c59 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/batched-updates/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/batched-updates/__snapshots__/dom.expected/template.js
@@ -9,7 +9,7 @@ const $expr_a_b_effect = _$.effect("__tests__/template.marko_0_a_b", ($scope, {
   $b($scope, ++b)
 }));
 const $expr_a_b = /* @__PURE__ */_$.intersection(4, $scope => {
-  const {
+  let {
     a,
     b
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/cleanup-single-child-for-deep/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/cleanup-single-child-for-deep/__snapshots__/dom.expected/template.hydrate.js
index 2d0ab0c7a6..b4d0ccc2f7 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/cleanup-single-child-for-deep/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/cleanup-single-child-for-deep/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 959 (min) 467 (brotli)
+// size: 957 (min) 469 (brotli)
 const $expr_name_write_effect = _$.effect(
     "a0",
     ($scope, { 3: name, 4: write }) =>
@@ -22,7 +22,7 @@ const $expr_name_write_effect = _$.effect(
     ($scope) => $scope._._,
   ),
   $expr_outerItem_middleItem$for$content = _$.intersection(3, ($scope) => {
-    const {
+    let {
       _: { 3: outerItem },
       2: middleItem,
     } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/cleanup-single-child-for-deep/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/cleanup-single-child-for-deep/__snapshots__/dom.expected/template.js
index a1abb2c991..98c2de9020 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/cleanup-single-child-for-deep/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/cleanup-single-child-for-deep/__snapshots__/dom.expected/template.js
@@ -9,7 +9,7 @@ const $setup$for$content2 = $scope => {
 };
 const $write$for$content2 = /* @__PURE__ */_$.dynamicClosureRead("write", ($scope, write) => _child_input_write($scope["#childScope/0"], write), $scope => $scope._._);
 const $expr_outerItem_middleItem$for$content = /* @__PURE__ */_$.intersection(3, $scope => {
-  const {
+  let {
     _: {
       outerItem
     },
diff --git a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-import-value/__snapshots__/dom.expected/tags/counter.js b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-import-value/__snapshots__/dom.expected/tags/counter.js
index 95105101e2..d1b0a84d6c 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-import-value/__snapshots__/dom.expected/tags/counter.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-import-value/__snapshots__/dom.expected/tags/counter.js
@@ -2,7 +2,7 @@ export const $template = "<button> </button>";
 export const $walks = /* get, next(1), get, out(1) */" D l";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_input_count = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     input,
     count
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-intersection/__snapshots__/dom.expected/tags/display-intersection.js b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-intersection/__snapshots__/dom.expected/tags/display-intersection.js
index c8f7233de3..583a92bcb3 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-intersection/__snapshots__/dom.expected/tags/display-intersection.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-intersection/__snapshots__/dom.expected/tags/display-intersection.js
@@ -2,7 +2,7 @@ export const $template = "<div> </div>";
 export const $walks = /* next(1), get, out(1) */"D l";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_value_dummy = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     value,
     dummy
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-intersection/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-intersection/__snapshots__/dom.expected/template.hydrate.js
index ed6bbdb11e..3fa8a59ed8 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-intersection/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-intersection/__snapshots__/dom.expected/template.hydrate.js
@@ -1,6 +1,6 @@
-// size: 187 (min) 145 (brotli)
+// size: 185 (min) 149 (brotli)
 const $expr_value_dummy = _$.intersection(5, ($scope) => {
-    const { 3: value, 4: dummy } = $scope;
+    let { 3: value, 4: dummy } = $scope;
     _$.data($scope[0], value);
   }),
   $value = _$.value(3, $expr_value_dummy),
diff --git a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-static-code/__snapshots__/dom.expected/tags/counter.js b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-static-code/__snapshots__/dom.expected/tags/counter.js
index 95105101e2..d1b0a84d6c 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-static-code/__snapshots__/dom.expected/tags/counter.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-static-code/__snapshots__/dom.expected/tags/counter.js
@@ -2,7 +2,7 @@ export const $template = "<button> </button>";
 export const $walks = /* get, next(1), get, out(1) */" D l";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_input_count = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     input,
     count
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-static-code/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-static-code/__snapshots__/dom.expected/template.hydrate.js
index 2f1155ab10..10e0c34b98 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/component-attrs-static-code/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/component-attrs-static-code/__snapshots__/dom.expected/template.hydrate.js
@@ -1,6 +1,6 @@
-// size: 279 (min) 176 (brotli)
+// size: 277 (min) 175 (brotli)
 const $expr_input_count = _$.intersection(5, ($scope) => {
-    const { 3: input, 4: count } = $scope;
+    let { 3: input, 4: count } = $scope;
     _$.data($scope[1], input.format(count));
   }),
   $count_effect = _$.effect("a0", ($scope, { 4: count }) =>
diff --git a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-value/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-value/__snapshots__/dom.expected/template.hydrate.js
index 6638fd5dda..3f20258241 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-value/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-value/__snapshots__/dom.expected/template.hydrate.js
@@ -1,6 +1,6 @@
-// size: 442 (min) 177 (brotli)
+// size: 440 (min) 178 (brotli)
 const $expr_checkedValue_$checkedValueChange = _$.intersection(6, ($scope) => {
-    const { 4: checkedValue, 5: $checkedValueChange } = $scope;
+    let { 4: checkedValue, 5: $checkedValueChange } = $scope;
     (_$.controllable_input_checkedValue(
       $scope,
       0,
diff --git a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-value/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-value/__snapshots__/dom.expected/template.js
index 7e8b45d843..ecd78f5124 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-value/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-value/__snapshots__/dom.expected/template.js
@@ -2,7 +2,7 @@ export const $template = "<input type=radio><input type=radio><input type=radio>
 export const $walks = /* get, over(1), get, over(1), get, over(1), next(1), get, out(1) */" b b bD l";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_checkedValue_$checkedValueChange = /* @__PURE__ */_$.intersection(6, $scope => {
-  const {
+  let {
     checkedValue,
     $checkedValueChange
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values-spread/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values-spread/__snapshots__/dom.expected/template.hydrate.js
index 61913519ad..1ffbaedd57 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values-spread/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values-spread/__snapshots__/dom.expected/template.hydrate.js
@@ -1,11 +1,11 @@
-// size: 413 (min) 211 (brotli)
+// size: 411 (min) 211 (brotli)
 const $input_effect = _$.effect("a0", ($scope) => _$.attrsEvents($scope, 0)),
   $input = _$.value(2, ($scope, input) => {
     (_$.attrs($scope, 0, { type: "checkbox", ...input }),
       $input_effect($scope));
   }),
   $expr_checkedValue_$checkedValueChange = _$.intersection(6, ($scope) => {
-    const { 4: checkedValue, 5: $checkedValueChange } = $scope;
+    let { 4: checkedValue, 5: $checkedValueChange } = $scope;
     ($input($scope[0], {
       checkedValue: checkedValue,
       checkedValueChange: $checkedValueChange,
diff --git a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values-spread/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values-spread/__snapshots__/dom.expected/template.js
index ffd0741994..6e40d68913 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values-spread/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values-spread/__snapshots__/dom.expected/template.js
@@ -3,7 +3,7 @@ export const $walks = /* beginChild, _checkbox_walks, endChild, beginChild, _che
 import { $setup as _checkbox, $input as _checkbox_input, $template as _checkbox_template, $walks as _checkbox_walks } from "./tags/checkbox.marko";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_checkedValue_$checkedValueChange = /* @__PURE__ */_$.intersection(6, $scope => {
-  const {
+  let {
     checkedValue,
     $checkedValueChange
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values/__snapshots__/dom.expected/template.hydrate.js
index 6638fd5dda..3f20258241 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values/__snapshots__/dom.expected/template.hydrate.js
@@ -1,6 +1,6 @@
-// size: 442 (min) 177 (brotli)
+// size: 440 (min) 178 (brotli)
 const $expr_checkedValue_$checkedValueChange = _$.intersection(6, ($scope) => {
-    const { 4: checkedValue, 5: $checkedValueChange } = $scope;
+    let { 4: checkedValue, 5: $checkedValueChange } = $scope;
     (_$.controllable_input_checkedValue(
       $scope,
       0,
diff --git a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values/__snapshots__/dom.expected/template.js
index b2c0648d5d..049fb4e39b 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/controllable-checked-values/__snapshots__/dom.expected/template.js
@@ -2,7 +2,7 @@ export const $template = "<input type=checkbox><input type=checkbox><input type=
 export const $walks = /* get, over(1), get, over(1), get, over(1), next(1), get, out(1) */" b b bD l";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_checkedValue_$checkedValueChange = /* @__PURE__ */_$.intersection(6, $scope => {
-  const {
+  let {
     checkedValue,
     $checkedValueChange
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/controllable-select-dynamic-spread/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/controllable-select-dynamic-spread/__snapshots__/dom.expected/template.hydrate.js
index 4276e61b84..1e51aedf19 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/controllable-select-dynamic-spread/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/controllable-select-dynamic-spread/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 482 (min) 239 (brotli)
+// size: 480 (min) 238 (brotli)
 const $setup$tagselect$content_effect = _$.effect("a2", ($scope) => {
     (_$.attrsEvents($scope, 0),
       _$.attrsEvents($scope, 1),
@@ -17,7 +17,7 @@ const $setup$tagselect$content_effect = _$.effect("a2", ($scope) => {
   ),
   $dynamicTag = _$.dynamicTag(0, $tagselect_content),
   $expr_value_tag = _$.intersection(4, ($scope) => {
-    const { 2: value, 3: tag } = $scope;
+    let { 2: value, 3: tag } = $scope;
     $dynamicTag($scope, tag ? "select" : {}, () => ({
       value: value,
       valueChange: $valueChange($scope),
diff --git a/packages/runtime-tags/src/__tests__/fixtures/controllable-select-dynamic-spread/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/controllable-select-dynamic-spread/__snapshots__/dom.expected/template.js
index 619aebbbdc..fc06f92286 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/controllable-select-dynamic-spread/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/controllable-select-dynamic-spread/__snapshots__/dom.expected/template.js
@@ -21,7 +21,7 @@ const $setup$tagselect$content = $scope => {
 const $tagselect_content = _$.registerContent("__tests__/template.marko_1_renderer", "<option>A</option><option>B</option><option>C</option>", /* get, over(1), get, over(1), get, over(1) */" b b b", $setup$tagselect$content);
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0", $tagselect_content);
 const $expr_value_tag = /* @__PURE__ */_$.intersection(4, $scope => {
-  const {
+  let {
     value,
     tag
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/counter-intersection/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/counter-intersection/__snapshots__/dom.expected/template.hydrate.js
index 53a111ef67..c33fd41762 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/counter-intersection/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/counter-intersection/__snapshots__/dom.expected/template.hydrate.js
@@ -1,6 +1,6 @@
-// size: 250 (min) 141 (brotli)
+// size: 248 (min) 141 (brotli)
 const $expr_a_b = _$.intersection(7, ($scope) => {
-    const { 5: a, 6: b } = $scope;
+    let { 5: a, 6: b } = $scope;
     _$.data($scope[4], a + b);
   }),
   $a = _$.state(5, ($scope, a) => {
diff --git a/packages/runtime-tags/src/__tests__/fixtures/counter-intersection/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/counter-intersection/__snapshots__/dom.expected/template.js
index 05a87a32e5..f4dfb7987b 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/counter-intersection/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/counter-intersection/__snapshots__/dom.expected/template.js
@@ -2,7 +2,7 @@ export const $template = "<div><button class=a> </button> + <button class=b> </b
 export const $walks = /* next(1), get, next(1), get, out(1), over(1), get, next(1), get, out(1), over(1), replace, out(1) */"D D lb D lb%l";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_a_b = /* @__PURE__ */_$.intersection(7, $scope => {
-  const {
+  let {
     a,
     b
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/create-and-clear-rows-loop-from/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/create-and-clear-rows-loop-from/__snapshots__/dom.expected/template.js
index 85d1abf204..0b086207ad 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/create-and-clear-rows-loop-from/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/create-and-clear-rows-loop-from/__snapshots__/dom.expected/template.js
@@ -7,7 +7,7 @@ const $params2$for$content = /* @__PURE__ */_$.value("$params2", ($scope, $param
 const $for_content = /* @__PURE__ */_$.createRenderer("<!>, ", /* replace, over(2) */"%c", 0, $params2$for$content);
 const $for = /* @__PURE__ */_$.loopTo("#div/0", $for_content);
 const $expr_input_from_input_to_input_step = /* @__PURE__ */_$.intersection(6, $scope => {
-  const {
+  let {
     input_from,
     input_to,
     input_step
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/tags/custom-tag.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/tags/custom-tag.js
index f3e54fc173..1d32fcdff4 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/tags/custom-tag.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/tags/custom-tag.js
@@ -11,7 +11,7 @@ const $expr_x_y_effect = _$.effect("__tests__/tags/custom-tag.marko_0_x_y", ($sc
 const $expr_x_y = /* @__PURE__ */_$.intersection(9, $expr_x_y_effect);
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/3", 0, 0, 1);
 const $expr_input_content_x_y = /* @__PURE__ */_$.intersection(10, $scope => {
-  const {
+  let {
     input_content,
     x,
     y
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/template.hydrate.js
index c9b664f3db..25f06138ec 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 475 (min) 272 (brotli)
+// size: 473 (min) 270 (brotli)
 const $expr_x_y_effect = _$.effect("a0", ($scope, { 7: x, 8: y }) =>
     _$.on($scope[0], "click", function () {
       ($x($scope, ++x), $y($scope, ++y));
@@ -9,7 +9,7 @@ const $expr_x_y_effect = _$.effect("a0", ($scope, { 7: x, 8: y }) =>
   $expr_input_content_x_y = _$.intersection(
     10,
     ($scope) => {
-      const { 6: input_content, 7: x, 8: y } = $scope;
+      let { 6: input_content, 7: x, 8: y } = $scope;
       $dynamicTag($scope, input_content, () => [x, y]);
     },
     2,
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-attributes/__snapshots__/dom.expected/tags/custom-tag.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-attributes/__snapshots__/dom.expected/tags/custom-tag.js
index 2d61e35767..ddcfe8f9df 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-attributes/__snapshots__/dom.expected/tags/custom-tag.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-attributes/__snapshots__/dom.expected/tags/custom-tag.js
@@ -3,7 +3,7 @@ export const $walks = /* get, next(1), get, out(1), replace, over(2) */" D l%c";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/2");
 const $expr_input_content_input_name_x = /* @__PURE__ */_$.intersection(8, $scope => {
-  const {
+  let {
     input_content,
     input_name,
     x
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-attributes/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-attributes/__snapshots__/dom.expected/template.hydrate.js
index 446eea2c3d..41ede724af 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-attributes/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-attributes/__snapshots__/dom.expected/template.hydrate.js
@@ -1,9 +1,9 @@
-// size: 437 (min) 287 (brotli)
+// size: 435 (min) 273 (brotli)
 const $dynamicTag = _$.dynamicTag(2),
   $expr_input_content_input_name_x = _$.intersection(
     8,
     ($scope) => {
-      const { 5: input_content, 6: input_name, 7: x } = $scope;
+      let { 5: input_content, 6: input_name, 7: x } = $scope;
       $dynamicTag($scope, input_content, () => ({
         count: x,
         name: input_name,
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-single-arg/__snapshots__/dom.expected/tags/custom-tag.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-single-arg/__snapshots__/dom.expected/tags/custom-tag.js
index c039e14531..e411c75931 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-single-arg/__snapshots__/dom.expected/tags/custom-tag.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-single-arg/__snapshots__/dom.expected/tags/custom-tag.js
@@ -3,7 +3,7 @@ export const $walks = /* get, next(1), get, out(1), replace, over(2) */" D l%c";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/2", 0, 0, 1);
 const $expr_input_content_x = /* @__PURE__ */_$.intersection(7, $scope => {
-  const {
+  let {
     input_content,
     x
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-single-arg/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-single-arg/__snapshots__/dom.expected/template.hydrate.js
index a8c6f17d4c..f3622b5666 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-single-arg/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-parameters-from-single-arg/__snapshots__/dom.expected/template.hydrate.js
@@ -1,7 +1,7 @@
-// size: 330 (min) 227 (brotli)
+// size: 328 (min) 227 (brotli)
 const $dynamicTag = _$.dynamicTag(2, 0, 0, 1),
   $expr_input_content_x = _$.intersection(7, ($scope) => {
-    const { 5: input_content, 6: x } = $scope;
+    let { 5: input_content, 6: x } = $scope;
     $dynamicTag($scope, input_content, () => [x]);
   }),
   $x_effect = _$.effect("a0", ($scope, { 6: x }) =>
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/tags/child.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/tags/child.js
index 366506a371..162d32d06e 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/tags/child.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/tags/child.js
@@ -2,7 +2,7 @@ export const $template = "<button class=inc> </button>";
 export const $walks = /* get, next(1), get, out(1) */" D l";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_input_extra_x = /* @__PURE__ */_$.intersection(6, $scope => {
-  const {
+  let {
     input_extra,
     x
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/template.hydrate.js
index 05a0e43741..a383b57a63 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/template.hydrate.js
@@ -1,6 +1,6 @@
-// size: 328 (min) 216 (brotli)
+// size: 324 (min) 214 (brotli)
 const $expr_input_extra_x = _$.intersection(6, ($scope) => {
-    const { 4: input_extra, 5: x } = $scope;
+    let { 4: input_extra, 5: x } = $scope;
     _$.tagVarSignal($scope, x + input_extra);
   }),
   $x_effect = _$.effect("a0", ($scope, { 5: x }) =>
@@ -15,7 +15,7 @@ const $expr_input_extra_x = _$.intersection(6, ($scope) => {
   $expr_name_data = _$.intersection(
     5,
     ($scope) => {
-      const { 3: name, 4: data } = $scope;
+      let { 3: name, 4: data } = $scope;
       $message($scope, `${name} ${data}`);
     },
     1,
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/template.js
index 12dd2487e3..4748d4587a 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-intersection/__snapshots__/dom.expected/template.js
@@ -4,7 +4,7 @@ import { $setup as _child, $input_extra as _child_input_extra, $template as _chi
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $message = /* @__PURE__ */_$.value("message", ($scope, message) => _$.data($scope["#text/2"], message));
 const $expr_name_data = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     name,
     data
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-multiple/__snapshots__/dom.expected/tags/child.js b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-multiple/__snapshots__/dom.expected/tags/child.js
index fb274b3cb8..efb302461b 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-multiple/__snapshots__/dom.expected/tags/child.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/custom-tag-var-multiple/__snapshots__/dom.expected/tags/child.js
@@ -2,7 +2,7 @@ export const $template = "<span>child</span>";
 export const $walks = /* over(1) */"b";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_x_y = /* @__PURE__ */_$.intersection(2, $scope => {
-  const {
+  let {
     x,
     y
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-args/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-args/__snapshots__/dom.expected/template.hydrate.js
index 04d82bc6d8..37ebec434f 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-args/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-args/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 442 (min) 250 (brotli)
+// size: 440 (min) 252 (brotli)
 const $a$define$content = _$.value(4, ($scope, a) => _$.data($scope[0], a)),
   $b$define$content = _$.value(5, ($scope, b) => _$.data($scope[1], b)),
   $c$define$content = _$.value(6, ($scope, c) => _$.data($scope[2], c)),
@@ -16,7 +16,7 @@ _$.registerContent(
 );
 const $dynamicTag = _$.dynamicTag(0, 0, 0, 1),
   $expr_x_MyTag = _$.intersection(5, ($scope) => {
-    const { 3: x, 4: MyTag } = $scope;
+    let { 3: x, 4: MyTag } = $scope;
     $dynamicTag($scope, MyTag, () => [1, "Hello", x]);
   }),
   $x_effect = _$.effect("a1", ($scope, { 3: x }) =>
diff --git a/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-args/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-args/__snapshots__/dom.expected/template.js
index 30324a23ce..4cdf4dc5f6 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-args/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-args/__snapshots__/dom.expected/template.js
@@ -12,7 +12,7 @@ const $params2$define$content = /* @__PURE__ */_$.value("$params2", ($scope, $pa
 const $define_content = _$.registerContent("__tests__/template.marko_1_renderer", "<div><!>|<!>|<!></div>", /* next(1), replace, over(2), replace, over(2), replace, out(1) */"D%c%c%l", 0, $params2$define$content);
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0", 0, 0, 1);
 const $expr_x_MyTag = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     x,
     MyTag
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-attr-signal/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-attr-signal/__snapshots__/dom.expected/template.hydrate.js
index fa6b1c5889..cb77af0127 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-attr-signal/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-attr-signal/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 365 (min) 228 (brotli)
+// size: 363 (min) 230 (brotli)
 const $number$define$content = _$.value(3, ($scope, number) =>
     _$.data($scope[0], number),
   ),
@@ -11,7 +11,7 @@ const $number$define$content = _$.value(3, ($scope, number) =>
 _$.registerContent("a0", "<div> </div>", "D l", 0, $params2$define$content);
 const $dynamicTag = _$.dynamicTag(0),
   $expr_x_MyTag = _$.intersection(5, ($scope) => {
-    const { 3: x, 4: MyTag } = $scope;
+    let { 3: x, 4: MyTag } = $scope;
     $dynamicTag($scope, MyTag, () => ({ number: x }));
   }),
   $x_effect = _$.effect("a1", ($scope, { 3: x }) =>
diff --git a/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-attr-signal/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-attr-signal/__snapshots__/dom.expected/template.js
index 0c638e46f9..edafe3cee4 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-attr-signal/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/define-tag-render-attr-signal/__snapshots__/dom.expected/template.js
@@ -7,7 +7,7 @@ const $temp$define$content = /* @__PURE__ */_$.value("$temp", ($scope, $temp) =>
 const $define_content = _$.registerContent("__tests__/template.marko_1_renderer", "<div> </div>", /* next(1), get, out(1) */"D l", 0, $params2$define$content);
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0");
 const $expr_x_MyTag = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     x,
     MyTag
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/destructure-and-member-intersection/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/destructure-and-member-intersection/__snapshots__/dom.expected/template.js
index db09a56151..a71707ca9a 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/destructure-and-member-intersection/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/destructure-and-member-intersection/__snapshots__/dom.expected/template.js
@@ -3,7 +3,7 @@ export const $walks = /* next(1), replace, over(1), replace, out(1) */"D%b%l";
 export const $setup = () => {};
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_a_b = /* @__PURE__ */_$.intersection(7, $scope => {
-  const {
+  let {
     input_a: a,
     b
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-content-attr/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-content-attr/__snapshots__/dom.expected/template.hydrate.js
index 5d949b5d07..6d63ed0166 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-content-attr/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-content-attr/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 328 (min) 212 (brotli)
+// size: 326 (min) 213 (brotli)
 let sideEffect = 3;
 const $count$define$content = _$.dynamicClosureRead(1, ($scope, count) =>
   _$.data($scope[0], count),
@@ -7,7 +7,7 @@ _$.registerContent("a0", "<!> <!>", "%c%b", ($scope) => {
   (_$.data($scope[1], sideEffect++), $count$define$content($scope));
 });
 const $expr_count_MyThing = _$.intersection(3, ($scope) => {
-    const { 1: count, 2: MyThing } = $scope;
+    let { 1: count, 2: MyThing } = $scope;
     _$.insertContent($scope, 0, MyThing);
   }),
   $count_closure = _$.dynamicClosure($count$define$content),
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-content-attr/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-content-attr/__snapshots__/dom.expected/template.js
index 34fb2c8bf0..1f2ccb6b40 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-content-attr/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-content-attr/__snapshots__/dom.expected/template.js
@@ -10,7 +10,7 @@ const $setup$define$content = $scope => {
 const $count$define$content = /* @__PURE__ */_$.dynamicClosureRead("count", ($scope, count) => _$.data($scope["#text/0"], count));
 const $define_content = _$.registerContent("__tests__/template.marko_1_renderer", "<!> <!>", /* replace, over(2), replace, over(1) */"%c%b", $setup$define$content);
 const $expr_count_MyThing = /* @__PURE__ */_$.intersection(3, $scope => {
-  const {
+  let {
     count,
     MyThing
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-native-dynamic-tag/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-native-dynamic-tag/__snapshots__/dom.expected/template.hydrate.js
index 55e07c0a97..49ef070fc7 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-native-dynamic-tag/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-native-dynamic-tag/__snapshots__/dom.expected/template.hydrate.js
@@ -1,8 +1,8 @@
-// size: 258 (min) 175 (brotli)
+// size: 256 (min) 176 (brotli)
 const $tagName_content = _$.registerContent("a0", "body content", "b"),
   $dynamicTag = _$.dynamicTag(0, $tagName_content),
   $expr_tagName_className = _$.intersection(4, ($scope) => {
-    const { 2: tagName, 3: className } = $scope;
+    let { 2: tagName, 3: className } = $scope;
     $dynamicTag($scope, tagName, () => ({ class: className }));
   }),
   $tagName_effect = _$.effect("a1", ($scope, { 2: tagName }) =>
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-native-dynamic-tag/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-native-dynamic-tag/__snapshots__/dom.expected/template.js
index 11d3442841..d5af5152ff 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-native-dynamic-tag/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-native-dynamic-tag/__snapshots__/dom.expected/template.js
@@ -4,7 +4,7 @@ import * as _$ from "@marko/runtime-tags/debug/dom";
 const $tagName_content = _$.registerContent("__tests__/template.marko_1_renderer", "body content", /* over(1) */"b");
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0", $tagName_content);
 const $expr_tagName_className = /* @__PURE__ */_$.intersection(4, $scope => {
-  const {
+  let {
     tagName,
     className
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-args-tag-var/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-args-tag-var/__snapshots__/html.expected/template.js
index bf68ae5210..4622ac22a9 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-args-tag-var/__snapshots__/html.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-args-tag-var/__snapshots__/html.expected/template.js
@@ -6,7 +6,7 @@ export default _$.createTemplate("__tests__/template.marko", input => {
   let x = 1;
   _$.write(`<button>Count: <!>${_$.escapeXML(x)}${_$.markResumeNode($scope0_id, "#text/1")}</button>${_$.markResumeNode($scope0_id, "#button/0")}`);
   const $tags0_scope = _$.peekNextScopeId();
-  const y = _$.dynamicTag($scope0_id, "#text/2", tags[0], [x], 0, 1);
+  let y = _$.dynamicTag($scope0_id, "#text/2", tags[0], [x], 0, 1);
   _$.setTagVar($scope0_id, "#scopeOffset/3", $tags0_scope, "__tests__/template.marko_0_y/var");
   _$.write(`<div>Parent: <!>${_$.escapeXML(y)}${_$.markResumeNode($scope0_id, "#text/4")}</div>`);
   _$.writeEffect($scope0_id, "__tests__/template.marko_0_x");
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-custom-tags/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-custom-tags/__snapshots__/dom.expected/template.hydrate.js
index 5315790215..627e10e22c 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-custom-tags/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-custom-tags/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 499 (min) 253 (brotli)
+// size: 497 (min) 253 (brotli)
 const $setup$1 = () => {},
   $value$1 = _$.value(3, ($scope, value) => _$.data($scope[0], value)),
   $input$1 = _$.value(2, ($scope, input) => $value$1($scope, input.value));
@@ -21,7 +21,7 @@ var child2 = _$.createTemplate(
 );
 const $dynamicTag = _$.dynamicTag(0),
   $expr_tagName_val = _$.intersection(4, ($scope) => {
-    const { 2: tagName, 3: val } = $scope;
+    let { 2: tagName, 3: val } = $scope;
     $dynamicTag($scope, tagName, () => ({ value: val }));
   }),
   $tagName_effect = _$.effect("c0", ($scope, { 2: tagName }) =>
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-custom-tags/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-custom-tags/__snapshots__/dom.expected/template.js
index ece9c6690d..54a8e0fd8c 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-custom-tags/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-custom-tags/__snapshots__/dom.expected/template.js
@@ -5,7 +5,7 @@ import child2 from "./tags/child2.marko";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0");
 const $expr_tagName_val = /* @__PURE__ */_$.intersection(4, $scope => {
-  const {
+  let {
     tagName,
     val
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-input-intersection/__snapshots__/dom.expected/tags/my-tag.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-input-intersection/__snapshots__/dom.expected/tags/my-tag.js
index 64cefef621..e4031bbd34 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-input-intersection/__snapshots__/dom.expected/tags/my-tag.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-input-intersection/__snapshots__/dom.expected/tags/my-tag.js
@@ -4,7 +4,7 @@ import * as _$ from "@marko/runtime-tags/debug/dom";
 const $define_content = /* @__PURE__ */_$.createContent("__tests__/tags/my-tag.marko_1_renderer", "default", /* over(1) */"b");
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0");
 const $expr_inputAs_inputClass_htmlInput_content = /* @__PURE__ */_$.intersection(9, $scope => {
-  const {
+  let {
     inputAs,
     inputClass,
     htmlInput,
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-input-intersection/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-input-intersection/__snapshots__/dom.expected/template.hydrate.js
index 13ea72c8d8..5a2bff4421 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-input-intersection/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-input-intersection/__snapshots__/dom.expected/template.hydrate.js
@@ -1,9 +1,9 @@
-// size: 250 (min) 178 (brotli)
+// size: 248 (min) 181 (brotli)
 const $dynamicTag = _$.dynamicTag(0),
   $expr_inputAs_inputClass_htmlInput_content = _$.intersection(
     9,
     ($scope) => {
-      const { 3: inputAs, 4: inputClass, 6: htmlInput, 8: content } = $scope;
+      let { 3: inputAs, 4: inputClass, 6: htmlInput, 8: content } = $scope;
       $dynamicTag($scope, inputAs || "div", () => ({
         ...htmlInput,
         class: ["foo", inputClass],
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-multiple/__snapshots__/dom.expected/tags/wrapper.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-multiple/__snapshots__/dom.expected/tags/wrapper.js
index 9892a78936..b1826f0289 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-multiple/__snapshots__/dom.expected/tags/wrapper.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-multiple/__snapshots__/dom.expected/tags/wrapper.js
@@ -5,7 +5,7 @@ import * as _$ from "@marko/runtime-tags/debug/dom";
 const $inputAsdiv_content = _$.registerContent("__tests__/tags/wrapper.marko_1_renderer", "hi", /* over(1) */"b");
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0", $inputAsdiv_content);
 const $expr_inputAs_htmlInput = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     inputAs,
     htmlInput
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-name/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-name/__snapshots__/dom.expected/template.js
index 4c53872ebb..ca8ea20820 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-name/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-name/__snapshots__/dom.expected/template.js
@@ -7,7 +7,7 @@ import * as _$ from "@marko/runtime-tags/debug/dom";
 const $showTagAtagA_content = _$.registerContent("__tests__/template.marko_1_renderer", "Body content", /* over(1) */"b");
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0");
 const $expr_content_other = /* @__PURE__ */_$.intersection(29, $scope => {
-  const {
+  let {
     content,
     other
   } = $scope;
@@ -20,7 +20,7 @@ export const $content = /* @__PURE__ */_$.value("content", $expr_content_other);
 const $dynamicTag11 = /* @__PURE__ */_$.dynamicTag("#text/10");
 const $dynamicTag2 = /* @__PURE__ */_$.dynamicTag("#text/1");
 const $expr_x_other = /* @__PURE__ */_$.intersection(30, $scope => {
-  const {
+  let {
     x,
     other
   } = $scope;
@@ -32,7 +32,7 @@ const $expr_x_other = /* @__PURE__ */_$.intersection(30, $scope => {
 const $dynamicTag3 = /* @__PURE__ */_$.dynamicTag("#text/2");
 const $dynamicTag4 = /* @__PURE__ */_$.dynamicTag("#text/3");
 const $expr_show_other = /* @__PURE__ */_$.intersection(31, $scope => {
-  const {
+  let {
     show,
     other
   } = $scope;
@@ -47,7 +47,7 @@ const $expr_show_other = /* @__PURE__ */_$.intersection(31, $scope => {
 });
 const $dynamicTag5 = /* @__PURE__ */_$.dynamicTag("#text/4");
 const $expr_isLarge_other = /* @__PURE__ */_$.intersection(33, $scope => {
-  const {
+  let {
     isLarge,
     other
   } = $scope;
@@ -60,7 +60,7 @@ const $dynamicTag6 = /* @__PURE__ */_$.dynamicTag("#text/5");
 const $dynamicTag7 = /* @__PURE__ */_$.dynamicTag("#text/6");
 const $dynamicTag8 = /* @__PURE__ */_$.dynamicTag("#text/7", $showTagAtagA_content);
 const $expr_showTagA_other = /* @__PURE__ */_$.intersection(32, $scope => {
-  const {
+  let {
     showTagA,
     other
   } = $scope;
@@ -79,7 +79,7 @@ const $expr_showTagA_other = /* @__PURE__ */_$.intersection(32, $scope => {
 });
 const $dynamicTag9 = /* @__PURE__ */_$.dynamicTag("#text/8");
 const $expr_tag_other = /* @__PURE__ */_$.intersection(34, $scope => {
-  const {
+  let {
     tag,
     other
   } = $scope;
@@ -90,7 +90,7 @@ const $expr_tag_other = /* @__PURE__ */_$.intersection(34, $scope => {
 });
 const $dynamicTag10 = /* @__PURE__ */_$.dynamicTag("#text/9");
 const $expr_other_largeHeading = /* @__PURE__ */_$.intersection(37, $scope => {
-  const {
+  let {
     other,
     largeHeading
   } = $scope;
@@ -102,7 +102,7 @@ const $expr_other_largeHeading = /* @__PURE__ */_$.intersection(37, $scope => {
 const $dynamicTag12 = /* @__PURE__ */_$.dynamicTag("#text/11");
 const $dynamicTag13 = /* @__PURE__ */_$.dynamicTag("#text/12");
 const $expr_level_other = /* @__PURE__ */_$.intersection(35, $scope => {
-  const {
+  let {
     level,
     other
   } = $scope;
@@ -117,7 +117,7 @@ const $expr_level_other = /* @__PURE__ */_$.intersection(35, $scope => {
 });
 const $dynamicTag14 = /* @__PURE__ */_$.dynamicTag("#text/13");
 const $expr_other_tagConstA = /* @__PURE__ */_$.intersection(39, $scope => {
-  const {
+  let {
     other,
     tagConstA
   } = $scope;
@@ -128,7 +128,7 @@ const $expr_other_tagConstA = /* @__PURE__ */_$.intersection(39, $scope => {
 });
 const $dynamicTag15 = /* @__PURE__ */_$.dynamicTag("#text/14");
 const $expr_other_tagConstB = /* @__PURE__ */_$.intersection(41, $scope => {
-  const {
+  let {
     other,
     tagConstB
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-var-assignment/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-var-assignment/__snapshots__/html.expected/template.js
index bda6626d71..dd39fe51fb 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-var-assignment/__snapshots__/html.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-var-assignment/__snapshots__/html.expected/template.js
@@ -6,7 +6,7 @@ import * as _$ from "@marko/runtime-tags/debug/html";
 export default _$.createTemplate("__tests__/template.marko", input => {
   const $scope0_id = _$.nextScopeId();
   const $getCounter_scope = _$.peekNextScopeId();
-  const count = _$.dynamicTag($scope0_id, "#text/0", getCounter(), {});
+  let count = _$.dynamicTag($scope0_id, "#text/0", getCounter(), {});
   _$.setTagVar($scope0_id, "#scopeOffset/1", $getCounter_scope, "__tests__/template.marko_0_count/var");
   _$.write(`<button class=reset>reset</button>${_$.markResumeNode($scope0_id, "#button/2")}`);
   _$.writeEffect($scope0_id, "__tests__/template.marko_0");
diff --git a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-var/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-var/__snapshots__/html.expected/template.js
index 4f504e5078..29bd29f235 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-var/__snapshots__/html.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/dynamic-tag-var/__snapshots__/html.expected/template.js
@@ -4,13 +4,13 @@ export default _$.createTemplate("__tests__/template.marko", input => {
   const $scope0_id = _$.nextScopeId();
   let data1 = child({});
   const $inputshowchild_scope = _$.peekNextScopeId();
-  const data2 = _$.dynamicTag($scope0_id, "#text/2", input.show && child, {});
+  let data2 = _$.dynamicTag($scope0_id, "#text/2", input.show && child, {});
   _$.setTagVar($scope0_id, "#scopeOffset/3", $inputshowchild_scope, "__tests__/template.marko_0_data2/var");
   const $inputdynamic_scope = _$.peekNextScopeId();
-  const data3 = _$.dynamicTag($scope0_id, "#text/4", input.dynamic, {});
+  let data3 = _$.dynamicTag($scope0_id, "#text/4", input.dynamic, {});
   _$.setTagVar($scope0_id, "#scopeOffset/5", $inputdynamic_scope, "__tests__/template.marko_0_data3/var");
   const $inputshowdiv_scope = _$.peekNextScopeId();
-  const el1 = _$.dynamicTag($scope0_id, "#text/6", input.show && "div", {});
+  let el1 = _$.dynamicTag($scope0_id, "#text/6", input.show && "div", {});
   _$.setTagVar($scope0_id, "#scopeOffset/7", $inputshowdiv_scope, "__tests__/template.marko_0_el1/var");
   _$.writeScope($scope0_id, {}, "__tests__/template.marko", 0);
 });
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/error-const-mutation/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/error-const-mutation/__snapshots__/dom.expected/template.js
index 75c6e62726..b443c4cf50 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/error-const-mutation/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/error-const-mutation/__snapshots__/dom.expected/template.js
@@ -9,7 +9,7 @@ const $user = /* @__PURE__ */_$.value("user", ($scope, user) => {
 });
 const $fullName = /* @__PURE__ */_$.value("fullName", ($scope, fullName) => _$.data($scope["#text/0"], fullName));
 const $expr_user_fullName_user_firstName_user_middleName_user_lastName = /* @__PURE__ */_$.intersection(6, $scope => {
-  const {
+  let {
     user_fullName,
     user_firstName,
     user_middleName,
diff --git a/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var-from-dynamic/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var-from-dynamic/__snapshots__/html.expected/template.js
index fdaeddc9b4..9c1dbf5492 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var-from-dynamic/__snapshots__/html.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var-from-dynamic/__snapshots__/html.expected/template.js
@@ -12,7 +12,7 @@ export default _$.createTemplate("__tests__/template.marko", (input, $serialize)
     content: _$.createContent("__tests__/template.marko_1_renderer", () => {
       const $scope1_id = _$.nextScopeId();
       const $Child_scope = _$.peekNextScopeId();
-      const setHtml = _$.dynamicTag($scope1_id, "#text/0", 1 && Child, {});
+      let setHtml = _$.dynamicTag($scope1_id, "#text/0", 1 && Child, {});
       _$.setTagVar($scope1_id, "#scopeOffset/1", $Child_scope, "__tests__/template.marko_1_setHtml/var");
       _$.writeSubscribe($thing_content_subscribers, _$.writeScope($scope1_id, {
         setHtml
@@ -28,7 +28,7 @@ export default _$.createTemplate("__tests__/template.marko", (input, $serialize)
       content: _$.createContent("__tests__/template.marko_3_renderer", () => {
         const $scope3_id = _$.nextScopeId();
         const $Child_scope2 = _$.peekNextScopeId();
-        const setHtml2 = _$.dynamicTag($scope3_id, "#text/0", 1 && Child, {});
+        let setHtml2 = _$.dynamicTag($scope3_id, "#text/0", 1 && Child, {});
         _$.setTagVar($scope3_id, "#scopeOffset/1", $Child_scope2, "__tests__/template.marko_3_setHtml2/var");
         _$.writeSubscribe($thing_content2_subscribers, _$.writeScope($scope3_id, {
           setHtml2
@@ -44,7 +44,7 @@ export default _$.createTemplate("__tests__/template.marko", (input, $serialize)
   _$.dynamicTag($scope0_id, "#text/2", input.show ? 'section' : null, {}, _$.registerContent("__tests__/template.marko_4_renderer", () => {
     const $scope4_id = _$.nextScopeId();
     const $Child_scope3 = _$.peekNextScopeId();
-    const setHtml3 = _$.dynamicTag($scope4_id, "#text/0", 1 && Child, {});
+    let setHtml3 = _$.dynamicTag($scope4_id, "#text/0", 1 && Child, {});
     _$.setTagVar($scope4_id, "#scopeOffset/1", $Child_scope3, "__tests__/template.marko_4_setHtml3/var");
     _$.writeSubscribe($inputshowsectionnull_content_subscribers, _$.writeScope($scope4_id, {
       setHtml3
diff --git a/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var-many/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var-many/__snapshots__/html.expected/template.js
index 28c74a43f8..1771fb9221 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var-many/__snapshots__/html.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var-many/__snapshots__/html.expected/template.js
@@ -6,7 +6,7 @@ export default _$.createTemplate("__tests__/template.marko", input => {
   _$.resumeForTo(5, 0, 1, () => {
     const $scope1_id = _$.nextScopeId();
     const $Child_scope = _$.peekNextScopeId();
-    const setHtml = _$.dynamicTag($scope1_id, "#text/0", 1 && Child, {});
+    let setHtml = _$.dynamicTag($scope1_id, "#text/0", 1 && Child, {});
     _$.setTagVar($scope1_id, "#scopeOffset/1", $Child_scope, "__tests__/template.marko_1_setHtml/var");
     _$.writeScope($scope1_id, {
       setHtml
@@ -19,7 +19,7 @@ export default _$.createTemplate("__tests__/template.marko", input => {
   _$.resumeForTo(to, 0, 1, () => {
     const $scope2_id = _$.nextScopeId();
     const $Child_scope2 = _$.peekNextScopeId();
-    const setHtml2 = _$.dynamicTag($scope2_id, "#text/0", 1 && Child, {});
+    let setHtml2 = _$.dynamicTag($scope2_id, "#text/0", 1 && Child, {});
     _$.setTagVar($scope2_id, "#scopeOffset/1", $Child_scope2, "__tests__/template.marko_2_setHtml2/var");
     _$.writeScope($scope2_id, {
       setHtml2
@@ -34,7 +34,7 @@ export default _$.createTemplate("__tests__/template.marko", input => {
     _$.resumeForTo(3, 0, 1, j => {
       const $scope4_id = _$.nextScopeId();
       const $Child_scope3 = _$.peekNextScopeId();
-      const setHtml3 = _$.dynamicTag($scope4_id, "#text/0", 1 && Child, {});
+      let setHtml3 = _$.dynamicTag($scope4_id, "#text/0", 1 && Child, {});
       _$.setTagVar($scope4_id, "#scopeOffset/1", $Child_scope3, "__tests__/template.marko_4_setHtml3/var");
       _$.writeScope($scope4_id, {
         setHtml3
diff --git a/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var/__snapshots__/html.expected/template.js
index 7c281c5b0c..2f2e153b59 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var/__snapshots__/html.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/hoist-dynamic-tag-var/__snapshots__/html.expected/template.js
@@ -11,7 +11,7 @@ export default _$.createTemplate("__tests__/template.marko", (input, $serialize)
         if (input.show) {
           const $scope2_id = _$.nextScopeId();
           const $Child_scope = _$.peekNextScopeId();
-          const setHtml = _$.dynamicTag($scope2_id, "#text/0", 1 && Child, {});
+          let setHtml = _$.dynamicTag($scope2_id, "#text/0", 1 && Child, {});
           _$.setTagVar($scope2_id, "#scopeOffset/1", $Child_scope, "__tests__/template.marko_2_setHtml/var");
           _$.writeScope($scope2_id, {
             setHtml
@@ -35,7 +35,7 @@ export default _$.createTemplate("__tests__/template.marko", (input, $serialize)
     if (true) {
       const $scope3_id = _$.nextScopeId();
       const $Child_scope2 = _$.peekNextScopeId();
-      const setHtml2 = _$.dynamicTag($scope3_id, "#text/0", 1 && Child, {});
+      let setHtml2 = _$.dynamicTag($scope3_id, "#text/0", 1 && Child, {});
       _$.setTagVar($scope3_id, "#scopeOffset/1", $Child_scope2, "__tests__/template.marko_3_setHtml2/var");
       _$.writeScope($scope3_id, {
         setHtml2
@@ -49,7 +49,7 @@ export default _$.createTemplate("__tests__/template.marko", (input, $serialize)
     if (true) {
       const $scope4_id = _$.nextScopeId();
       const $Child_scope3 = _$.peekNextScopeId();
-      const setHtml3 = _$.dynamicTag($scope4_id, "#text/0", 1 && Child, {});
+      let setHtml3 = _$.dynamicTag($scope4_id, "#text/0", 1 && Child, {});
       _$.setTagVar($scope4_id, "#scopeOffset/1", $Child_scope3, "__tests__/template.marko_4_setHtml3/var");
       _$.writeScope($scope4_id, {
         setHtml3
diff --git a/packages/runtime-tags/src/__tests__/fixtures/hoist-native-tag-var-many/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/hoist-native-tag-var-many/__snapshots__/dom.expected/template.js
index 1baf116c67..ad0a0c6442 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/hoist-native-tag-var-many/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/hoist-native-tag-var-many/__snapshots__/dom.expected/template.js
@@ -3,7 +3,7 @@ export const $walks = /* over(1), replace, over(2), replace, over(2), replace, o
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $get$hoisted_el = _$.register("__tests__/template.marko_0_$hoisted_el3/hoist", _$.hoist("Getter:#li/0", "LoopScopeMap:#ul/0", "LoopScopeMap:#text/2"));
 const $expr_i_j$for$content = /* @__PURE__ */_$.intersection(3, $scope => {
-  const {
+  let {
     _: {
       i
     },
diff --git a/packages/runtime-tags/src/__tests__/fixtures/if-tag/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/if-tag/__snapshots__/dom.expected/template.js
index b7743a6e7e..a4934866df 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/if-tag/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/if-tag/__snapshots__/dom.expected/template.js
@@ -10,7 +10,7 @@ const $if_content = /* @__PURE__ */_$.createRenderer("Hello", /* over(1) */"b");
 const $if = /* @__PURE__ */_$.conditional("#text/0", $if_content);
 const $if2 = /* @__PURE__ */_$.conditional("#text/1", $if_content2);
 const $expr_input_a_input_b = /* @__PURE__ */_$.intersection(7, $scope => {
-  const {
+  let {
     input_a,
     input_b
   } = $scope;
@@ -21,7 +21,7 @@ export const $input_a = /* @__PURE__ */_$.value("input_a", $expr_input_a_input_b
 export const $input_b = /* @__PURE__ */_$.value("input_b", $expr_input_a_input_b);
 const $if3 = /* @__PURE__ */_$.conditional("#div/2", $if_content3, $elseif_content, $else_content);
 const $expr_input_x_input_y = /* @__PURE__ */_$.intersection(10, $scope => {
-  const {
+  let {
     input_x,
     input_y
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-child/__snapshots__/dom.expected/tags/child.js b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-child/__snapshots__/dom.expected/tags/child.js
index d9de485197..6556569cb0 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-child/__snapshots__/dom.expected/tags/child.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-child/__snapshots__/dom.expected/tags/child.js
@@ -12,7 +12,7 @@ const $state = /* @__PURE__ */_$.state("state/11", ($scope, state) => {
   $state_effect($scope);
 });
 const $expr_input_value_input_valueChange = /* @__PURE__ */_$.intersection(10, $scope => {
-  const {
+  let {
     input_value,
     input_valueChange
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-child/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-child/__snapshots__/dom.expected/template.hydrate.js
index 27c9dfd858..921e8cbf57 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-child/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-child/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 563 (min) 251 (brotli)
+// size: 561 (min) 251 (brotli)
 const $state_effect = _$.effect("a0", ($scope, { 11: state }) =>
     _$.on($scope[0], "click", function () {
       $state($scope, ++state);
@@ -8,7 +8,7 @@ const $state_effect = _$.effect("a0", ($scope, { 11: state }) =>
     (_$.data($scope[2], state), $state_effect($scope));
   }),
   $expr_input_value_input_valueChange = _$.intersection(10, ($scope) => {
-    const { 8: input_value, 9: input_valueChange } = $scope;
+    let { 8: input_value, 9: input_valueChange } = $scope;
     $state($scope, input_value, input_valueChange);
   }),
   $input_value = _$.value(8, ($scope, input_value) => {
diff --git a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-dynamic-change-handler/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-dynamic-change-handler/__snapshots__/dom.expected/template.hydrate.js
index d8de06bda0..b48360ed90 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-dynamic-change-handler/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-dynamic-change-handler/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 346 (min) 198 (brotli)
+// size: 344 (min) 198 (brotli)
 const $y_effect = _$.effect("a1", ($scope, { 7: y }) =>
     _$.on($scope[0], "click", function () {
       $y($scope, ++y);
@@ -8,7 +8,7 @@ const $y_effect = _$.effect("a1", ($scope, { 7: y }) =>
     (_$.data($scope[2], y), $y_effect($scope));
   }),
   $expr_x_yChange = _$.intersection(6, ($scope) => {
-    const { 4: x, 5: yChange } = $scope;
+    let { 4: x, 5: yChange } = $scope;
     $y($scope, x, yChange);
   }),
   $x = _$.state(4, ($scope, x) => {
diff --git a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-dynamic-change-handler/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-dynamic-change-handler/__snapshots__/dom.expected/template.js
index 263b3df0ea..8446570115 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-dynamic-change-handler/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-dynamic-change-handler/__snapshots__/dom.expected/template.js
@@ -11,7 +11,7 @@ const $y = /* @__PURE__ */_$.state("y/7", ($scope, y) => {
   $y_effect($scope);
 });
 const $expr_x_yChange = /* @__PURE__ */_$.intersection(6, $scope => {
-  const {
+  let {
     x,
     yChange
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-id/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-id/__snapshots__/dom.expected/template.hydrate.js
index 09441bd4b7..fdd7b57ef1 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-id/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-id/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 272 (min) 170 (brotli)
+// size: 270 (min) 170 (brotli)
 const $y_effect = _$.effect("a1", ($scope, { 6: y }) =>
     _$.on($scope[0], "click", function () {
       $y($scope, ++y);
@@ -8,7 +8,7 @@ const $y_effect = _$.effect("a1", ($scope, { 6: y }) =>
     (_$.data($scope[2], y), $y_effect($scope));
   }),
   $expr_x_handler = _$.intersection(5, ($scope) => {
-    const { 3: x, 4: handler } = $scope;
+    let { 3: x, 4: handler } = $scope;
     $y($scope, x, handler);
   }),
   $x = _$.state(3, ($scope, x) => {
diff --git a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-id/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-id/__snapshots__/dom.expected/template.js
index 270104f8f0..f45b1c64db 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-id/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/let-tag-controllable-id/__snapshots__/dom.expected/template.js
@@ -11,7 +11,7 @@ const $y = /* @__PURE__ */_$.state("y/6", ($scope, y) => {
   $y_effect($scope);
 });
 const $expr_x_handler = /* @__PURE__ */_$.intersection(5, $scope => {
-  const {
+  let {
     x,
     handler
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/let-tag-with-intersection/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/let-tag-with-intersection/__snapshots__/dom.expected/template.hydrate.js
index d77bf9353f..d10441db3e 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/let-tag-with-intersection/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/let-tag-with-intersection/__snapshots__/dom.expected/template.hydrate.js
@@ -1,7 +1,7 @@
-// size: 306 (min) 178 (brotli)
+// size: 304 (min) 179 (brotli)
 const $a = _$.value(9, ($scope, a) => _$.data($scope[4], a)),
   $expr_y_z = _$.intersection(8, ($scope) => {
-    const { 6: y, 7: z } = $scope;
+    let { 6: y, 7: z } = $scope;
     $a($scope, y + z);
   }),
   $y = _$.value(6, ($scope, y) => {
diff --git a/packages/runtime-tags/src/__tests__/fixtures/let-tag-with-intersection/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/let-tag-with-intersection/__snapshots__/dom.expected/template.js
index 4387c45473..b2376fe899 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/let-tag-with-intersection/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/let-tag-with-intersection/__snapshots__/dom.expected/template.js
@@ -3,7 +3,7 @@ export const $walks = /* get, next(1), get, out(1), replace, over(2), replace, o
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $a = /* @__PURE__ */_$.value("a", ($scope, a) => _$.data($scope["#text/4"], a));
 const $expr_y_z = /* @__PURE__ */_$.intersection(8, $scope => {
-  const {
+  let {
     y,
     z
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/tags/2counters.js b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/tags/2counters.js
index de0a738d92..5e5224120d 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/tags/2counters.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/tags/2counters.js
@@ -12,7 +12,7 @@ const $count = /* @__PURE__ */_$.state("count1/12", ($scope, count1) => {
   $count_effect($scope);
 });
 const $expr_input_count1_input_count1Change = /* @__PURE__ */_$.intersection(8, $scope => {
-  const {
+  let {
     input_count1,
     input_count1Change
   } = $scope;
@@ -30,7 +30,7 @@ const $count2 = /* @__PURE__ */_$.state("count2/13", ($scope, count2) => {
   $count2_effect($scope);
 });
 const $expr_input_count2_input_count2Change = /* @__PURE__ */_$.intersection(11, $scope => {
-  const {
+  let {
     input_count2,
     input_count2Change
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.hydrate.js
index 9084cd1d52..655ba2b554 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.hydrate.js
@@ -1,4 +1,4 @@
-// size: 560 (min) 234 (brotli)
+// size: 556 (min) 231 (brotli)
 const $count_effect = _$.effect("a0", ($scope, { 12: count1 }) =>
     _$.on($scope[0], "click", function () {
       $count$1($scope, ++count1);
@@ -8,7 +8,7 @@ const $count_effect = _$.effect("a0", ($scope, { 12: count1 }) =>
     (_$.data($scope[1], count1), $count_effect($scope));
   }),
   $expr_input_count1_input_count1Change = _$.intersection(8, ($scope) => {
-    const { 6: input_count1, 7: input_count1Change } = $scope;
+    let { 6: input_count1, 7: input_count1Change } = $scope;
     $count$1($scope, input_count1, input_count1Change);
   }),
   $input_count = _$.value(6, $expr_input_count1_input_count1Change),
@@ -21,7 +21,7 @@ const $count_effect = _$.effect("a0", ($scope, { 12: count1 }) =>
     (_$.data($scope[3], count2), $count2_effect($scope));
   }),
   $expr_input_count2_input_count2Change = _$.intersection(11, ($scope) => {
-    const { 9: input_count2, 10: input_count2Change } = $scope;
+    let { 9: input_count2, 10: input_count2Change } = $scope;
     $count2$1($scope, input_count2, input_count2Change);
   }),
   $input_count2 = _$.value(9, $expr_input_count2_input_count2Change),
diff --git a/packages/runtime-tags/src/__tests__/fixtures/native-tag-spread-content/__snapshots__/dom.expected/tags/my-div.js b/packages/runtime-tags/src/__tests__/fixtures/native-tag-spread-content/__snapshots__/dom.expected/tags/my-div.js
index d01b064736..8f09ebe8de 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/native-tag-spread-content/__snapshots__/dom.expected/tags/my-div.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/native-tag-spread-content/__snapshots__/dom.expected/tags/my-div.js
@@ -4,7 +4,7 @@ import * as _$ from "@marko/runtime-tags/debug/dom";
 const $define_content = _$.registerContent("__tests__/tags/my-div.marko_1_renderer", "Custom content", /* over(1) */"b");
 const $expr_input_CustomContent_content_effect = _$.effect("__tests__/tags/my-div.marko_0_input_CustomContent_content", $scope => _$.attrsEvents($scope, "#p/5"));
 const $expr_input_CustomContent_content = /* @__PURE__ */_$.intersection(11, $scope => {
-  const {
+  let {
     input,
     CustomContent_content
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/.name-cache.json b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/.name-cache.json
new file mode 100644
index 0000000000..7fde10def4
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/.name-cache.json
@@ -0,0 +1,9 @@
+{
+  "vars": {
+    "props": {
+      "$_$": "t",
+      "$init": "r",
+      "$$get_effect": "e"
+    }
+  }
+}
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/csr-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/csr-sanitized.expected.md
new file mode 100644
index 0000000000..7098a525ef
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/csr-sanitized.expected.md
@@ -0,0 +1,6 @@
+# Render
+```html
+<div>
+  hello
+</div>
+```
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/csr.expected.md b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/csr.expected.md
new file mode 100644
index 0000000000..771b341328
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/csr.expected.md
@@ -0,0 +1,12 @@
+# Render
+```html
+<div>
+  hello
+</div>
+```
+
+# Mutations
+```
+INSERT div
+INSERT div/#text
+```
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/dom.expected/tags/getter.js b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/dom.expected/tags/getter.js
new file mode 100644
index 0000000000..538cd10e52
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/dom.expected/tags/getter.js
@@ -0,0 +1,12 @@
+export const $template = "";
+export const $walks = "";
+import * as _$ from "@marko/runtime-tags/debug/dom";
+const $getter2 = /* @__PURE__ */_$.value("getter", _$.tagVarSignal);
+export function $setup($scope) {
+  $getter2($scope, $getter);
+}
+function $getter() {
+  return "hello";
+}
+_$.register("__tests__/tags/getter.marko_0/getter", $getter);
+export default /* @__PURE__ */_$.createTemplate("__tests__/tags/getter.marko", $template, $walks, $setup);
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/dom.expected/template.hydrate.js
new file mode 100644
index 0000000000..96f4b4f6f7
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/dom.expected/template.hydrate.js
@@ -0,0 +1,9 @@
+// size: 143 (min) 103 (brotli)
+_$.register("a0", function () {
+  return "hello";
+});
+const $get_effect = _$.effect(
+  "b0",
+  ($scope, { 3: get }) => ($scope[2].textContent = get()),
+);
+(_$.registerBoundSignal("b1", _$.value(3, $get_effect)), init());
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/dom.expected/template.js
new file mode 100644
index 0000000000..e0df6a7032
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/dom.expected/template.js
@@ -0,0 +1,13 @@
+export const $template = `${_getter_template}<div></div>`;
+export const $walks = /* beginChildWithVar, _getter_walks, endChild, get, over(1) */`0${_getter_walks}& b`;
+import { $setup as _getter, $template as _getter_template, $walks as _getter_walks } from "./tags/getter.marko";
+import * as _$ from "@marko/runtime-tags/debug/dom";
+const $get_effect = _$.effect("__tests__/template.marko_0_get", ($scope, {
+  get
+}) => ($scope["#div/2"].textContent = get()));
+const $get = _$.registerBoundSignal("__tests__/template.marko_0_get/var", /* @__PURE__ */_$.value("get", $get_effect));
+export function $setup($scope) {
+  _$.setTagVar($scope, "#childScope/0", $get);
+  _getter($scope["#childScope/0"]);
+}
+export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", $template, $walks, $setup);
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/html.expected/tags/getter.js b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/html.expected/tags/getter.js
new file mode 100644
index 0000000000..8503f86365
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/html.expected/tags/getter.js
@@ -0,0 +1,9 @@
+import * as _$ from "@marko/runtime-tags/debug/html";
+export default _$.createTemplate("__tests__/tags/getter.marko", input => {
+  const $scope0_id = _$.nextScopeId();
+  const getter = _$.register(() => {
+    return "hello";
+  }, "__tests__/tags/getter.marko_0/getter");
+  const $return = getter;
+  return $return;
+});
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/html.expected/template.js
new file mode 100644
index 0000000000..5fa8034ca4
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/html.expected/template.js
@@ -0,0 +1,14 @@
+import _getter from "./tags/getter.marko";
+import * as _$ from "@marko/runtime-tags/debug/html";
+export default _$.createTemplate("__tests__/template.marko", input => {
+  const $scope0_id = _$.nextScopeId();
+  let get = _getter({});
+  const el = _$.nodeRef();
+  _$.write(`<div></div>${_$.markResumeNode($scope0_id, "#div/2")}`);
+  _$.writeEffect($scope0_id, "__tests__/template.marko_0_get");
+  _$.writeScope($scope0_id, {
+    get
+  }, "__tests__/template.marko", 0, {
+    get: "1:9"
+  });
+});
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/resume-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/resume-sanitized.expected.md
new file mode 100644
index 0000000000..7098a525ef
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/resume-sanitized.expected.md
@@ -0,0 +1,6 @@
+# Render
+```html
+<div>
+  hello
+</div>
+```
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/resume.expected.md b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/resume.expected.md
new file mode 100644
index 0000000000..28e5a9fc35
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/resume.expected.md
@@ -0,0 +1,30 @@
+# Render
+```html
+<html>
+  <head />
+  <body>
+    <div>
+      hello
+    </div>
+    <!--M_*1 #div/2-->
+    <script>
+      WALKER_RUNTIME("M")("_");
+      M._.r = [_ =&gt; (_.a = [0,
+        {
+          get: _._[
+            "__tests__/tags/getter.marko_0/getter"
+            ]
+        }]),
+        "__tests__/template.marko_0_get",
+        1
+      ];
+      M._.w()
+    </script>
+  </body>
+</html>
+```
+
+# Mutations
+```
+INSERT html/body/div/#text
+```
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/ssr-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/ssr-sanitized.expected.md
new file mode 100644
index 0000000000..ab1de91de3
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/ssr-sanitized.expected.md
@@ -0,0 +1,4 @@
+# Render End
+```html
+<div />
+```
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/ssr.expected.md b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/ssr.expected.md
new file mode 100644
index 0000000000..5920baf69c
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/__snapshots__/ssr.expected.md
@@ -0,0 +1,39 @@
+# Write
+```html
+  <div></div><!--M_*1 #div/2--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.a=[0,{get:_._["__tests__/tags/getter.marko_0/getter"]}]),"__tests__/template.marko_0_get",1];M._.w()</script>
+```
+
+# Render End
+```html
+<html>
+  <head />
+  <body>
+    <div />
+    <!--M_*1 #div/2-->
+    <script>
+      WALKER_RUNTIME("M")("_");
+      M._.r = [_ =&gt; (_.a = [0,
+        {
+          get: _._[
+            "__tests__/tags/getter.marko_0/getter"
+            ]
+        }]),
+        "__tests__/template.marko_0_get",
+        1
+      ];
+      M._.w()
+    </script>
+  </body>
+</html>
+```
+
+# Mutations
+```
+INSERT html
+INSERT html/head
+INSERT html/body
+INSERT html/body/div
+INSERT html/body/#comment
+INSERT html/body/script
+INSERT html/body/script/#text
+```
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/tags/getter.marko b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/tags/getter.marko
new file mode 100644
index 0000000000..b5a6a3186e
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/tags/getter.marko
@@ -0,0 +1,5 @@
+<const/getter=() => {
+  return "hello";
+}>
+
+<return=getter>
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/template.marko b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/template.marko
new file mode 100644
index 0000000000..232120fae1
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/template.marko
@@ -0,0 +1,5 @@
+<getter/get/>
+<div/el/>
+<script>
+  el().textContent = get();
+</script>
diff --git a/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/test.ts b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/test.ts
new file mode 100644
index 0000000000..2e1746dabe
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/return-value-registered/test.ts
@@ -0,0 +1,3 @@
+import { wait } from "../../utils/resolve";
+
+export const steps = [{}, wait(1)];
diff --git a/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/dom.expected/template.hydrate.js
index 2ced446da1..407f122aab 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/dom.expected/template.hydrate.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/dom.expected/template.hydrate.js
@@ -1,6 +1,6 @@
-// size: 1194 (min) 427 (brotli)
+// size: 1186 (min) 426 (brotli)
 const $expr_value_call$define$content2 = _$.intersection(4, ($scope) => {
-    const { 2: value, 3: call } = $scope;
+    let { 2: value, 3: call } = $scope;
     _$.tagVarSignal($scope, $_return2($scope));
   }),
   $call$define$content2 = _$.state(3, $expr_value_call$define$content2),
@@ -21,7 +21,7 @@ _$.registerContent(
   $params3$define$content,
 );
 const $expr_value_call$define$content = _$.intersection(4, ($scope) => {
-    const { 2: value, 3: call } = $scope;
+    let { 2: value, 3: call } = $scope;
     _$.tagVarSignal($scope, $_return($scope));
   }),
   $call$define$content = _$.state(3, $expr_value_call$define$content),
@@ -43,7 +43,7 @@ _$.registerContent(
 );
 const $dynamicTag = _$.dynamicTag(0, 0, () => $onClickOnce2),
   $expr_Once_clickOnceCount = _$.intersection(10, ($scope) => {
-    const { 8: Once, 9: clickOnceCount } = $scope;
+    let { 8: Once, 9: clickOnceCount } = $scope;
     $dynamicTag($scope, Once, () => ({ value: $onClickOnce($scope) }));
   }),
   $clickOnceCount = _$.state(9, ($scope, clickOnceCount) => {
@@ -51,7 +51,7 @@ const $dynamicTag = _$.dynamicTag(0, 0, () => $onClickOnce2),
   }),
   $dynamicTag2 = _$.dynamicTag(4, 0, () => $onClickTwice2),
   $expr_Twice_clickTwiceCount = _$.intersection(14, ($scope) => {
-    const { 12: Twice, 13: clickTwiceCount } = $scope;
+    let { 12: Twice, 13: clickTwiceCount } = $scope;
     $dynamicTag2($scope, Twice, () => ({ value: $onClickTwice($scope) }));
   }),
   $clickTwiceCount = _$.state(13, ($scope, clickTwiceCount) => {
diff --git a/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/dom.expected/template.js
index b1575672f4..1828c59ecc 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/dom.expected/template.js
@@ -2,7 +2,7 @@ export const $template = "<!><!><button class=once> </button><!><button class=tw
 export const $walks = /* over(1), dynamicTagWithVar, over(1), get, next(1), get, out(1), dynamicTagWithVar, over(1), get, next(1), get, out(1) */"b1b D l1b D l";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_value_call$define$content2 = /* @__PURE__ */_$.intersection(4, $scope => {
-  const {
+  let {
     value,
     call
   } = $scope;
@@ -17,7 +17,7 @@ const $params3$define$content = /* @__PURE__ */_$.value("$params3", ($scope, $pa
 const $temp2$define$content = /* @__PURE__ */_$.value("$temp2", ($scope, $temp2) => $value$define$content2($scope, $temp2.value));
 const $define_content2 = _$.registerContent("__tests__/template.marko_2_renderer", 0, 0, $setup$define$content2, $params3$define$content);
 const $expr_value_call$define$content = /* @__PURE__ */_$.intersection(4, $scope => {
-  const {
+  let {
     value,
     call
   } = $scope;
@@ -33,7 +33,7 @@ const $temp$define$content = /* @__PURE__ */_$.value("$temp", ($scope, $temp) =>
 const $define_content = _$.registerContent("__tests__/template.marko_1_renderer", 0, 0, $setup$define$content, $params2$define$content);
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/0", 0, () => $onClickOnce2);
 const $expr_Once_clickOnceCount = /* @__PURE__ */_$.intersection(10, $scope => {
-  const {
+  let {
     Once,
     clickOnceCount
   } = $scope;
@@ -48,7 +48,7 @@ const $clickOnceCount = /* @__PURE__ */_$.state("clickOnceCount/9", ($scope, cli
 });
 const $dynamicTag2 = /* @__PURE__ */_$.dynamicTag("#text/4", 0, () => $onClickTwice2);
 const $expr_Twice_clickTwiceCount = /* @__PURE__ */_$.intersection(14, $scope => {
-  const {
+  let {
     Twice,
     clickTwiceCount
   } = $scope;
diff --git a/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/html.expected/template.js
index 04ed1d698b..93747a57a1 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/html.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/returns-within-define-tag/__snapshots__/html.expected/template.js
@@ -26,7 +26,7 @@ export default _$.createTemplate("__tests__/template.marko", input => {
   };
   let clickOnceCount = 0;
   const $Once_scope = _$.peekNextScopeId();
-  const onClickOnce = _$.dynamicTag($scope0_id, "#text/0", Once, {
+  let onClickOnce = _$.dynamicTag($scope0_id, "#text/0", Once, {
     value: _$.register(function () {
       clickOnceCount++;
     }, "__tests__/template.marko_0/onClickOnce", $scope0_id)
@@ -58,7 +58,7 @@ export default _$.createTemplate("__tests__/template.marko", input => {
   };
   let clickTwiceCount = 0;
   const $Twice_scope = _$.peekNextScopeId();
-  const onClickTwice = _$.dynamicTag($scope0_id, "#text/4", Twice, {
+  let onClickTwice = _$.dynamicTag($scope0_id, "#text/4", Twice, {
     value: _$.register(function () {
       clickTwiceCount++;
     }, "__tests__/template.marko_0/onClickTwice", $scope0_id)
diff --git a/packages/runtime-tags/src/__tests__/fixtures/update-dynamic-attrs/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/update-dynamic-attrs/__snapshots__/dom.expected/template.js
index 5083e16388..01475f96bc 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/update-dynamic-attrs/__snapshots__/dom.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/update-dynamic-attrs/__snapshots__/dom.expected/template.js
@@ -3,7 +3,7 @@ export const $walks = /* get, over(1), get, over(1), get, over(1) */" b b b";
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $expr_input_value_a_effect = _$.effect("__tests__/template.marko_0_input_value_a", $scope => _$.attrsEvents($scope, "#div/1"));
 const $expr_input_value_a = /* @__PURE__ */_$.intersection(7, $scope => {
-  const {
+  let {
     input_value,
     a
   } = $scope;
diff --git a/packages/translator-interop/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/components/custom-tag.js b/packages/translator-interop/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/components/custom-tag.js
index 0f83ed833e..549b3e581a 100644
--- a/packages/translator-interop/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/components/custom-tag.js
+++ b/packages/translator-interop/src/__tests__/fixtures/custom-tag-parameters-from-args/__snapshots__/dom.expected/components/custom-tag.js
@@ -11,7 +11,7 @@ const $expr_x_y_effect = _$.effect("__tests__/components/custom-tag.marko_0_x_y"
 const $expr_x_y = /* @__PURE__ */_$.intersection(9, $expr_x_y_effect);
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/3", 0, 0, 1);
 const $expr_input_content_x_y = /* @__PURE__ */_$.intersection(10, $scope => {
-  const {
+  let {
     input_content,
     x,
     y
diff --git a/packages/translator-interop/src/__tests__/fixtures/interop-tag-params-class-to-tags/__snapshots__/dom.expected/components/tags-layout.js b/packages/translator-interop/src/__tests__/fixtures/interop-tag-params-class-to-tags/__snapshots__/dom.expected/components/tags-layout.js
index cc616528fc..de03d32175 100644
--- a/packages/translator-interop/src/__tests__/fixtures/interop-tag-params-class-to-tags/__snapshots__/dom.expected/components/tags-layout.js
+++ b/packages/translator-interop/src/__tests__/fixtures/interop-tag-params-class-to-tags/__snapshots__/dom.expected/components/tags-layout.js
@@ -3,7 +3,7 @@ export const $walks = /* get, next(1), get, out(1), next(1), replace, out(1) */"
 import * as _$ from "@marko/runtime-tags/debug/dom";
 const $dynamicTag = /* @__PURE__ */_$.dynamicTag("#text/2", 0, 0, 1);
 const $expr_input_content_count = /* @__PURE__ */_$.intersection(7, $scope => {
-  const {
+  let {
     input_content,
     count
   } = $scope;
diff --git a/packages/translator-interop/src/__tests__/fixtures/interop-tag-params-tags-to-class/__snapshots__/dom.expected/template.js b/packages/translator-interop/src/__tests__/fixtures/interop-tag-params-tags-to-class/__snapshots__/dom.expected/template.js
index 644f9035b7..9787cd203d 100644
--- a/packages/translator-interop/src/__tests__/fixtures/interop-tag-params-tags-to-class/__snapshots__/dom.expected/template.js
+++ b/packages/translator-interop/src/__tests__/fixtures/interop-tag-params-tags-to-class/__snapshots__/dom.expected/template.js
@@ -6,7 +6,7 @@ import _classLayout from "./components/class-layout.marko";
 _$.register("__tests__/components/class-layout.marko", _classLayout);
 const $message$classlayout$content = /* @__PURE__ */_$.value("message", ($scope, message) => _$.data($scope["#text/0"], message));
 const $expr_multiplier_baseCount$classlayout$content = /* @__PURE__ */_$.intersection(7, $scope => {
-  const {
+  let {
     _: {
       multiplier
     },