Conrad Nuxt docs

Performance, assets and testing

Where to start on a slow page, lazy components versus lazy hydration, NuxtLink prefetching, Nuxt Image, Fonts and Scripts, app/assets versus public, serving .output/public in Kubernetes and on Workers, fonts and layout shift, LCP, and Nuxt's test environments.

From the performance part of your Concepts note, the assets and styling parts of Getting started I, the prefetching part of Getting started II and the testing part of Getting started III.

Know

  • Measure first: field Core Web Vitals, Lighthouse on a throttled phone, nuxi analyze for the bundle. Different metrics, different fixes.
  • Less JavaScript, three levels: Lazy prefix with v-if (not downloaded until rendered), lazy hydration on Lazy components (hydrate-on-visible, -on-idle, -on-interaction, -on-media-query, -after, -when, -never: HTML now, JavaScript later), server components (no JavaScript at all).
  • Prefetching: <NuxtLink> loads the linked page's code, and the payload of prerendered or cached pages, when the link is visible; switch to prefetch-on="interaction" on link-heavy pages.
  • Modules: Nuxt Image (sized images, WebP/AVIF, preload the LCP image, lazy the rest), Nuxt Fonts (self-hosted fonts, fontaine fallbacks against CLS), Nuxt Scripts (third-party scripts after hydration or on triggers, facades).
  • Assets: app/assets is processed and hashed (cache a year, immutable); public is copied as is with stable URLs (short cache). .output/public goes to a bucket behind the CDN in Kubernetes; on Workers it's uploaded and served by Cloudflare automatically.
  • CLS from fonts: the fallback font must match the real font's metrics (size-adjust and the overrides); LCP: preload the main image with high priority, sized and in a modern format, never lazy.
  • Testing: Vitest + @nuxt/test-utils; Node environment for plain logic and end-to-end tests (setup() from @nuxt/test-utils/e2e), Nuxt environment (happy-dom or jsdom) for anything using Nuxt, with mountSuspended, mockNuxtImport and registerEndpoint.

Fact check of your notes

Gotcha· hydrate-on-visible needs the Lazy prefix

"Add an attribute hydrate-on-visible to components": the lazy hydration attributes only work on components used with the Lazy prefix (<LazyMyComponent hydrate-on-visible />), in SFC templates, with the prop written in the template. On a normal component it's just an attribute.

Gotcha· Nuxt Scripts delays scripts; it doesn't use threads

"Delays their execution using multithreading": by default Nuxt Scripts loads third-party scripts after hydration, when the browser is idle, or later on a trigger (interaction, visibility, consent), and offers facade components. Running scripts in a web worker is Partytown, which Nuxt Scripts supports only as an option.

Gotcha· You can use Vue Test Utils in Nuxt

"I can't use regular Vue Test Utils": you can, for components that don't use Nuxt features, and the docs install @vue/test-utils next to @nuxt/test-utils; mountSuspended is VTU's mount with the Nuxt context and async setup around it. What fails is mounting a component that relies on auto-imports, useState or plugins outside the Nuxt environment.

Exercise

Exercise
  • Put a heavy component below the fold three ways: plain, <LazyX v-if> behind a button, and <LazyX hydrate-on-visible />. Compare the page source and the network panel while scrolling.
  • Set prefetchOn to interaction globally and watch the requests on a page with many links.
  • Add @nuxt/fonts with a Google font and look at the generated @font-face and fallback rules in the CSS.
  • Set up Vitest projects for test/unit (node) and test/nuxt (nuxt), and write the registerEndpoint test from this page.

Be able to say

Be able to say· What's the difference between lazy components and lazy hydration?

"A Lazy component with v-if isn't rendered at all until the condition is true, so there's no HTML and its code is downloaded only then. Lazy hydration, like hydrate-on-visible on a Lazy component, renders it on the server, so the HTML is there for users and crawlers, but loads and hydrates its JavaScript only when it's needed. The first saves both, the second saves the JavaScript work while keeping the content."

Be able to say· How do you test a Nuxt app?

"Vitest with @nuxt/test-utils, in projects per environment. Plain logic and server utils run in the Node environment and are fast. Components and composables that use Nuxt run in the Nuxt environment, a real Nuxt app in happy-dom, mounted with mountSuspended, with registerEndpoint to fake API routes and mockNuxtImport for composables. End-to-end tests build and start the app with setup() and drive it over HTTP or with Playwright, for the critical journeys only."

Your notes

Open in Notes

Nothing yet. Notes filed here show up on this page and the section overview.