Next.js: [RFC] Static Error Pages

Created on 26 Aug 2019  路  11Comments  路  Source: vercel/next.js

Goals

  • 404 being rendered statically

Background

Next.js has a special page rendered when errors happen, this page is internally called /_error and can be customized by users by creating a pages/_error.js file that exports a React Component.

The rendered errors are generally divided in 2 cases: expected errors and unexpected errors.

Expected errors are for example the 404 page. This be statically served because the rendered content does not change.

The unexpected errors can be for example when a user throws an error in getInitialProps or while rendering the React tree, which render a 500.

getInitialProps in pages/_error.js is currently used to report errors to error reporting tools, which is something to keep in mind for this proposal.

Furthermore when the server target is used (next start or custom server) rendering the 404 page causes load on the server instance, and there can be quite a lot of 404 requests as bots try to crawl certain files continuously. Even browsers trying to load a favicon.ico if none is provided cause 404 to be rendered.

On a serverless environment (like ZEIT Now) this is less of an issue as all routes are split and don't affect each other, however you'd pay for serverless invocations / duration even though the same exact page is rendered.

Another benefits of making the 404 page static is that it can be edge cached automatically when using a CDN.

Proposal

Considering _error is currently being used for reporting errors (both server and client-side) we can't statically render the 500 page.

However we can statically render the 404 page, as it doesn't change.

At build time we can render the /_error page to errors/404.html.

The Next.js server will be changed to use this file to serve 404 pages. This change also requires a few modifications to @now/next.

I assume there are quite a few cases where users have custom behavior related to _error, so we most likely need a way to opt-out of statically rendering the 404 page, if you do have such a case please do provide it in the comments as we'd love to know more.

Note: this is an extension of the automatic static optimization introduced in Next.js 9: https://nextjs.org/blog/next-9#automatic-static-optimization

Most helpful comment

I run one Next.js website where 404 page is dynamic. Say there are two existing products with similar slugs at /products/thing-a and /products/thing-b. When a user goes to a URL that cannot be unambiguously corrected (redirected) to one of the products (e.g. /products/thi), I show _Product not found_ and a list of products with similar slugs. That鈥檚 basically done by a GraphQL query with a current slug as a variable. When a 404 url does not match /products/*, it鈥檚 _Page not found_ instead of _Product not found_.

All 11 comments

Linking this to #7399

Would this use the same mechanism as auto static export: check if getInitialProps is used to opt out?

@quentin-sommer the problem here is that getInitialProps is implement in almost all cases because it's used for error reporting, we're planning to have an error reporting hook in the future which would make that specifically obsolete, however as of now we can't deopt based on getInitialProps being defined in pages/_error.

I run one Next.js website where 404 page is dynamic. Say there are two existing products with similar slugs at /products/thing-a and /products/thing-b. When a user goes to a URL that cannot be unambiguously corrected (redirected) to one of the products (e.g. /products/thi), I show _Product not found_ and a list of products with similar slugs. That鈥檚 basically done by a GraphQL query with a current slug as a variable. When a 404 url does not match /products/*, it鈥檚 _Page not found_ instead of _Product not found_.

I run a news Next.js site, and page 404 is dynamic. It suggests articles to the reader (most read, most commentend and so on)

Those don't necessarily have to block rendering / be server-side rendered right? You could do the fetches on the client side.

Perhaps the list of suggested news or products could be client-side rendered (although this is still worse than SSR because of flickering of what鈥檚 appearing on the page). However, if the header of 404 page says _Page not found / Product not found / Post not found_ based on path, guess this decision should be SSR for sure.

One more reason for rendering 404 dynamically in my projects is i18n. I鈥檓 using next-i18next and the language is configured to depend on the request鈥檚 host name. I鈥檇 need several static 404 pages with some custom routing rules to handle i18n without the dynamic _error.tsx

Those don't necessarily have to block rendering / be server-side rendered right? You could do the fetches on the client side.

maybe but it's not my decision to take

Really looking forward to this being implemented. I have a static next.js app deployed to ZEIT now, and 404 pages are the only ones that cause serverless invocations.

On a serverless environment (like ZEIT Now) this is less of an issue as all routes are split and don't affect each other, however you'd pay for serverless invocations / duration even though the same exact page is rendered.

Also - it took me a while to find this issue when I read the 9.1 release blog post - maybe add a link to this issue at the end of the "Static Error Pages" section?

This has been solved and released in Next.js 9.3: https://nextjs.org/blog/next-9-3#automatic-static-optimization-for-404

Was this page helpful?
0 / 5 - 0 ratings