Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next.js v12.1 on-demand-isr client-side navigation displays out of date content #35195

Closed
1 task done
sven-ra opened this issue Mar 10, 2022 · 34 comments
Closed
1 task done
Labels
bug Issue was opened via the bug report template.

Comments

@sven-ra
Copy link

sven-ra commented Mar 10, 2022

Verify canary release

  • I verified that the issue exists in Next.js canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 21.2.0: Sun Nov 28 20:28:41 PST 2021; root:xnu-8019.61.5~1/RELEASE_ARM64_T6000
Binaries:
  Node: 16.14.0
  npm: 8.3.1
  Yarn: N/A
  pnpm: 6.32.3
Relevant packages:
  next: 12.1.1-canary.8
  react: 17.0.2
  react-dom: 17.0.2

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

Vercel

Describe the Bug

I have couple of sites for which I changed the regular ISR to on-demand-isr. The revalidated pages do show the updated content when directly reloading but on client-side navigation I still have the content from the last build. This does not happen when I make a local build with npm run build. For additional details, one of the site runs on i18n the and one does not.

The same issue was described here but marked as resolved.
#34531

Expected Behavior

Expecting the content to be up to date when doing client-side navigation.

To Reproduce

@sven-ra sven-ra added the bug Issue was opened via the bug report template. label Mar 10, 2022
@balazsorban44
Copy link
Member

Could you attach a minimal reproduction or a link to your site/code for further investigation? 🙏

@Sinhalite
Copy link

I'm having the exact same problem.

It doesn't always happen, it probably happens only on heavy pages.
(However, Vercel's serverless function has not timed out)

This is happening in my closed project, so I'll try to make something for reproduction.

@Sinhalite
Copy link

  • Additional information
    This only happens when the path is registered in getStaticPaths.
    It does not occur when the path is empty.

@Sinhalite
Copy link

I have created a project for reproduction.

Steps to Reproduce

  • SSR
  1. View https://nextjs-issue-35268.vercel.app/test
  • CSR
  1. View https://nextjs-issue-35268.vercel.app/
  2. Click 'TestPage'
  • Revalidate
  1. View https://nextjs-issue-35268.vercel.app/api/revalidate

Issue

Different values are displayed.

@kristjanmar
Copy link

This is the same issue as #34531 -- it was fixed, but now the problem is occurring every now and then. Loading a page directly shows the fresh revalidated page but client-side navigating to a page shows the stale version. These guys were aware of it: @ijjk @leerob

Apparently the problem then was Vercel related, not sure what is going on now.

@sven-ra sven-ra changed the title Next.js v12.1 on-demand-isr client-side navigation displays old content Next.js v12.1 on-demand-isr client-side navigation displays out of date content Mar 19, 2022
@jmotes
Copy link

jmotes commented Mar 21, 2022

This issue is happening for us too - only on Vercel (local revalidation works perfectly). In production we see old content on client side navigation after a successful revalidation but a full reload loads the new content fine.

Unlike @kristjanmar it isn't intermittent for us. We've observed this behavior on every single revalidation since March 3rd. And unlike Sinhalite above, this happens on dynamic URLs too (not just ones brought in by getStaticPaths).

It seems the client-side-navigated content does finally update after the hardcoded revalidation time is reached however. Hoping we can get this fixed soon so I don't have to reduce the revalidation period (which will add to our API server load).

It's worth noting that we're using middleware routing to enable multi-tenant support. I wonder if the .json file deletion isn't respecting the custom paths generated there:

import { NextMiddleware, NextResponse } from "next/server";

export const middleware: NextMiddleware = (req) => {
	const url = req.nextUrl.clone();
	const pathname = req.nextUrl.pathname;
	const hostname = req.headers.get("host") ?? "";

	// don't proxy requests to static files or api endpoints
	if (!pathname.includes(".") && !pathname.startsWith("/api")) {
		url.pathname = `/_sites/${encodeURIComponent(hostname)}${pathname}`;
		return NextResponse.rewrite(url);
	}
};

@jmotes
Copy link

jmotes commented Mar 21, 2022

@ijjk do you have any ideas? (sorry for tagging you, but I saw you worked on #34531)

@ghost ghost mentioned this issue Mar 26, 2022
1 task
@jmotes
Copy link

jmotes commented Mar 28, 2022

I finally found what was causing my issue. I had internalization configured in my next.config.js file like this:

module.exports = {
  i18n: {
    locales: ["en-US"],
    defaultLocale: "en-US",
  },
  reactStrictMode: true,
};

But, I was using middleware to adjust my pathname (to implement ISR+multitenant support) without realizing that I needed to prefix the pathname with the current locale.

I am curious how exactly to implement i18n support while modifying the pathname though if anyone has any suggestions.

@kristjanmar
Copy link

I'm not using internationalization so it doesn't explain the bug on my end. I've reverted back to the default ISR for now and I'll wait for the on-demand ISR to go out of beta.

@agustints
Copy link
Contributor

I have the same problem, the content is revalidated but not painted on the screen, it happens to me in the local environment too, it is not only in vercel in my case. The page loads correctly only when reloading it manually!

@afewyards
Copy link

Same issue here, for me this only happens when I deploy on vercel. basically the x-vercel-cache never goes stale for the supplied jsons and remain serving the previous cached version

@ijjk
Copy link
Member

ijjk commented Apr 8, 2022

Hi, are you able to share deployment URLs/specific reproductions similar to this comment where you are seeing this behavior so we can investigate further?

@ijjk
Copy link
Member

ijjk commented Apr 8, 2022

@Sinhalite the reproduction you are showing is currently expected as the data endpoint and HTML are revalidated separately on Vercel although a fix is being tested currently that prevents this in newer Next.js versions

@agustints
Copy link
Contributor

agustints commented Apr 8, 2022

@ijjk I have this video I recorded today to demonstrate the bug, the issue is like this, I edit the animal for the first time and the changes are reflected, then I edit it again and until I manually reload the web I don't see the changes but the revalidate is called and the props run. I hope it can be fixed soon, I love the ISR on-Demand functionality!

URL https://youtu.be/QhmF1cOJIR8

@agustints
Copy link
Contributor

image
I tried also in vercel directly and the logs show that the first time it revalidates and calls the json but the second time it only revalidates, it does not call the getStaticProps nor the json and therefore does not update the web!

@ghost
Copy link

ghost commented Apr 8, 2022

@agustints is the "uy" after your port number an i18n prefix? (http://localhost:3000/**uy**/). I'm curious if your issue might be related to mine that I mentioned above.

@agustints
Copy link
Contributor

@jmotes No, I am not using i18n, it is simply a country identifier that I take with router.query.

@ijjk
Copy link
Member

ijjk commented Apr 8, 2022

@agustints it looks like you are revalidating and then doing a client-transition. Currently Next.js prefetches the data for client-transitions and doesn't reset the cache until a refresh or hard navigation is done to ensure navigations are as fast as possible. So this currently looks expected.

@agustints
Copy link
Contributor

agustints commented Apr 8, 2022

@ijjk But it applies to the router.push()? there is no solution then, so after updating I have no way to take the user to that updated page?

@kristjanmar
Copy link

kristjanmar commented Apr 8, 2022 via email

@ijjk
Copy link
Member

ijjk commented Apr 8, 2022

@kristjanmar that sounds like a separate issue, please provide a deployment/reproduction for that case to allow investigating that

@ijjk
Copy link
Member

ijjk commented Apr 8, 2022

@agustints you can verify this is your issue by manually clearing the cache before calling router.push e.g. delete next.router.sdc[new URL(`/_next/data/${window.__NEXT_DATA__.buildId}/${AS_PATH_VALUE_TO_CLEAR}.json`, location.href).toString()]

@agustints
Copy link
Contributor

agustints commented Apr 8, 2022

@ijjk
The problem continues to act the same way with your solution,
The page I am revalidating is
https://www.mascoty.app/uy/adopciones/rocky

The revalidation url is https://www.mascoty.app/api/revalidate?secret=M4scoty&path=/uy/adopciones/rocky

The edit url that calls the revalidate is https://www.mascoty.app/uy/adopciones/editar/rocky

To edit you must first log in to the app

User: agustint@live.com
Password: admin

@ijjk
Copy link
Member

ijjk commented Apr 8, 2022

@agustints is the revalidation API being called before calling router.push? Seems like unstable_revalidate() should be called inside of the edit endpoint after the data is saved instead of doing an additional request client-side. Then after the edit response is returned to the client it would need to clear the cache delete next.router.sdc[new URL(`/_next/data/${window.__NEXT_DATA__.buildId}/uy/adopciones/rocky.json`, location.href).toString()]` and then trigger the `router.push().

Also it looks like a service-worker is present, so would be good to double check it isn't accidentally caching any _next/data requests.

@afewyards
Copy link

So I did some more testing and it seems that I need to specifically also need to target the json to revalidate. if I just do
/${locale}/${channel.slug}/collection/${slug}/${data?.product?.slug} it will revalidate the page but not the data json. and if I add /_next/data/${process.env.BUILD_ID}/${locale}/${channel.slug}/collection/${slug}/${data?.product?.slug}.json to my revalidation loop it also revalidates the json.

unsure if this is wanted but at least it's usable for me now

@agustints
Copy link
Contributor

Perfect, I managed to make it work locally with that delete line, but when deployed in vercel it doesn't work...

@AbadotDigital
Copy link

@afewyards so far this workaround works for us. thanks for sharing it!

@ivankadukpc
Copy link

@afewyards this is not working for me

@Hooman-studio
Copy link

Same Problem. Not using i18n.

@meotimdihia
Copy link

meotimdihia commented Jun 18, 2022

same here, the data file JSON wasn't revalidated. Not using 18n.
I have to relivalidate like /_next/data/${process.env.BUILD_ID}/${locale}/${channel.slug}/collection/${slug}/${data?.product?.slug}.json @afewyards said.

@2820402
Copy link

2820402 commented Jun 22, 2022

So I did some more testing and it seems that I need to specifically also need to target the json to revalidate. if I just do /${locale}/${channel.slug}/collection/${slug}/${data?.product?.slug} it will revalidate the page but not the data json. and if I add /_next/data/${process.env.BUILD_ID}/${locale}/${channel.slug}/collection/${slug}/${data?.product?.slug}.json to my revalidation loop it also revalidates the json.

unsure if this is wanted but at least it's usable for me now

Can anyone give the full code of this plz I can't understand this

@meotimdihia
Copy link

meotimdihia commented Jun 22, 2022

@2820402 : this is the line that I used. My website is running on a custom server.

   await got(
      `https://domain/api/revalidate?url=/comic/${comic.slug}/${chapter.id}-chapter-${chapter.chap}-${chapter.lang}&secret=${process.env.SECRET_KEY}`
    )
   await got(
      `https://domain/api/revalidate?url=/_next/data/${buildID}/comic/${comic.slug}/${chapter.hid}-chapter-${chapter.chap}-${chapter.lang}.json&secret=${process.env.SECRET_KEY}`
    )
// pages/api/revalidate.js

export default async function handler(req, res) {
      // Check for secret to confirm this is a valid request
      if (req.query.secret !== process.env.SECRET_KEY) {
        return res.status(401).json({ message: "Invalid token" })
      }
      if (!req.query.url) {
      return res.status(401).json({ message: "No url provided" })
      }

    console.log(req.query.url)
    try {
      await res.unstable_revalidate(req.query.url)
      return res.json({ revalidated: true })
    } catch (err) {
		  console.log(err)
      // If there was an error, Next.js will continue
      // to show the last successfully generated page
      return res.status(500).send("Error revalidating")
    }
}

@ijjk
Copy link
Member

ijjk commented Jun 25, 2022

Hi, this has been updated in the latest canary of Next.js v12.1.7-canary.48, please update and give it a try!

In this version the API has been made stable so unstable_revalidate became revalidate, there is also optimistic updating during client-navigations where fresh data is attempted to be fetched in case an on-demand revalidation has occurred since the data was prefetched.

A manual client cache update can also be triggered in the latest canary before a navigation with next.router.prefetch('/blog/post-1', undefined, { unstable_skipClientCache: true })

Please remove the duplicate revalidations for both the page and the data like mentioned in #35195 (comment) as this should not be necessary. If you are seeing issues with the data route not being revalidated please open a fresh issue with a Vercel deployment and we can investigate that closer!

I'm gonna close this as it seems to have diverged from the initial issue which should be resolved after updating canary.

@ijjk ijjk closed this as completed Jun 25, 2022
kodiakhq bot pushed a commit that referenced this issue Jun 25, 2022
This adds a note about ensuring requests during a revalidation don't leverage an upstream cache as it will fail to pull fresh data to update the ISR cache with if configured. 

## Documentation / Examples

- [x] Make sure the linting passes by running `pnpm lint`
- [x] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)

Fixes: #35523 (comment)
x-ref: #35195


Co-authored-by: Lee Robinson <9113740+leerob@users.noreply.github.com>
@github-actions
Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 26, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests