Next.js Discord

Discord Forum

How to find out why x-vercel-cache: MISS?

Answered
Whiteleg shrimp posted this in #help-forum
Open in Discord
Avatar
Whiteleg shrimpOP
Hi, I want to make our landing page a x-vercel-cache: HIT because I never changes. I have tried some things like revalidate = X or dynamic = "force-static" but none worked. I figured out that the issue in on the root layout.

I know I can be a million things but is there a way to find out what is? Or at least narrow it down?
Answered by B33fb0n3
can you add export const dynamic = 'force-static' to your layout and your page? After that take a look at the icon that you get when you build your page. Is it now static?
View full answer

14 Replies

Avatar
when you build your page with next build what icon did you landingpage got?

Also share the root layout and also tell us why you think there could be the problem

You also might want to share the page itself so we can take a look at the page
Avatar
Whiteleg shrimpOP
When I build, the layout gets ƒ (Dynamic)
I know it's not the page because I try to cache a dummy pages like this and it didn't work
export const revalidate = 86400

export default function Page() {
  return <h1>hola</h1>
}
export default function RootLayout(props: { children: ReactNode }) {
  return (
    <html suppressHydrationWarning lang="es" dir="ltr">
      <head>
        <PWAHeadMetadata />
        <Script defer src="/assets/scripts/zbar-wasm.js" />
      </head>
      <body
        className={cn(
          "caret-primary selection:bg-primary selection:text-primary-foreground selection:shadow-primary font-sans [--radius:0.5rem]",
          inter.variable
        )}
      >
        <Providers>
          <NuqsAdapter>
            {props.children}
            <TailwindIndicator />
            <Suspense>
              <RegisterServiceWorker />
            </Suspense>
          </NuqsAdapter>
          {process.env.VERCEL_ENV === "production" && (
            <>
              <Suspense>
                <UnioVercelToolbar />
              </Suspense>
              <SpeedInsights />
            </>
          )}
        </Providers>
        <Toaster />
      </body>
    </html>
  )
}
the providers is only a react query provider
"use client"

import type { ReactNode } from "react"
import { isServer, QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"

let browserQueryClient: QueryClient | undefined = undefined

function makeQueryClient() {
  return new QueryClient({
    defaultOptions: {
      mutations: {
        onSuccess: async () => {
          await browserQueryClient?.invalidateQueries()
        },
      },
    },
  })
}

function getQueryClient() {
  if (isServer) {
    return makeQueryClient()
  } else {
    if (!browserQueryClient) browserQueryClient = makeQueryClient()
    return browserQueryClient
  }
}

export function ReactQueryClientProvider(props: { children: ReactNode }) {
  const queryClient = getQueryClient()
  return (
    <QueryClientProvider client={queryClient}>
      {props.children}
      <ReactQueryDevtools />
    </QueryClientProvider>
  )
}
this is the service worker
"use client"

import { useEffect } from "react"

import { log } from "@/utils/log"

async function registerServiceWorker() {
  if (!("serviceWorker" in navigator)) {
    return
  }

  const registration = await navigator.serviceWorker.register("/serviceWorker.js", {
    scope: "/",
    updateViaCache: "none",
  })

  try {
    await registration.update()
    log("Service worker registered")
  } catch (error) {
    // eslint-disable-next-line no-console
    console.error("Error updating service worker", error)
  }
}

async function getReadyServiceWorker() {
  if (!("serviceWorker" in navigator)) {
    return
  }

  const registration = await navigator.serviceWorker.ready
  return registration
}

export const getCurrentPushSubscription = async () => {
  const sw = await getReadyServiceWorker()
  return await sw?.pushManager.getSubscription()
}

export const registerPushNotifications = async (applicationServerKey: string) => {
  const existingSubscription = await getCurrentPushSubscription()
  if (existingSubscription) {
    return
  }

  const sw = await getReadyServiceWorker()
  const suscription = await sw?.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey,
  })

  return suscription
}

export const unregisterPushNotifications = async () => {
  const existingSubscription = await getCurrentPushSubscription()
  if (!existingSubscription) {
    return
  }

  await existingSubscription.unsubscribe()
  return existingSubscription
}

export const RegisterServiceWorker = () => {
  useEffect(() => {
    registerServiceWorker()
  }, [])

  return null
}
 
and the toolbar
 
"use client"

import type { ComponentPropsWithoutRef } from "react"
import { VercelToolbar } from "@vercel/toolbar/next"

import { useProfileUserQuery } from "@/app/(profile)/_hooks/use-profile-user-query"
import { useAuthSessionQuery } from "@/app/auth/_hooks/use-auth-session-query"

function LocalUnioVercelToolbar(props: ComponentPropsWithoutRef<typeof VercelToolbar>) {
  const { data } = useProfileUserQuery()
  if (data?.role !== "admin") return null
  return <VercelToolbar {...props} />
}

export function UnioVercelToolbar(props: ComponentPropsWithoutRef<typeof VercelToolbar>) {
  const { data } = useAuthSessionQuery()
  if (!data) return null
  return <LocalUnioVercelToolbar {...props} />
}
Avatar
can you add export const dynamic = 'force-static' to your layout and your page? After that take a look at the icon that you get when you build your page. Is it now static?
Answer
Avatar
Whiteleg shrimpOP
I added export const dynamic = 'force-static' to the root layout only. It actually make all the pages that we need to be static, static. Like /terms-of-service or /privacy. Thanks dude. I didn't know that you could add the dynamic export to layouts
Avatar
Ah so is your initial issue already solved like that?
Avatar
Whiteleg shrimpOP
Yes
Avatar
Happy to help