Skip to content

Commit b054c19

Browse files
committed
fix: render static search list on ssr
1 parent e0b85b5 commit b054c19

1 file changed

Lines changed: 48 additions & 24 deletions

File tree

app/components/PackageList.vue

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import type { NpmSearchResult } from '#shared/types'
33
import type { WindowVirtualizerHandle } from '~/composables/useVirtualInfiniteScroll'
44
import { WindowVirtualizer } from 'virtua/vue'
55
6+
/** Number of items to render statically during SSR */
7+
const SSR_COUNT = 20
8+
69
const props = defineProps<{
710
/** List of search results to display */
811
results: NpmSearchResult[]
@@ -96,31 +99,52 @@ defineExpose({
9699

97100
<template>
98101
<div>
99-
<WindowVirtualizer
100-
ref="listRef"
101-
:data="results"
102-
:item-size="140"
103-
as="ol"
104-
item="li"
105-
class="list-none m-0 p-0"
106-
@scroll="handleScroll"
107-
>
108-
<template #default="{ item, index }">
109-
<div class="pb-4">
110-
<PackageCard
111-
:result="item as NpmSearchResult"
112-
:heading-level="headingLevel"
113-
:show-publisher="showPublisher"
114-
:selected="index === (selectedIndex ?? -1)"
115-
:index="index"
116-
:search-query="searchQuery"
117-
class="motion-safe:animate-fade-in motion-safe:animate-fill-both"
118-
:style="{ animationDelay: `${Math.min(index * 0.02, 0.3)}s` }"
119-
@focus="emit('select', $event)"
120-
/>
121-
</div>
102+
<!-- SSR: Render static list for first page, replaced by virtual list on client -->
103+
<ClientOnly>
104+
<WindowVirtualizer
105+
ref="listRef"
106+
:data="results"
107+
:item-size="140"
108+
as="ol"
109+
item="li"
110+
class="list-none m-0 p-0"
111+
@scroll="handleScroll"
112+
>
113+
<template #default="{ item, index }">
114+
<div class="pb-4">
115+
<PackageCard
116+
:result="item as NpmSearchResult"
117+
:heading-level="headingLevel"
118+
:show-publisher="showPublisher"
119+
:selected="index === (selectedIndex ?? -1)"
120+
:index="index"
121+
:search-query="searchQuery"
122+
class="motion-safe:animate-fade-in motion-safe:animate-fill-both"
123+
:style="{ animationDelay: `${Math.min(index * 0.02, 0.3)}s` }"
124+
@focus="emit('select', $event)"
125+
/>
126+
</div>
127+
</template>
128+
</WindowVirtualizer>
129+
130+
<!-- SSR fallback: static list of first page results -->
131+
<template #fallback>
132+
<ol class="list-none m-0 p-0">
133+
<li v-for="(item, index) in results.slice(0, SSR_COUNT)" :key="item.package.name">
134+
<div class="pb-4">
135+
<PackageCard
136+
:result="item"
137+
:heading-level="headingLevel"
138+
:show-publisher="showPublisher"
139+
:selected="index === (selectedIndex ?? -1)"
140+
:index="index"
141+
:search-query="searchQuery"
142+
/>
143+
</div>
144+
</li>
145+
</ol>
122146
</template>
123-
</WindowVirtualizer>
147+
</ClientOnly>
124148

125149
<!-- Loading indicator -->
126150
<div v-if="isLoading" class="py-4 flex items-center justify-center">

0 commit comments

Comments
 (0)