vikejs / vike

🔨 Flexible, lean, community-driven, dependable, fast Vite-based frontend framework.
https://vike.dev
MIT License
4.27k stars 348 forks source link

Allow multiple error pages #1038

Open jamiehaywood opened 1 year ago

jamiehaywood commented 1 year ago

Description

Given this file structure in the pages/ dir:

.
└── foo
    ├── index.page.server.ts
    ├── error.page.tsx
    └── index.page.tsx

When an error is thrown inside index.page.server.ts or index.page.tsx, it would render the local error page before moving up to the error page defined in renderer/

The main benefit of this is to reduce the amount of logic held in the default _error.page.tsx, and reduce the amount of data being passed in the throw RenderErrorPage()

brillout commented 1 year ago

I agree and it's actually on the radar.

data being passed in the throw RenderErrorPage()

What data are you currently passing? I'm asking because throw RenderErrorPage() will be (soft-)deprecated in the next release in favor of this:

// Render the error page
render(statusCode: 401 | 403 | 404 | 429 | 500 | 503, abortReason?: string)

This means you won't be able to set arbitrary pageContext values anymore, but only pageContext.abortReason which needs to be a string. (You'll then be able to access and show pageContext.abortReason to your users in your error page.)

See discussion at https://github.com/brillout/vite-plugin-ssr/issues/926.

jamiehaywood commented 1 year ago

thanks for the quick reply.

At the moment I'm passing information that's contextual to the rendering of the 404 i.e:

throw RenderErrorPage({ venueNotFound: true, itemNotFound: true })

and then rendering the error page based on that data:

function Page({ venueNotFound, itemNotFound }: { venueNotFound: boolean; itemNotFound: boolean }) {
  if (venueNotFound || itemNotFound) {
    return (
      <>
        <h1>404 Page Not Found</h1>
        <p>This page could not be found.</p>
        {venueNotFound && (
          <p>
            <a href="/venues">Search venues</a>
          </p>
        )}
      ...
      </>
    );
  } 
}

I think your proposal is a good one. Would the render function be a special error render function, and where would this be used? My only thought around maintaining the ability to pass data other than an abortReason would be if you wanted to pass data to the error page originating from the server.

brillout commented 1 year ago

Actually, I'm realizing that pageContext.abortReason doesn't need to be a string (it does need to be serializable though). I'll make it that it can be any value, so that you'll be able to continue to do what you do.

where would this be used?

Same as throw RenderErrorPage().

As for the original request of having several error pages, note that it may take a little while since it isn't a top priority at the moment.

(Btw. sponsoring welcome and I'll then be more than happy to reconsider prioritization.)