Skip to content

fix: use static 404 for non-prerendered dynamic routes without fallback #1795

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

Merged
merged 9 commits into from
Dec 9, 2022
4 changes: 2 additions & 2 deletions cypress/integration/default/dynamic-routes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('Dynamic Routing', () => {
cy.request({ url: '/getStaticProps/3/', headers: { 'x-nf-debug-logging': '1' }, failOnStatusCode: false }).then(
(res) => {
expect(res.status).to.eq(404)
expect(res.headers).to.have.property('x-nf-render-mode', 'odb')
expect(res.headers).to.not.have.property('x-nf-render-mode')
expect(res.body).to.contain('Custom 404')
},
)
Expand Down Expand Up @@ -102,7 +102,7 @@ describe('Dynamic Routing', () => {
failOnStatusCode: false,
}).then((res) => {
expect(res.status).to.eq(404)
expect(res.headers).to.have.property('x-nf-render-mode', 'odb')
expect(res.headers).to.not.have.property('x-nf-render-mode')
expect(res.body).to.contain('Custom 404')
})
})
Expand Down
12 changes: 11 additions & 1 deletion packages/runtime/src/helpers/redirects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
isApiRoute,
redirectsForNextRoute,
redirectsForNextRouteWithData,
redirectsForNext404Route,
routeToDataRoute,
} from './utils'

Expand Down Expand Up @@ -187,13 +188,15 @@ const generateDynamicRewrites = ({
basePath,
buildId,
i18n,
is404Isr,
}: {
dynamicRoutes: RoutesManifest['dynamicRoutes']
prerenderedDynamicRoutes: PrerenderManifest['dynamicRoutes']
basePath: string
i18n: NextConfig['i18n']
buildId: string
middleware: Array<string>
is404Isr: boolean
}): {
dynamicRoutesThatMatchMiddleware: Array<string>
dynamicRewrites: NetlifyConfig['redirects']
Expand All @@ -207,9 +210,11 @@ const generateDynamicRewrites = ({
if (route.page in prerenderedDynamicRoutes) {
if (matchesMiddleware(middleware, route.page)) {
dynamicRoutesThatMatchMiddleware.push(route.page)
} else if (prerenderedDynamicRoutes[route.page].fallback === false && !is404Isr) {
dynamicRewrites.push(...redirectsForNext404Route({ route: route.page, buildId, basePath, i18n }))
} else {
dynamicRewrites.push(
...redirectsForNextRoute({ buildId, route: route.page, basePath, to: ODB_FUNCTION_PATH, status: 200, i18n }),
...redirectsForNextRoute({ route: route.page, buildId, basePath, to: ODB_FUNCTION_PATH, i18n }),
)
}
} else {
Expand Down Expand Up @@ -263,6 +268,10 @@ export const generateRedirects = async ({

const staticRouteEntries = Object.entries(prerenderedStaticRoutes)

const is404Isr = staticRouteEntries.some(
([route, { initialRevalidateSeconds }]) => is404Route(route, i18n) && initialRevalidateSeconds !== false,
)

const routesThatMatchMiddleware: Array<string> = []

const { staticRoutePaths, staticIsrRewrites, staticIsrRoutesThatMatchMiddleware } = generateStaticIsrRewrites({
Expand Down Expand Up @@ -295,6 +304,7 @@ export const generateRedirects = async ({
basePath,
buildId,
i18n,
is404Isr,
})
netlifyConfig.redirects.push(...dynamicRewrites)
routesThatMatchMiddleware.push(...dynamicRoutesThatMatchMiddleware)
Expand Down
40 changes: 36 additions & 4 deletions packages/runtime/src/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,18 @@ export const netlifyRoutesForNextRouteWithData = ({ route, dataRoute }: { route:
export const routeToDataRoute = (route: string, buildId: string, locale?: string) =>
`/_next/data/${buildId}${locale ? `/${locale}` : ''}${route === '/' ? '/index' : route}.json`

const netlifyRoutesForNextRoute = (route: string, buildId: string, i18n?: I18n): Array<string> => {
const netlifyRoutesForNextRoute = (
route: string,
buildId: string,
i18n?: I18n,
): Array<{ redirect: string; locale: string | false }> => {
if (!i18n?.locales?.length) {
return netlifyRoutesForNextRouteWithData({ route, dataRoute: routeToDataRoute(route, buildId) })
return netlifyRoutesForNextRouteWithData({ route, dataRoute: routeToDataRoute(route, buildId) }).map(
(redirect) => ({
redirect,
locale: false,
}),
)
}
const { locales, defaultLocale } = i18n
const routes = []
Expand All @@ -87,7 +96,10 @@ const netlifyRoutesForNextRoute = (route: string, buildId: string, i18n?: I18n):
...netlifyRoutesForNextRouteWithData({
route: locale === defaultLocale ? route : `/${locale}${route}`,
dataRoute,
}),
}).map((redirect) => ({
redirect,
locale,
})),
)
})
return routes
Expand Down Expand Up @@ -115,13 +127,33 @@ export const redirectsForNextRoute = ({
status?: number
force?: boolean
}): NetlifyConfig['redirects'] =>
netlifyRoutesForNextRoute(route, buildId, i18n).map((redirect) => ({
netlifyRoutesForNextRoute(route, buildId, i18n).map(({ redirect }) => ({
from: `${basePath}${redirect}`,
to,
status,
force,
}))

export const redirectsForNext404Route = ({
route,
buildId,
basePath,
i18n,
force = false,
}: {
route: string
buildId: string
basePath: string
i18n: I18n
force?: boolean
}): NetlifyConfig['redirects'] =>
netlifyRoutesForNextRoute(route, buildId, i18n).map(({ redirect, locale }) => ({
from: `${basePath}${redirect}`,
to: locale ? `${basePath}/server/pages/${locale}/404.html` : `${basePath}/server/pages/404.html`,
status: 404,
force,
}))

export const redirectsForNextRouteWithData = ({
route,
dataRoute,
Expand Down