Skip to content

Commit 748fb82

Browse files
committed
fix: fix warmup (fix bug with cards loads after first catalog visit)
1 parent 6c833df commit 748fb82

5 files changed

Lines changed: 67 additions & 8 deletions

File tree

app/components/AppFooter.vue

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
<script setup lang="ts">
2+
import { useCatalogNavigationWarmup } from '~/composables/useCatalogNavigationWarmup'
3+
4+
const { warmCatalogListing } = useCatalogNavigationWarmup()
5+
</script>
6+
17
<template>
28
<footer class="bg-surface-container-lowest py-12 lg:py-20 border-t border-white/5">
39
<div class="container mx-auto px-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-12 lg:gap-8">
@@ -13,7 +19,16 @@
1319
<div class="flex flex-col gap-6">
1420
<h3 class="text-lg font-heading font-semibold text-white/90">Навигация</h3>
1521
<nav class="flex flex-col gap-3">
16-
<NuxtLink to="/products" prefetch-on="interaction" class="text-sm text-white/60 hover:text-secondary transition-colors">Каталог</NuxtLink>
22+
<NuxtLink
23+
to="/products"
24+
prefetch-on="interaction"
25+
class="text-sm text-white/60 hover:text-secondary transition-colors"
26+
@pointerenter="warmCatalogListing"
27+
@focus="warmCatalogListing"
28+
@mousedown="warmCatalogListing"
29+
>
30+
Каталог
31+
</NuxtLink>
1732
<NuxtLink to="/services" prefetch-on="interaction" class="text-sm text-white/60 hover:text-secondary transition-colors">Услуги</NuxtLink>
1833
<NuxtLink to="/brands" prefetch-on="interaction" class="text-sm text-white/60 hover:text-secondary transition-colors">Бренды</NuxtLink>
1934
<NuxtLink to="/delivery" prefetch-on="interaction" class="text-sm text-white/60 hover:text-secondary transition-colors">Доставка</NuxtLink>

app/components/AppHeader.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<script setup lang="ts">
22
import AppButton from './ui/AppButton.vue'
3+
import { useCatalogNavigationWarmup } from '~/composables/useCatalogNavigationWarmup'
34
45
const isMenuOpen = ref(false)
56
const toggleMenu = () => isMenuOpen.value = !isMenuOpen.value
7+
const { warmCatalogListing } = useCatalogNavigationWarmup()
68
79
const navLinks = [
810
{ name: 'Каталог', to: '/products' },
@@ -27,6 +29,9 @@ const navLinks = [
2729
:to="link.to"
2830
prefetch-on="interaction"
2931
class="text-sm font-medium text-white/70 hover:text-white transition-colors focus:outline-none focus:text-white"
32+
@pointerenter="link.to === '/products' ? warmCatalogListing() : undefined"
33+
@focus="link.to === '/products' ? warmCatalogListing() : undefined"
34+
@mousedown="link.to === '/products' ? warmCatalogListing() : undefined"
3035
>
3136
{{ link.name }}
3237
</NuxtLink>
@@ -61,6 +66,9 @@ const navLinks = [
6166
:to="link.to"
6267
prefetch-on="interaction"
6368
class="text-lg font-medium text-white/70 py-2 border-b border-white/5"
69+
@pointerenter="link.to === '/products' ? warmCatalogListing() : undefined"
70+
@focus="link.to === '/products' ? warmCatalogListing() : undefined"
71+
@mousedown="link.to === '/products' ? warmCatalogListing() : undefined"
6472
@click="isMenuOpen = false"
6573
>
6674
{{ link.name }}

app/components/ui/AppButton.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import { computed } from 'vue'
3+
import { useCatalogNavigationWarmup } from '~/composables/useCatalogNavigationWarmup'
34
45
interface Props {
56
variant?: 'primary' | 'glass' | 'text'
@@ -17,6 +18,9 @@ const props = withDefaults(defineProps<Props>(), {
1718
disabled: false,
1819
ariaLabel: undefined
1920
})
21+
const { warmCatalogListing } = useCatalogNavigationWarmup()
22+
23+
const shouldWarmCatalogListing = computed(() => props.to === '/products' || props.to?.startsWith('/products?'))
2024
const classes = computed(() => [
2125
'inline-flex items-center justify-center font-medium transition-all focus:outline-none focus:ring-2 focus:ring-secondary/50 disabled:opacity-50 disabled:cursor-not-allowed',
2226
{
@@ -34,6 +38,9 @@ const classes = computed(() => [
3438
:class="classes"
3539
:aria-label="ariaLabel"
3640
prefetch-on="interaction"
41+
@pointerenter="shouldWarmCatalogListing ? warmCatalogListing() : undefined"
42+
@focus="shouldWarmCatalogListing ? warmCatalogListing() : undefined"
43+
@mousedown="shouldWarmCatalogListing ? warmCatalogListing() : undefined"
3744
>
3845
<span v-if="loading" class="mr-2 animate-spin"/>
3946
<slot />
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useCatalog } from '~/composables/useCatalog'
2+
3+
export const useCatalogNavigationWarmup = () => {
4+
const { getCachedProductsPageByFilters, prefetchCatalogPage } = useCatalog()
5+
const warmupStarted = useState('catalog-navigation-warmup-started', () => false)
6+
7+
const warmCatalogListing = () => {
8+
if (import.meta.server || warmupStarted.value || getCachedProductsPageByFilters(1, '', '', [])) {
9+
return
10+
}
11+
12+
warmupStarted.value = true
13+
14+
void prefetchCatalogPage(1, '', '', [], {
15+
imageCount: 8,
16+
imagePriority: 'high'
17+
}).finally(() => {
18+
warmupStarted.value = false
19+
})
20+
}
21+
22+
return {
23+
warmCatalogListing
24+
}
25+
}

app/pages/products/index.vue

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const firstRenderSettled = ref(false)
5353
const lastResolvedData = ref(defaultProductsResponse())
5454
const isRouteFetching = ref(false)
5555
const filtersHydrated = ref(false)
56+
const routeFetchReady = ref(false)
5657
5758
let searchDebounceTimeout: ReturnType<typeof setTimeout> | null = null
5859
@@ -182,7 +183,6 @@ const criticalImageLinks = computed(() => products.value
182183
as: 'image',
183184
href,
184185
fetchpriority: 'high',
185-
// crossorigin: ''
186186
})))
187187
188188
useHead(() => ({
@@ -195,7 +195,6 @@ const categories = computed(() =>
195195
slug: category.slug,
196196
label: getCategoryLabel(category.slug)
197197
}))
198-
.sort((left, right) => left.label.localeCompare(right.label))
199198
)
200199
201200
const allVisibleImagesReady = computed(() => {
@@ -388,14 +387,13 @@ const handlePageChange = (page: number) => {
388387
389388
watch(
390389
() => route.fullPath,
391-
() => {
392-
if (import.meta.server) {
390+
(nextPath, previousPath) => {
391+
if (import.meta.server || !routeFetchReady.value || nextPath === previousPath) {
393392
return
394393
}
395394
396395
void fetchRoutePage()
397-
},
398-
{ immediate: true }
396+
}
399397
)
400398
401399
watch(
@@ -456,12 +454,18 @@ watch(error, (currentError) => {
456454
})
457455
458456
onMounted(() => {
457+
routeFetchReady.value = true
458+
459459
requestAnimationFrame(() => {
460460
firstRenderSettled.value = true
461461
})
462462
463463
if (!products.value.length) {
464-
void recoverCatalogDataOnClient()
464+
void fetchRoutePage().finally(() => {
465+
if (!products.value.length) {
466+
void recoverCatalogDataOnClient()
467+
}
468+
})
465469
}
466470
})
467471

0 commit comments

Comments
 (0)