Nuxt 3 - Nitro vercel-edge - Redirection problem on page load - URL parameter appended to URL
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
Hi @pi0 How can I provide a reproduction for this since it's specific to the vercel-edge preset? Thanks.
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 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.
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.
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.
Does someone have a clue on what's going on? I'm really stuck on this one and could really use some help. Thanks!
It takes hours to figure out.
Why add ?url=$url? It seems useless. When set isr=false, it works normally.
It takes hours to figure out.
Why add
?url=$url? It seems useless. When setisr=false, it works normally.
Nice catch! Would anybody know why this is appended to the URL?
Hi guys, anyone with a clue on how to solve this? Or at least on why ?url=$url is appendend on line 4241?
Thanks.
Hi guys, anyone with a clue on how to solve this? Or at least on why
?url=$urlis appendend on line 4241?Thanks.
workaround: set isr=false for all routes (As line 4233)
Hi guys, anyone with a clue on how to solve this? Or at least on why
?url=$urlis appendend on line 4241? Thanks.workaround: set
isr=falsefor all routes (As line 4233)
Yes, but I meant while keeping ISR enabled. Because I use ISR with ISR On-Demand Revalidation here
Maybe just modify line 4241. I don't know why the query is added.
And the generated result is same as isr=false
I’m also having this issue with vercel-edge and isr enabled.
Hi, is there any update on this issue? It's a shame not being able to benefit from the edge's speed.
Please check: https://nitro.build/deploy/providers/vercel#fine-grained-isr-config-via-route-rules (available in Nitro 2.10+)
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,
},
},
},
});
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.
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.
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.
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!
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.
This config maps to vercel build output API. More in their docs: https://vercel.com/docs/build-output-api/v3/primitives#prerender-configuration-file
@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 Thanks for your input. It helps knowing I'm not the only one :-)
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?
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.
Any updates on this issue?
@pi0 @TheAlexLichter Can you share some insight on wether this fix is planned and/or when to expect changes?
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: trueisr: { 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
It takes hours to figure out. Why add
?url=$url? It seems useless. When setisr=false, it works normally.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)
