N
Nuxt3d ago
Revadike

404 with SPA

I have a static site (ssr off) hosted on cloudflare pages. However, I have a problem with my dynamic paths (e.g. pages/apps/[id].vue), they always return 404. They are served fine luckily, but if you inspect network request they have 404 not found as statuscode. How can I fix this?
26 Replies
kapa.ai
kapa.ai3d ago
Hi @Revadike. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- When deploying a static Nuxt site (with ssr: false) to Cloudflare Pages, dynamic routes like /apps/[id] are generated as static HTML files (e.g., /apps/123/index.html). However, when a user navigates directly to a dynamic route (e.g., /apps/123), the static host (Cloudflare Pages) may not find a matching file and returns a 404 status, even though the SPA loads and renders the page correctly on the client side. Why does this happen? - Static hosts serve files based on the URL path. If a file for the exact path doesn't exist, a 404 is returned. - In SPA mode, Nuxt expects the static host to serve index.html for all routes, letting the client-side router handle the actual page rendering. How to fix this: You need to configure a "catch-all" or "fallback" so that all unknown routes serve your index.html file. This allows the SPA router to take over and render the correct page, and ensures the HTTP status is 200 instead of 404. For Cloudflare Pages, you can do this by adding a _routes.json or _redirects file, or by configuring the project settings to serve index.html for all unmatched routes. Unfortunately, the knowledge sources do not provide the exact file or setting for Cloudflare Pages, but this is the standard approach for static SPA hosting. Summary:
Your dynamic routes return 404 because the static host doesn't know to serve index.html for them. Configure a fallback so all routes serve index.html to fix the 404 status for dynamic SPA routes. If you need more specific instructions for Cloudflare Pages, the knowledge sources do not contain enough information to provide the exact configuration file or setting required. However, the general solution is as described above. For more on static hosting and SPA fallback in Nuxt, see the Nuxt deployment documentation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3d ago
<@172781195329798144> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Revadike
RevadikeOP3d ago
@kapa.ai There are thousands of id's so pre-generating a html page for each of these is out of the question. With redirects, can users still directly visit /apps/ID pages without being redirected to the website homepage? Or should I use routes? How does that work with dynamic urls?
kapa.ai
kapa.ai3d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- When using Nuxt with ssr: false (SPA mode) and static hosting, you do not need to pre-generate an HTML file for every possible dynamic ID (such as /apps/ID). Instead, you should configure your static host (e.g., Cloudflare Pages) to serve the main index.html file for all unknown routes. This allows the Nuxt client-side router to handle dynamic URLs like /apps/ID and render the correct page, without redirecting users to the homepage or requiring a separate HTML file for each ID. How it works: - When a user visits /apps/ID directly, the static host serves index.html. - Nuxt's client-side router reads the URL and loads the correct page/component (e.g., pages/apps/[id].vue). - The user sees the correct content for /apps/ID, not the homepage. Redirects vs. SPA Fallback: - A proper SPA fallback (serving index.html for all unknown routes) is not a redirect to the homepage; it simply allows the SPA to handle routing. - Users will see the correct dynamic page, not be redirected to /. Dynamic URLs: - Nuxt's file-based routing with dynamic segments (e.g., [id].vue) works seamlessly in SPA mode as long as the static host is configured to serve index.html for all routes that aren't actual files. You do not need to pre-generate every possible route, nor do you need to use server-side routes for this use case. The knowledge sources confirm that in SPA mode (ssr: false), Nuxt outputs a single index.html and JavaScript bundles, and you should configure your static host to serve index.html for all routes to enable client-side routing for dynamic URLs. This is the recommended approach for handling thousands of dynamic IDs without pre-generating each one Static Hosting. If you need to handle truly dynamic data (e.g., fetching content for each ID), you can do so in your page component using the ID from the route params.
The knowledge sources do not provide the exact Cloudflare Pages configuration, but the general Nuxt approach is as described above.
---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3d ago
<@172781195329798144> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Omnislash
Omnislash3d ago
I'm not in front of my computer rn but I have a ssr false project on cloudflare with dynamics route that work fine My guess is you use nuxi generate or something, or other configuration issue
Revadike
RevadikeOP3d ago
it works fine, but if you inspect the page requests, they return 404 as statuscode, which is undesired.
manniL
manniL3d ago
But that’s correct How would the server serving the SPA know whether the page can be resolved by Nuxt or not, all without a server running but with a static asset?
Revadike
RevadikeOP3d ago
magic? 🥹
Omnislash
Omnislash3d ago
compatibilityDate: '2024-04-03',
future: {
compatibilityVersion: 4
},
// devtools: { enabled: true },
ssr: false,
nitro: {
prerender: {
autoSubfolderIndex: false
}
},
runtimeConfig: {
public: {
apiScheme: 'http',
apiHost: 'localhost',
apiPort: '',
imageProvider: 'https://images.preprod.tech',
tfCertifId: '',
tfBookId: '',
},
},
routeRules: {
'*/account/**': { ssr: false },
'*/login/**': { ssr: false },
'/admin/**': { ssr: false },
'/operation/**': { ssr: false },
},
compatibilityDate: '2024-04-03',
future: {
compatibilityVersion: 4
},
// devtools: { enabled: true },
ssr: false,
nitro: {
prerender: {
autoSubfolderIndex: false
}
},
runtimeConfig: {
public: {
apiScheme: 'http',
apiHost: 'localhost',
apiPort: '',
imageProvider: 'https://images.preprod.tech',
tfCertifId: '',
tfBookId: '',
},
},
routeRules: {
'*/account/**': { ssr: false },
'*/login/**': { ssr: false },
'/admin/**': { ssr: false },
'/operation/**': { ssr: false },
},
Works for me (forgot to remove the the ssr false in the routes XD)
Revadike
RevadikeOP3d ago
maybe cloudflare pages can be configured to fix this
Omnislash
Omnislash3d ago
With the normal bulding ofc, not nuxi generate
Revadike
RevadikeOP3d ago
define works is your site public?
Omnislash
Omnislash3d ago
It's a b2b website but I have dynamic routes to load different properties and they work ^^" ? Nop :/ I can probably do it on a public website in a few hours ^^ And cloudflare conf is the default nuxt build cloudflare propose Gotta run, back in an hour or two
Revadike
RevadikeOP3d ago
My site is public https://steamkey.trade/app/1085660 as you can see, it "works" fine, but if you inspect network requests, you see it actually has a 404 statuscode
manniL
manniL3d ago
Use a running server is the magic then I think I’ve explained why the desired result can’t be achieved without having something responding dynamically and “knows how Nuxt will evaluate the requested page”
Revadike
RevadikeOP3d ago
i suppose hash dynamic routing could fix it @kapa.ai how can I configure cloudflare pages to do that?
kapa.ai
kapa.ai3d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I'm sorry, but the knowledge sources do not contain specific instructions or examples for configuring Cloudflare Pages to serve index.html for all unknown routes in a Nuxt SPA deployment. The general approach is described for static hosting with Nuxt, but there are no details about the exact configuration file or settings required for Cloudflare Pages in the provided sources. If you need more information, you may want to consult the official Cloudflare Pages documentation or Nuxt community discussions for up-to-date guidance on SPA fallback configuration for dynamic routes in Cloudflare Pages deployments. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3d ago
<@172781195329798144> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Revadike
RevadikeOP3d ago
Cloudflare Docs
Redirects
To apply custom redirects on Cloudflare Pages, declare your redirects in a plain text file called _redirects without a file extension, in the static asset directory of your project. This file will not itself be served as a static asset, but will instead be parsed by Cloudflare Pages and its rules will be applied to static asset responses.
manniL
manniL3d ago
Hash dynamic routing?
Revadike
RevadikeOP3d ago
Ok so, adding the following to my nuxt config
nitro: {
preset: 'cloudflare-pages',
prerender: {
ignore: ['/404']
}
},
nitro: {
preset: 'cloudflare-pages',
prerender: {
ignore: ['/404']
}
},
will disable nuxt generating a 404.html page. This will cause cloudflare pages to correctly assume it's a SPA: https://developers.cloudflare.com/pages/configuration/serving-pages/ I now no longer get 404 status when visiting dynamic pages, while still getting an error page for unknown pages (using error.vue and createError method). The only downside is it's not actually serving these requests with 404 statuscode for unknown pages, but that's still better than how it was before.
Omnislash
Omnislash3d ago
I'm back Never checked but it seems I indeed don't have this issue ? https://willyou404me.pages.dev/test/44 deploying this : https://github.com/ribbityfrog/nuxt-base/blob/nossr/nuxt.config.ts is that the use case you were expecting ?
Revadike
RevadikeOP3d ago
does your deployment include a 404.html?
Omnislash
Omnislash3d ago
Nop Or maybe it's still being generated if I don't create one ? The repo is public you can fork and deploy it and add what you want 🙂 The nossr branch, the main one will not compile
Revadike
RevadikeOP3d ago
well, that was my problem, i had to disable this

Did you find this page helpful?