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

adding a /404 route without app.add_custom_404_page breaks dynamic routes in prod mode #4438

Open
masenf opened this issue Nov 26, 2024 · 2 comments

Comments

@masenf
Copy link
Collaborator

masenf commented Nov 26, 2024

Describe the bug
Dynamic routes with a static export depends on being able to trigger client-side routing for non-existant files corresponding to the dynamic route. The static host should serve /404.html when the route is not found.

However, if the app adds a /404 page without the wait_for_client_redirect wrapper applied, then the resulting 404 page will not include the necessary logic to perform the redirect.

Instead of having a separate add_custom_404_page function, maybe the rx.App should just treat the /404 route specially and ensure that client redirect logic is included. The downside with this approach is there would be no way for the app to opt-out of client side redirection if that were desirable, although i don't know of a practical use case for opting out.

Specifics (please complete the following information):

  • Python Version: 3.12
  • Reflex Version: 0.6.5
@Cirr0e
Copy link

Cirr0e commented Nov 26, 2024

I understand you're encountering an issue where adding a /404 route directly breaks dynamic routes in production, because it bypasses the necessary client-side routing logic. Let me explain what's happening and propose a solution.

The root cause is that the /404 route requires special handling in Reflex. When you add a 404 page directly via app.add_page(), you're missing the crucial wait_for_client_redirect wrapper that's automatically applied when using app.add_custom_404_page(). This wrapper is essential because it:

  1. Prevents the 404 page from flashing while redirects are being processed
  2. Ensures proper handling of dynamic routes in static exports
  3. Manages the client-side routing state

Looking at the codebase, particularly in reflex/components/core/client_side_routing.py, I can see that this is by design:

def wait_for_client_redirect(component) -> Component:
    """Wait for a redirect to occur before rendering a component."""
    return cond(
        condition=route_not_found,
        c1=component,
        c2=ClientSideRouting.create(),
    )

For your specific case, I recommend:

  1. Either use the official add_custom_404_page method:
app.add_custom_404_page(
    your_404_component,
    title="Custom 404",
    description="Page not found"
)
  1. Or if you need to use add_page, manually wrap your component:
from reflex.components.core.client_side_routing import wait_for_client_redirect

app.add_page(
    component=wait_for_client_redirect(your_404_component),
    route="/404",
    title="Custom 404"
)

Regarding your suggestion about making rx.App treat the /404 route specially: While this could work, it might introduce some issues:

  1. It would be less explicit, making it harder to debug
  2. As you mentioned, it would remove the ability to opt-out
  3. It could cause confusion when developers expect regular route behavior

Be careful with:

  • Ensure you're testing dynamic routes in production mode
  • Remember that this behavior is specific to static exports
  • The client-side routing mechanism needs to be present for proper 404 handling

Let me know if you need any clarification or have questions about implementing either approach.

References:

  1. Client-side routing implementation: reflex/components/core/client_side_routing.py
  2. Custom 404 page handling: reflex/app.py in the add_custom_404_page method
  3. Client-side routing JS implementation: reflex/.templates/web/utils/client_side_routing.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants