Adding a scoped slot to a component whose <slot> sits inside a :for loop stops the page rendering entirely. Not a wrong value, not a missing element - the response never completes.
Found on @stacksjs/stx@0.2.607, npm's latest.
Reproduction
A working page: a Stacks dashboard table with 50 rows, already using a
#toolbar slot on the same component, rendering fine.
Add one scoped slot whose host <slot> is inside the row loop:
<Table :columns="COLUMNS" :data="visibleRows()">
<template #actions="{ row }">
<Button variant="ghost" size="sm" @click="console.log(row)">Edit</Button>
</template>
<template #toolbar> … unchanged … </template>
</Table>The host renders that slot as:
<template :for="row in visibleRows()">
<tr>
…
<td :if="$slots.actions" class="px-4 w-12">
<slot name="actions" :row="row" />
</td>
</tr>
</template>Result:
curl -s -o /dev/null -w "%{http_code} %{size_download}" http://localhost:3002/dependencies
000 0 # hangs, nothing returnedRemove only that <template #actions> block, change nothing else, restart:
200 548823The dev server stays up and logs no error for it. In the browser the document
sits at readyState: "loading" with an empty body, so it reads as a slow page
rather than a failure.
What is not the cause
- Not compilation.
compileTemplate()on the same file completes and the output looks right: the<th>, the<td :if="$slots.actions">, the slot body with its@click="openEdit(row)"binding, and the resolved<Button>scope are all present. - Not the
#toolbarslot. That one is on the same component, outside the row loop, and has worked throughout. - Not
$slotsin a compound condition. The guard here is the standalone$slots.actions, which is the form that works for #2098.
The difference between the two slots on that component is that #toolbar
expands once, outside any loop, and #actions expands per row inside
<template :for>.
Why I am reporting it rather than working around it quietly
The workaround is easy - a declarative prop instead of a slot - but the failure mode is not. A slot that renders nothing is findable. A slot that makes the whole page hang, with no error anywhere and a server that stays healthy, costs much more to track down, and the natural first guess is the data layer rather than the template.
Context: this is the actions column of a 729-line table component in Stacks that 42 dashboard tables are being migrated onto (stacksjs/stacks#2925). It is now using props instead, so nothing is blocked - but the slot is part of that component's public shape and other callers will reach for it.
Possibly already fixed on main: v0.2.609 carries 1f167716d1 fix(slots):
expose per-instance presence to reactive expressions, and v0.2.612 carries
9d783de44a test(slots): cover nested table projection and visible
interpolation, neither of which is published. I will re-test the moment a
release lands and close this if it is gone.