Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to clear NextJs GetStaticPaths cache / "unpublish" a dynamic route?

I think this is quite a vanilla question but I can't find anything on Google.

I'm learning NextJs (using TypeScript) and I've got a site successfully working with dynamic routes, SSR, and incremental regeneration all setup and deployed to Vercel. Here's an example of the GetStaticProps and GetStaticPaths code in my dynamic route handler:

export const getStaticPaths: GetStaticPaths = async () => {
    const routes = new CmsHelper().GetRoutes();

    const paths = (await routes).items.map((item, index, items) => {
        return item.fields.urlPath;
    })

    return {
        paths: paths,
        fallback: 'blocking',
    };
}

export const getStaticProps: GetStaticProps = async (context) => {
    const urlParts = context.params?.url as string[] || [];
    const urlPath = `/${urlParts.join('/')}`;
    const article = await new CmsHelper().GetArticle(urlPath);
    return {
        props: {
            article
        },
        revalidate: 10,
    }
}

If I request a new path that was published in the cms after build time, it successfully regenerates on the server and returns the page.

So far so good.

However, if I unpublish a route in my CMS... it is still returned by the app, unless I rebuild and redeploy (or otherwise cause the process to restart, in dev).

So my question is: how do I dynamically cause NextJs to remove a dynamic route from its GetStaticPaths cache?

I understand that GetStaticProps is going to be called at most once every 10 seconds because of the revalidate configuration. But as far as I know, GetStaticPaths will only be called if a request comes in from a route that is not currently cached(?)

In other words, for an integration with a headless CMS, how can I support unpublishing or renaming pages with NextJs without triggering a rebuild/deploy?

Thanks in advance!

like image 358
Alex Norcliffe Avatar asked Jan 01 '21 01:01

Alex Norcliffe


Video Answer


1 Answers

Maybe try this approach described here.

Also providing the code here for reference purposes.

// pages/blog/[slug].js

import {useRouter} from 'next/router'
import DefaultErrorPage from 'next/error'

export async function getStaticProps({ params }) {
  // fetch data from CMS through params
  const post = await getBlogItem(params.slug)
  return {
    props: {
      post
    }
  }
}

export async function getStaticPaths() {
  return {
    fallback: true,
    paths: []
  }
}

export default function MyPage({post}) {
  const router = useRouter()

  if(router.isFallback) {
     return <h1>Loading...</h1>
  }

  // This includes setting the noindex header because static files always return a status 200 but the rendered not found page page should obviously not be indexed
  if(!post) {
    return <>
      <Head>
        <meta name="robots" content="noindex">
      </Head>
      <DefaultErrorPage statusCode={404} />
    </>
  }

  return <h1>{post.title}</h1>
}

So, instead of deleting/clearing the cache, maybe try to handle successfully that the content you are fetching is "unpublished" and if so, you can display a 404 Not found page or something of your choice.

Something like this:

export async function getStaticProps(context) {

    const {params: {id}} = context

    let data;
    try {
        data = await httpClient...
    } catch (err) {
        if (not err is caused due to content being unpublished){
            // re throw it
            throw err;
        }
        // Else handle it gracefully
        data = null;
    }

    return {
        props: {
            data,
        },
        revalidate: 1
    };
}

and then on your View:

export default function Data(props) {
    const {data} = props;

    const router = useRouter()

    // If the page is not yet generated, this will be displayed
    // initially until getStaticProps() finishes running
    if (router.isFallback) {
        return <div>Loading...</div>
    }

    if (!data) {
        return (
            <>
                <Head>
                    <meta name="robots" content="noindex"/>
                </Head>
                <DefaultErrorPage statusCode={404}/>
            </>
        )
    }

    return <DataView {...data} />;

}
like image 183
entropyfeverone Avatar answered Oct 21 '22 13:10

entropyfeverone