nitro icon indicating copy to clipboard operation
nitro copied to clipboard

Nuxt 3 - Nitro vercel-edge - Redirection problem on page load - URL parameter appended to URL

Open CedsTrash opened this issue 1 year ago • 41 comments

Environment


  • Operating System: Linux
  • Node Version: v20.11.1
  • Nuxt Version: 3.12.2
  • CLI Version: 3.12.0
  • Nitro Version: 2.9.6
  • Package Manager: [email protected]
  • Builder: -
  • User Config: basicAuth, head, build, components, css, devtools, i18n, modules, nitro, runtimeConfig, routeRules
  • Runtime Modules: @nuxtjs/[email protected], @kgierke/[email protected], @nuxtjs/[email protected]
  • Build Modules: -

Reproduction

I can't give you a minimal reproduction because it runs on Vercel Edge. I can just give you the link to the website: https://staging-vercel-edge.nxstar.ca

Describe the bug

Everything works fine locally and when I deploy to vercel with the "vercel" nitro preset. But when I do the same with the "vercel-edge" preset the problems starts:

  • https://staging-vercel-edge.nxstar.ca is redirected to https://staging-vercel-edge.nxstar.ca/?url=/
  • https://staging-vercel-edge.nxstar.ca/first-page is redirected to https://staging-vercel-edge.nxstar.ca/first-page?url=/first-page
  • And so on

If I reach any of the pages directly, I can see the content and then open my navigation menu and navigate to an other page. It works fine and the URL is now correct (without the appended URL parameter). But the problem appears again as soon as I refresh the page.

All my routes are in ISR mode and I use @nuxtjs/i18n with this config:

export default defineNuxtConfig({
    i18n: {
        defaultLocale: 'en',
        detectBrowserLanguage: false,
        langDir: 'lang',
        lazy: true,
        locales: [
          {
            code: 'fr',
            iso: 'fr-CA',
            file: 'fr.ts'
          },
          {
            code: 'en',
            iso: 'en-CA',
            file: 'en.ts'
          }
        ],
        customRoutes: 'config',
        pages: {
            '[url]': {
                en: '/[url]',
                fr: '/[url]'
            },
            'post/[url]': {
                en: '/post/[url]',
                fr: '/article/[url]'
            }
        },
        strategy: 'prefix_except_default',
        vueI18n: "./i18n.config.ts"
    },
    routeRules: {
        '/**': { isr: 3600 },
    }
})

And finally, page content is fetched from a headless CMS like this: pages/[url].vue

<script setup>
const config = useRuntimeConfig()
const route = useRoute()
const { locale } = useI18n()
const requestUrl = useRequestURL()

const url = ref({en: '/' + route.params.url, fr: '/fr/' + route.params.url})
const { data : page } = await useAsyncData(
    'page-${route.params.url}',
    () => $fetch(config.public.BASE_API_URL + '/collections/pages/entries?token=' + route.query.token + '&filter[site]=' + locale.value + '&filter[url]=' + url.value[locale.value])
)
</script>

I found out 2 people on the official Nuxt Discord server who point out to a but with the vercel-edge Nitro preset. Again, it all works perfectly until I activate the vercel-edge preset.

Thanks for your help.

Additional context

I want to use Vercel Edge in conjunction with ISR because I need the On-Demand ISR feature, and of course the lower latencies that edge functions offer.

Logs

No response

CedsTrash avatar Jun 12 '24 10:06 CedsTrash

Hi @pi0 How can I provide a reproduction for this since it's specific to the vercel-edge preset? Thanks.

CedsTrash avatar Jun 12 '24 15:06 CedsTrash

After playing a bit with the routeRules setting I now have a slighty different behavior:

routeRules: {
    '/**': { isr: 3600 },
    '/second-page': { swr: true, cache: { maxAge: 60 * 40 } },
    '/third-page': { isr: 3600, cache: { maxAge: 60 } },
    '/fourth-page': { cache: { maxAge: 60 } },
  },

Now I get this:

  • https://staging-vercel-edge.nxstar.ca doesn't redirect at all
  • https://staging-vercel-edge.nxstar.ca/second-page redirects to https://staging-vercel-edge.nxstar.ca/second-page?url=$url (instead of https://staging-vercel-edge.nxstar.ca/second-page?url=/second-page before)
  • Same for https://staging-vercel-edge.nxstar.ca/third-page
  • https://staging-vercel-edge.nxstar.ca/fourth-page doesn't redirect at all

I disabled Vercel deployment protection so anyone can access the site without having to click the Vercel shared link first.

CedsTrash avatar Jun 12 '24 16:06 CedsTrash

@CedsTrash it would be best if you can reproduce this in pure Nitro (reproduction sandbox). 🙏

It's fine if you upload it to StackBlitz or a GitHub repo, and if it needs to be deployed to vercel to reproduce - we can test that.

danielroe avatar Jun 14 '24 14:06 danielroe

After briefly talking to @manniL, I've tried to set up a reproduction but I wasn't really sure about what to do: https://stackblitz.com/~/github.com/CedsTrash/nitro-vercel-edge-isr

And then I deployed it to Vercel: https://nitro-vercel-edge-isr.vercel.app/

The current preset is "vercel", because if I set it to "vercel_edge" I get a 404: NOT FOUND. I don't see any URL parameter being appended here, but again, I'm not sure if this is good reproduction.

Thanks for your insights.

CedsTrash avatar Jun 19 '24 09:06 CedsTrash

Hi everyone,

I just updated the code and also created a dedicated project on Vercel with a new domain: https://staging-vercel-edge.nxstar.ca

I've changed a few things after talking with @manniL, in order to better manage caching.

pages/[url].vue now looks like this:

<script setup>
const route = useRoute()
const { locale } = useI18n()
const requestUrl = useRequestURL()

const url = ref({en: '/' + route.params.url, fr: '/fr/' + route.params.url})

const { data: page } = await useAsyncData(
    `page-${route.params.url}`,
    () => $fetch(`/api/bff`, {
      method: 'POST',
      body: {
        locale: locale.value,
        url: url.value[locale.value],
        cacheKey: `page-${route.params.url}`,
      }
    })
)
</script>

My /api/bff route looks like this:

export default defineCachedEventHandler(async (event) => {
    const config = useRuntimeConfig()

    const body = await readBody(event)
    const result = await $fetch(config.public.BASE_API_URL + '/collections/pages/entries?filter[site]=' + body.locale + '&filter[url]=' + body.url)

    return {
        data: result.data,
        fetchedAt: new Date()
    }
}, {
    maxAge: 30,
    getKey: async (event) => {
        const body = await readBody(event)

        return body.cacheKey
    }
})

And my routes rules are as follow:

routeRules: {
  '/**': { isr: 60 },
  '/api/**': { isr: false },
},

I now have a better understanding on how all of these parts work together in terms of caching. But I still experience the same behavior on Vercel as soon as I switch to the vercel-edge preset.

CedsTrash avatar Jul 04 '24 13:07 CedsTrash

Does someone have a clue on what's going on? I'm really stuck on this one and could really use some help. Thanks!

CedsTrash avatar Jul 29 '24 17:07 CedsTrash

It takes hours to figure out.

Why add ?url=$url? It seems useless. When set isr=false, it works normally.

image

way-zer avatar Aug 23 '24 17:08 way-zer

It takes hours to figure out.

Why add ?url=$url? It seems useless. When set isr=false, it works normally.

image

Nice catch! Would anybody know why this is appended to the URL?

CedsTrash avatar Aug 25 '24 05:08 CedsTrash

Hi guys, anyone with a clue on how to solve this? Or at least on why ?url=$url is appendend on line 4241?

Thanks.

CedsTrash avatar Sep 25 '24 06:09 CedsTrash

Hi guys, anyone with a clue on how to solve this? Or at least on why ?url=$url is appendend on line 4241?

Thanks.

workaround: set isr=false for all routes (As line 4233)

way-zer avatar Sep 25 '24 06:09 way-zer

Hi guys, anyone with a clue on how to solve this? Or at least on why ?url=$url is appendend on line 4241? Thanks.

workaround: set isr=false for all routes (As line 4233)

Yes, but I meant while keeping ISR enabled. Because I use ISR with ISR On-Demand Revalidation here

CedsTrash avatar Sep 25 '24 06:09 CedsTrash

Maybe just modify line 4241. I don't know why the query is added.

And the generated result is same as isr=false

way-zer avatar Sep 25 '24 06:09 way-zer

I’m also having this issue with vercel-edge and isr enabled.

thunder87 avatar Nov 06 '24 23:11 thunder87

Hi, is there any update on this issue? It's a shame not being able to benefit from the edge's speed.

CedsTrash avatar Nov 15 '24 10:11 CedsTrash

Please check: https://nitro.build/deploy/providers/vercel#fine-grained-isr-config-via-route-rules (available in Nitro 2.10+)

pi0 avatar Nov 15 '24 16:11 pi0

Please check: https://nitro.build/deploy/providers/vercel#fine-grained-isr-config-via-route-rules (available in Nitro 2.10+)

Thanks @pi0 , could you give me a bit more context? Are you referring to the passQuery property?

export default defineNitroConfig({
  routeRules: {
    "/products/**": {
      isr: {
        allowQuery: ["q"],
        passQuery: true,
      },
    },
  },
});

CedsTrash avatar Nov 15 '24 16:11 CedsTrash

Yes, it should configure platform primitives to include query params in vercel ISR cache key.

Let me know if this worked for you so we can investigate better.

pi0 avatar Nov 15 '24 16:11 pi0

I'm not sure what I need to do though. Should I set it to true or false?

I changed my routeRules config to this and still face the same issue:

routeRules: {
    '/**': {
      isr: {
        expiration: 60,
        passQuery: true
      }
    },
    '/api/**': { isr: false },
  },

I've also tried to set it to false, same outcome.

CedsTrash avatar Nov 15 '24 16:11 CedsTrash

Aaaah, wait a second, I see that my app runs Nitro 2.9.7. How can I upgrade to Nitro 2.10+ with Nuxt 3.12.3? Nuxt 3.14.159 isn't working for me. "Error: Worker not ready" when running npm run dev. And build error on Vercel as well. Happening on various projects as soon as I upgrade to Nuxt 3.14.159.

I see a few open issues regarding this issue.

CedsTrash avatar Nov 15 '24 16:11 CedsTrash

npx nuxi upgrade --force should most of the time do the trick.

And if you had issues after the upgrade, if you can share your project somehow (perhaps better in nuxt issues) we can definitely help!

pi0 avatar Nov 15 '24 17:11 pi0

Yeah I ran npx nuxi upgrade --force but there's definitely an issue with Nuxt 3.14.159 so I can check Nitro 2.10 out for now.

Could you just tell me a bit more about the passQuery property? I'd like to understand what value I should use and how it could fix the issue.

Thanks for your time.

CedsTrash avatar Nov 15 '24 17:11 CedsTrash

This config maps to vercel build output API. More in their docs: https://vercel.com/docs/build-output-api/v3/primitives#prerender-configuration-file

pi0 avatar Nov 15 '24 17:11 pi0

@CedsTrash I am experiencing the exact same issue on Nuxt 3.14.159 with Nitro 2.10.4.

ISR (or to be exact: revalidating) only works for me with NITRO_PRESET=vercel-edge in .env. But with this present in .env i also get these ?url= appended to my urls.

Havent found a solution yet.

@pi0 Can you maybe clarify? I tried both passQuery: true/false but I cant seem to get rid of this ?url= behaviour

fiveam-lukas avatar Nov 18 '24 20:11 fiveam-lukas

@fiveam-lukas Thanks for your input. It helps knowing I'm not the only one :-)

CedsTrash avatar Nov 18 '24 20:11 CedsTrash

Its a bit annoying because I cant ship pages like this for my clients. The urls need to be pure imho.

@pi0 What I am puzzled by is: In the nitro docs under allowQuery it says in the third bulletpoint: For wildcard /** route rules, url is always added Source: https://nitro.build/deploy/providers/vercel#fine-grained-isr-config-via-route-rules

But there is no further explanation. Does this mean whatever options i set, ?url= will always be added?

fiveam-lukas avatar Nov 18 '24 21:11 fiveam-lukas

Using vercel preset I get __nitro-?url= appended urls and using the vercel-edge preset: ?url=

As @CedsTrash, this only occurs on page refresh (SSR) with passQuery: true

isr: {
  expiration: 3600,
  allowQuery: ['token', 'preview-token'],
  passQuery: true,
},

passQuery also only works with the vercel-edge preset.

thunder87 avatar Nov 19 '24 11:11 thunder87

Any updates on this issue?

fiveam-lukas avatar Nov 27 '24 06:11 fiveam-lukas

@pi0 @TheAlexLichter Can you share some insight on wether this fix is planned and/or when to expect changes?

fiveam-lukas avatar Jan 27 '25 08:01 fiveam-lukas

Using vercel preset I get __nitro-?url= appended urls and using the vercel-edge preset: ?url=

As @CedsTrash, this only occurs on page refresh (SSR) with passQuery: true

isr: {
  expiration: 3600,
  allowQuery: ['token', 'preview-token'],
  passQuery: true,
},

passQuery also only works with the vercel-edge preset.

I'm having the same issue. Did you find a workaround?

Thank you in advance

plcdnl avatar Feb 16 '25 10:02 plcdnl

It takes hours to figure out. Why add ?url=$url? It seems useless. When set isr=false, it works normally. image

Nice catch! Would anybody know why this is appended to the URL?

@plcdnl see the code, the only way to avoid this is isr=false(with vercle-edge)

way-zer avatar Feb 16 '25 11:02 way-zer