vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.4k stars 26.9k forks source link

[Needs reproduction] Revalidation issues with the App Router #49417

Closed leerob closed 1 year ago

leerob commented 1 year ago

Moved from https://github.com/vercel/next.js/discussions/42290

Edit: Updated Reply


Hey folks, small update here. Since this issue has been posted, we've fixed a number of bugs with revalidation in the App Router. Further, we have published brand new caching documentation that goes in depth on fetching, caching, and revalidating:

Going forward, we can't look into any issues mentioned unless there's a reproduction provided. If you are still seeing an issue, please create a minimal repro and open a new issue. Thank you! 🙏

Diabl0570 commented 1 year ago

Title: Issue in preview branches but not present after merging or deploying to production

Description:

I have encountered an issue that consistently occurs in preview branches but is not present once the branch is merged or deployed to production.

Reproducible Scenario:

  1. Visit the "production" URL: https://next-revalidate-test-nu.vercel.app/pokemon
  2. Note the current pokemon that is listed
  3. Click on "Revalidate link"
  4. Reload the URL: https://next-revalidate-test-nu.vercel.app/pokemon
  5. Note the pokemon that is listed

Preview URL

  1. Visit the PR/preview URL and repeat: https://next-revalidate-test-git-feat-commit-diabl0570.vercel.app/
  2. Compare the behavior between the production URL and the PR/preview URL.
  3. Note the differences and any issues encountered.

Expected Result: The behavior should be consistent between the production and preview branches.

Additional Information:

Repository: https://github.com/Diabl0570/next-revalidate-test "Production" URL: https://next-revalidate-test-nu.vercel.app/pokemon Preview URL: https://next-revalidate-test-git-feat-commit-diabl0570.vercel.app/ PR URL: https://github.com/Diabl0570/next-revalidate-test/pull/3

Diabl0570 commented 1 year ago

@leerob I see the issue is closed, should I create a new issue?

Galanthus commented 1 year ago

I would like to add my thoughts on this issue. I tried to make the revalidatePath function work on Vercel. The revalidate action is fired after saving a Post or page returning a console log of the edited content with status code 200. Working on A Sanity CMS project and I am 100% sure there is this bug inside the Next app router. Where, the export const dynamic = 'auto' which if we have to believe the Next js documentation enabled by default. This is not true, tried refactoring my code for days to figure out what was going on. After 7 days tried to use the export const dynamic = 'auto' and after deploying to Vercel it works perfectly fine for all dynamic routes. It will instantly display and generate a new static file after making changes. GenerateStaticParams only creates and works after building the application after that, nothing will work or display new data at all.

Hope this helps...

SimulShift commented 1 year ago

It's also an issue when using fetch with { cache: 'no-store' } setting to fetch data from your local Next API. One work around I found was to make sure you have POST and GET requests stubbed out in your API route.js file. When I only had GET specified it failed to get the most up-to-data data from the API call until I fully rebuilt the production next app (npm run build ; npm run start)

so you mean that it's necessary change the name of the function inside the route.js from GET to POST also when it's not necessary catch params in input?

No, just need to have both specified. I found if I only have POST in the route.js, it didn't return the most recent data until I specified GET as well. The GET function doesn't need to do anything, it just needs to be stubbed.

i.e.

export async function POST(request) {
  return NextResponse.json(latestData)
}

export async function GET(request) {
  return NextResponse.json({})
}

OH! Thank you. I tried doing something like this on a whim and it actually fixed my issue. In my case, I already had a get and I just exported a POST and now next is respecting no-store and I am getting fresh data. Otherwise, none of these options do anything

export const fetchCache = 'force-no-store'
export const revalidate = 0 // seconds
export const dynamic = 'force-dynamic'

Here's what I added:

export const POST = async (req: Request) => {
  return NextResponse.json({error: 'Method not allowed'}, {status: 405})
}
stabildev commented 1 year ago

export const revalidate = 0 doesn't work for me with server component pages and Prisma. The data isn't being updated when navigating back and forth or via <Link> components.

// page.js
export const revalidate = 0

async function getData() {
  return await prisma.post.findMany(...)
}

export default async function Page() {
  const data = await getData()
  return (
    <>
      {data.map(
        ...
      }
    </>
  )
}

Workaround atm: Call revalidate(path) after mutating the data

IlirEdis commented 1 year ago

well, in actuality I am fetching from a graphql endpoint of a local headless CMS (Strapi). It's harder to share as a working code but it's really a completely standard fetch routine in app/page.tsx, and no changes to the above pages/api/revalidate.ts, something like

import { ApolloClient, InMemoryCache, gql } from "@apollo/client";
import moment from "moment";

const client = new ApolloClient({
 uri: "http://localhost:1337/graphql",
 cache: new InMemoryCache(),
 ssrMode: typeof window === "undefined",
  name: "react-web-client",
  connectToDevTools: true,
  defaultOptions: { 
     watchQuery: { fetchPolicy: "no-cache", errorPolicy: "ignore"},
     query: { fetchPolicy: "no-cache", errorPolicy: "all" }
}});

async function getData() {
  const { data, error } = await client.query({
     query: gql`{
         front {
           data {
             id
             attributes {
               updatedAt
    }}}}`,});
   return data;}

export default async function Home() {
   const strapidata = await getData();
  return (<h1>
        Strapi updatedAt:&nbsp;
        {moment(strapidata.front.data.attributes.updatedAt as string).format("HH:mm:ss")}
      </h1> )
}

The cache options in the Apollo client were part of my debugging (in v13.2.x), but I don't think they are essential (anymore). I have not tested again, but it worked in 13.3.0, and should also in latest canary.

@jwalcher I have exactly the same setup and the same issue. The difference is that in my case it works locally but not in production (Vercel). Did you manage to fix this?

jwalcher commented 1 year ago

You mean the issue with middleware breaking res.revalidate? I basically left the app at 13.3.0 where everything works fine. My plan is to refactor, using fetch() instead of apollo once revalidatePath works on dynamic routes https://github.com/vercel/next.js/issues/49387 (I hope that's not never). I'm self hosting, can't comment on Vercel issues.

IlirEdis commented 1 year ago

No, not middleware. Pages router with getStaticProps using Strapi. I only get the new posts when i re-deploy.

tobbbe commented 1 year ago

For me both revalidatePath and revalidateTag works on 13.4.10 but NOT on 13.4.12. Following basic examples from Next docs

karlhorky commented 1 year ago

@tobbbe not 100% certain, but maybe this is related to current cache invalidation bugs (since next@13.4.11-canary.1):

Frost-on-Web commented 1 year ago

@jwalcher I have exactly the same setup and the same issue. The difference is that in my case it works locally but not in production (Vercel). Did you manage to fix this?

Same setup here :

tjrooted commented 1 year ago

Please, for the love of donuts, do NOT make caching the default. For 6 months now, since using Next.js 13, I CANNOT REVALIDATE MY DATA IN PRODUCTION!

I've tried revalidatePath, export const revalidate = true, export const revalidate = 0, export const dynamic = 'force-dynamic', refreshing the page each time the user visits the page. Nothing works. My data won't update. I've spent 6 months building this product for a big client and I can't get the data on the screen to update in production.

Caching should NOT be the default behavior. It should be optional.

leerob commented 1 year ago

Hey folks, small update here. Since this issue has been posted, we've fixed a number of bugs with revalidation in the App Router. Further, we have published brand new caching documentation that goes in depth on fetching, caching, and revalidating:

Going forward, we can't look into any issues mentioned unless there's a reproduction provided. If you are still seeing an issue, please create a minimal repro and open a new issue. Thank you! 🙏