srcdev-nuxt-components 9.1.25 → 9.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,7 +39,7 @@ Any [Iconify](https://icon-sets.iconify.design/) icon name is accepted. See `.cl
39
39
 
40
40
  ### `index` and image loading
41
41
 
42
- The `index` prop controls eager vs lazy image loading. The first two sections (`index` 0 and 1) load eagerly; all others load lazily. Pass the loop index when rendering a list of sections.
42
+ The `index` prop controls both eager/lazy loading and fetch priority. The first two sections (`index` 0 and 1) load eagerly; all others load lazily. Only `index 0` gets `fetchpriority="high"` (LCP candidate). Pass the loop index when rendering a list of sections.
43
43
 
44
44
  ### `reverse`
45
45
 
@@ -20,6 +20,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
20
20
  .claude/skills/
21
21
  ├── index.md — this file
22
22
  ├── performance-review.md — spawn a subagent to inspect recently written code for Vue/Nuxt performance issues before dev handoff
23
+ ├── performance-lcp-image-priority.md — fetchpriority=high + eager/lazy loading pattern for LCP images in list-rendered components
23
24
  ├── security-review.md — spawn a subagent to inspect recently written code for security vulnerabilities (XSS, injection, data exposure, etc.) before dev handoff
24
25
  ├── storybook-add-story.md — create a Storybook story for a component
25
26
  ├── storybook-add-font.md — add a new font to Storybook
@@ -0,0 +1,74 @@
1
+ # LCP Image — fetchpriority and loading
2
+
3
+ ## Overview
4
+
5
+ When a component renders images in a loop, the first item is typically the LCP candidate. Without explicit hints, the browser treats all images equally and delays fetching the first one — inflating the "resource load delay" metric in Lighthouse.
6
+
7
+ Two props work together:
8
+
9
+ | Prop | `index === 0` | `index === 1` | `index > 1` |
10
+ |------|--------------|--------------|-------------|
11
+ | `fetchpriority` | `"high"` | `"auto"` | `"auto"` |
12
+ | `loading` | `"eager"` | `"eager"` | `"lazy"` |
13
+
14
+ ## When to apply
15
+
16
+ Apply this pattern to any component that:
17
+ - renders a `<NuxtImg>` or `<img>` in a list driven by an `index` prop, **and**
18
+ - is likely to appear above or near the fold on first load
19
+
20
+ Do **not** apply `fetchpriority="high"` to more than one image per page — it cancels out the benefit.
21
+
22
+ ## Steps
23
+
24
+ ### 1. Accept an `index` prop
25
+
26
+ ```ts
27
+ interface Props {
28
+ index?: number
29
+ // ...other props
30
+ }
31
+ const props = withDefaults(defineProps<Props>(), {
32
+ index: 0,
33
+ })
34
+ ```
35
+
36
+ ### 2. Derive loading and fetchpriority
37
+
38
+ ```ts
39
+ const imageLoading = computed(() =>
40
+ props.index > 1 ? "lazy" : "eager"
41
+ )
42
+
43
+ const imageFetchPriority = computed(() =>
44
+ props.index === 0 ? "high" : "auto"
45
+ )
46
+ ```
47
+
48
+ ### 3. Bind both to the image
49
+
50
+ ```vue
51
+ <NuxtImg
52
+ :src="item.image"
53
+ :alt="item.title"
54
+ :loading="imageLoading"
55
+ :fetchpriority="imageFetchPriority"
56
+ />
57
+ ```
58
+
59
+ ### 4. Pass the loop index from the consumer
60
+
61
+ ```vue
62
+ <MyComponent
63
+ v-for="(item, i) in items"
64
+ :key="item.slug"
65
+ :index="i"
66
+ />
67
+ ```
68
+
69
+ ## Notes
70
+
71
+ - `fetchpriority="high"` signals to the browser to fetch the resource in the high-priority queue, reducing resource load delay — the main driver of LCP latency.
72
+ - Indices 0 and 1 both load eagerly because the second item is often partially visible on load (e.g. in a two-column grid). Only index 0 gets high priority.
73
+ - If the LCP element is not inside a loop (e.g. a standalone hero image), bind `fetchpriority="high"` directly without the computed.
74
+ - For non-Nuxt `<img>` elements, the attribute is identical: `<img fetchpriority="high" />`.
@@ -59,6 +59,7 @@ Read each file in full, then check for the following issues. Report only issues
59
59
  ─── Images / Assets ─────────────────────────────────────────────
60
60
  □ `NuxtImg` without explicit `width` and `height` (causes layout shift + Vercel width fallback)
61
61
  □ Images without `loading="lazy"` where above-the-fold loading is not required
62
+ □ First image in a list-rendered component missing `fetchpriority="high"` (LCP candidate — see `performance-lcp-image-priority.md`)
62
63
  □ Large inline SVGs that could be icon components
63
64
 
64
65
  ─── Bundle / Imports ────────────────────────────────────────────
@@ -1,10 +1,8 @@
1
1
  @keyframes entrySlideInAnimation {
2
2
  from {
3
- opacity: 0;
4
3
  transform: translateY(200px);
5
4
  }
6
5
  to {
7
- opacity: 1;
8
6
  transform: translateY(0);
9
7
  }
10
8
  }
@@ -2,7 +2,7 @@
2
2
  <component :is="tag" class="services-section" :class="[elementClasses]" :aria-labelledby="ariaLabelledby">
3
3
  <div class="services-section__grid" :class="{ 'services-section__grid--reverse': reverse }">
4
4
  <div class="image-wrapper">
5
- <NuxtImg :src="serviceData.image" :alt="serviceData.title" :loading="imageLoading" class="image" />
5
+ <NuxtImg :src="serviceData.image" :alt="serviceData.title" :loading="imageLoading" :fetchpriority="imageFetchPriority" class="image" />
6
6
  </div>
7
7
  <div class="info-wrapper" :class="infoWrapperClasses">
8
8
  <EyebrowText font-size="large" :text-content="serviceData.subtitle" />
@@ -179,6 +179,9 @@ const infoWrapperClasses = computed(() => {
179
179
  // Computed to return loading="lazy" if index is greater than 1, so that the first two sections prioritise image loading, but if there are more than 2 sections, the rest will lazy load their images to improve performance.
180
180
  const imageLoading = computed(() => (props.index !== undefined && props.index > 1 ? "lazy" : "eager"));
181
181
 
182
+ // Only the first image (LCP candidate) gets fetchpriority="high" to reduce resource load delay.
183
+ const imageFetchPriority = computed(() => (props.index === 0 ? "high" : "auto"));
184
+
182
185
  const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
183
186
 
184
187
  watch(
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "9.1.25",
4
+ "version": "9.1.27",
5
5
  "main": "nuxt.config.ts",
6
6
  "types": "types.d.ts",
7
7
  "license": "MIT",