After following the on-demand revalidation article I realized that if we send a broken page from prismic (eg: content team adds a broken link that we validate during the page build time) nextjs will clear all prismic
cache tags during the revalidate and will serve a broken page (error 500). Is there another strategy we can use to prevent that and serve the last successfully built page for avoiding it?
@angeloashmore since you have worked closely on the app router changes, do you have any ideas about it?
Hi @gabriel,
Clearing all Prismic-related network requests via revalidateTag("prismic")
is a general strategy that works in most cases, but it can be replaced with something more specific if necessary.
In addition to the revalidateTag()
function, Next.js provides a revalidatePath()
function that lets you revalidate a specific page path:
import { revalidatePath } from 'next/cache'
import { NextRequest, NextResponse } from 'next/server'
export async function POST(request: NextRequest) {
revalidatePath("/foo/bar")
return NextResponse.json({ revalidated: true, now: Date.now() })
}
You could write some logic that iterates through the changed pages and validate that their content is correct. The Prismic webhook sends data about which documents were created, updated, and deleted as part of the event, from which you could gather a list of page paths to revalidate.
Because that kind of logic is website-specific—especially the validation part—I don't have a code snippet to share with you. If you have questions about how to write that logic, however, please post them here.
Hey! thanks for replying! From their docs looks like both revalidatePath and revalidateTag don't return anything, so I'm not sure if we can iterate on those to verify if pages are working correctly. Currently what my team is doing is similar to the code snippet below:
import { SliceZone } from "@prismicio/react";
import { createClient } from "@/prismicio";
import { components } from "@/slices";
export default async function Home() {
const client = createClient();
const page = await client.getSingle("homepage");
//@ts-ignore
const buttonLink = page.data.slices[0]?.primary.buttonLink as any
if(buttonLink.url.includes('http://')){
throw new Error('http:// is not allowed, please use https://')
}
return <SliceZone slices={page.data.slices} components={components} />;
}
It's simplified on purpose, the original repo is a copy of the one mentioned on the tutorial, but the rest of the code is here
From the nextjs docs
If an error is thrown while attempting to revalidate data, the last successfully generated data will continue to be served from the cache. On the next subsequent request, Next.js will retry revalidating the data.
Cleaning the cache after a revalidation works correctly, but my expectation was around the previous cached page, throwing an error or returning null will not serve the last successful page, but rather an 500/internal server error page in production
Ah, I think I understand what you mean. Since that throw new Error()
is occurring within the component, the generated page will throw. That may be too late for revalidateTag
/revalidatePath
to consider it a failed revalidation.
I don't deeply know the internal workings of Nex.js's new caching system, but it's possible revalidating a path or tag only clears the fetch()
cache, not the generated page HTML. Thus, the Error
won't be thrown until someone tries to access the page.
You could run your content validations within the /revalidate
Route Handler instead. For example, you could read the webhook, gather the list of change document IDs, query each document, and validate its data. If the data is invalid, don't revalidate the page (and maybe send a notification somewhere so content writers know their page won't be published).