From 05f528fe3b179c86bf546022d992db70f7c45b90 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Thu, 27 Apr 2023 14:36:37 -0500 Subject: [PATCH 01/18] fix: legacy fallback env var --- packages/runtime/src/helpers/redirects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/helpers/redirects.ts b/packages/runtime/src/helpers/redirects.ts index c1710bf7b2..9a97beb946 100644 --- a/packages/runtime/src/helpers/redirects.ts +++ b/packages/runtime/src/helpers/redirects.ts @@ -238,7 +238,7 @@ const generateDynamicRewrites = ({ withData: true, }), ) - } else if (prerenderedDynamicRoutes[route.page].fallback === false && !is404Isr) { + } else if (prerenderedDynamicRoutes[route.page].fallback === false && !is404Isr && !process.env.LEGACY_FALLBACK_FALSE) { dynamicRewrites.push(...redirectsForNext404Route({ route: route.page, buildId, basePath, i18n })) } else { dynamicRewrites.push( From 6fbf91fc67ce86c865d025049f3a6e8b7518405e Mon Sep 17 00:00:00 2001 From: taty2010 Date: Thu, 27 Apr 2023 14:37:30 -0500 Subject: [PATCH 02/18] chore: prettier --- packages/runtime/src/helpers/redirects.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/helpers/redirects.ts b/packages/runtime/src/helpers/redirects.ts index 9a97beb946..ba8b4def45 100644 --- a/packages/runtime/src/helpers/redirects.ts +++ b/packages/runtime/src/helpers/redirects.ts @@ -238,7 +238,11 @@ const generateDynamicRewrites = ({ withData: true, }), ) - } else if (prerenderedDynamicRoutes[route.page].fallback === false && !is404Isr && !process.env.LEGACY_FALLBACK_FALSE) { + } else if ( + prerenderedDynamicRoutes[route.page].fallback === false && + !is404Isr && + !process.env.LEGACY_FALLBACK_FALSE + ) { dynamicRewrites.push(...redirectsForNext404Route({ route: route.page, buildId, basePath, i18n })) } else { dynamicRewrites.push( From 8f58d0277b47cbafe39aa4c1a1e8f428d2257a16 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 28 Apr 2023 00:49:35 -0500 Subject: [PATCH 03/18] chore: added tests --- cypress/e2e/default/dynamic-routes.cy.ts | 10 ++++ cypress/e2e/default/rewrites-redirects.cy.ts | 6 +++ demos/default/next.config.js | 5 ++ package-lock.json | 57 ++++++++++++-------- 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/cypress/e2e/default/dynamic-routes.cy.ts b/cypress/e2e/default/dynamic-routes.cy.ts index 266f6faa43..13e7ef4a99 100644 --- a/cypress/e2e/default/dynamic-routes.cy.ts +++ b/cypress/e2e/default/dynamic-routes.cy.ts @@ -54,6 +54,16 @@ describe('Dynamic Routing', () => { }, ) }) + it('fallback:false and LEGACY_FALLBACK_FALSE=true does not return static 404', () => { + Cypress.env('LEGACY_FALLBACK_FALSE', 'true') + 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') + expect(res.body).to.contain('Custom 404') + }, + ) + }) it('serves correct static file on a prerendered dynamic route with fallback: true', () => { cy.request({ url: '/getStaticProps/withFallback/1/', headers: { 'x-nf-debug-logging': '1' } }).then((res) => { expect(res.status).to.eq(200) diff --git a/cypress/e2e/default/rewrites-redirects.cy.ts b/cypress/e2e/default/rewrites-redirects.cy.ts index 1462f7aef0..7b6cc61e79 100644 --- a/cypress/e2e/default/rewrites-redirects.cy.ts +++ b/cypress/e2e/default/rewrites-redirects.cy.ts @@ -18,4 +18,10 @@ describe('Rewrites and Redirects', () => { cy.url().should('eq', `${Cypress.config().baseUrl}/`) } ) + + it('redirects /getStaticProps/4 to / on LEGACY_', () => { + Cypress.env('LEGACY_FALLBACK_FALSE', 'true') + cy.visit('/getStaticProps/4') + cy.url().should('eq', `${Cypress.config().baseUrl}/`) + }) }) \ No newline at end of file diff --git a/demos/default/next.config.js b/demos/default/next.config.js index 890533b532..c81e87d68d 100644 --- a/demos/default/next.config.js +++ b/demos/default/next.config.js @@ -67,6 +67,11 @@ module.exports = { destination: '/', permanent: true, }, + { + source: '/getStaticProps/4/', + destination: '/', + permanent: true, + }, ] }, // https://nextjs.org/docs/basic-features/image-optimization#domains diff --git a/package-lock.json b/package-lock.json index 0a8432e482..b2678ef756 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6042,13 +6042,13 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.0.38", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.38.tgz", "integrity": "sha512-ExsidLLSzYj4cvaQjGnQCk4HFfVT9+EZ9XZsQ8Hsrcn8QNgXtpZ3m9vSIC2MWtx7jHictK6wYhQgGh6ic58oOw==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -6074,7 +6074,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "devOptional": true }, "node_modules/@types/semver": { "version": "7.3.13", @@ -9729,7 +9729,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true + "devOptional": true }, "node_modules/custom-routes": { "resolved": "demos/custom-routes", @@ -14219,7 +14219,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", - "dev": true + "devOptional": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -21405,7 +21405,7 @@ "version": "1.56.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", - "dev": true, + "devOptional": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -28549,13 +28549,13 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "devOptional": true }, "@types/react": { "version": "18.0.38", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.38.tgz", "integrity": "sha512-ExsidLLSzYj4cvaQjGnQCk4HFfVT9+EZ9XZsQ8Hsrcn8QNgXtpZ3m9vSIC2MWtx7jHictK6wYhQgGh6ic58oOw==", - "dev": true, + "devOptional": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -28581,7 +28581,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "devOptional": true }, "@types/semver": { "version": "7.3.13", @@ -28896,7 +28896,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "acorn-walk": { "version": "7.2.0", @@ -28953,7 +28954,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", - "dev": true + "dev": true, + "requires": {} }, "ansi-colors": { "version": "4.1.3", @@ -30817,7 +30819,8 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.2.0.tgz", "integrity": "sha512-NkANeMnaHrlaSSlpKGyvn2R4rqUDeE/9E5YHx+b4nwo0R8dZyAqcih8/gxpCZvqWP9Vf6xuLpMSzSgdVEIM78g==", - "dev": true + "dev": true, + "requires": {} }, "cp-file": { "version": "10.0.0", @@ -31367,7 +31370,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true + "devOptional": true }, "custom-routes": { "version": "file:demos/custom-routes", @@ -32579,13 +32582,15 @@ "version": "8.5.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true + "dev": true, + "requires": {} }, "eslint-config-standard": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", - "dev": true + "dev": true, + "requires": {} }, "eslint-formatter-codeframe": { "version": "7.32.1", @@ -33031,7 +33036,8 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", - "dev": true + "dev": true, + "requires": {} }, "eslint-plugin-react": { "version": "7.31.10", @@ -33089,7 +33095,8 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true + "dev": true, + "requires": {} }, "eslint-plugin-unicorn": { "version": "43.0.2", @@ -34726,7 +34733,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", - "dev": true + "devOptional": true }, "import-fresh": { "version": "3.3.0", @@ -35879,7 +35886,8 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true + "dev": true, + "requires": {} }, "jest-regex-util": { "version": "27.5.1", @@ -39363,7 +39371,8 @@ "version": "8.9.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", - "dev": true + "dev": true, + "requires": {} } } }, @@ -40151,7 +40160,7 @@ "version": "1.56.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", - "dev": true, + "devOptional": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -41855,7 +41864,8 @@ "ws": { "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==" + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "requires": {} } } }, @@ -42266,7 +42276,8 @@ "version": "7.5.9", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "dev": true + "dev": true, + "requires": {} }, "xml": { "version": "1.0.1", From 66d61c0b9cd183e3bf42ac5292277d11d8cafcd7 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 28 Apr 2023 01:01:13 -0500 Subject: [PATCH 04/18] chore: added failOnStatusCode: false --- cypress/e2e/default/rewrites-redirects.cy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/default/rewrites-redirects.cy.ts b/cypress/e2e/default/rewrites-redirects.cy.ts index 7b6cc61e79..6594d49639 100644 --- a/cypress/e2e/default/rewrites-redirects.cy.ts +++ b/cypress/e2e/default/rewrites-redirects.cy.ts @@ -18,10 +18,10 @@ describe('Rewrites and Redirects', () => { cy.url().should('eq', `${Cypress.config().baseUrl}/`) } ) - + it('redirects /getStaticProps/4 to / on LEGACY_', () => { Cypress.env('LEGACY_FALLBACK_FALSE', 'true') - cy.visit('/getStaticProps/4') + cy.visit('/getStaticProps/4', { failOnStatusCode: false }) cy.url().should('eq', `${Cypress.config().baseUrl}/`) }) }) \ No newline at end of file From c11218b7e97f5f17e2dab5ca0f187f63c721c6b2 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 28 Apr 2023 09:35:30 -0500 Subject: [PATCH 05/18] fix: removed redirect test and odb check for dynamic tests --- cypress/e2e/default/dynamic-routes.cy.ts | 2 +- cypress/e2e/default/rewrites-redirects.cy.ts | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/cypress/e2e/default/dynamic-routes.cy.ts b/cypress/e2e/default/dynamic-routes.cy.ts index 13e7ef4a99..01b5649ffe 100644 --- a/cypress/e2e/default/dynamic-routes.cy.ts +++ b/cypress/e2e/default/dynamic-routes.cy.ts @@ -59,7 +59,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') + expect(res.headers).to.have.property('x-nf-render-mode', 'odb') expect(res.body).to.contain('Custom 404') }, ) diff --git a/cypress/e2e/default/rewrites-redirects.cy.ts b/cypress/e2e/default/rewrites-redirects.cy.ts index 6594d49639..1462f7aef0 100644 --- a/cypress/e2e/default/rewrites-redirects.cy.ts +++ b/cypress/e2e/default/rewrites-redirects.cy.ts @@ -18,10 +18,4 @@ describe('Rewrites and Redirects', () => { cy.url().should('eq', `${Cypress.config().baseUrl}/`) } ) - - it('redirects /getStaticProps/4 to / on LEGACY_', () => { - Cypress.env('LEGACY_FALLBACK_FALSE', 'true') - cy.visit('/getStaticProps/4', { failOnStatusCode: false }) - cy.url().should('eq', `${Cypress.config().baseUrl}/`) - }) }) \ No newline at end of file From aca6961adaf5303564d7241934ad43ea51e40ec4 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 28 Apr 2023 17:53:29 -0500 Subject: [PATCH 06/18] chore: removed cy test and added unit test --- cypress/e2e/default/dynamic-routes.cy.ts | 10 -- test/helpers/utils.spec.ts | 128 +++++++++++++++++++++++ 2 files changed, 128 insertions(+), 10 deletions(-) diff --git a/cypress/e2e/default/dynamic-routes.cy.ts b/cypress/e2e/default/dynamic-routes.cy.ts index 01b5649ffe..266f6faa43 100644 --- a/cypress/e2e/default/dynamic-routes.cy.ts +++ b/cypress/e2e/default/dynamic-routes.cy.ts @@ -54,16 +54,6 @@ describe('Dynamic Routing', () => { }, ) }) - it('fallback:false and LEGACY_FALLBACK_FALSE=true does not return static 404', () => { - Cypress.env('LEGACY_FALLBACK_FALSE', 'true') - 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.body).to.contain('Custom 404') - }, - ) - }) it('serves correct static file on a prerendered dynamic route with fallback: true', () => { cy.request({ url: '/getStaticProps/withFallback/1/', headers: { 'x-nf-debug-logging': '1' } }).then((res) => { expect(res.status).to.eq(200) diff --git a/test/helpers/utils.spec.ts b/test/helpers/utils.spec.ts index e02bd3fb42..7b14346d7a 100644 --- a/test/helpers/utils.spec.ts +++ b/test/helpers/utils.spec.ts @@ -1,11 +1,22 @@ import Chance from 'chance' import { ExperimentalConfig } from 'next/dist/server/config-shared' +import type { PrerenderManifest } from 'next/dist/build' +import { generateDynamicRewrites } from '../../packages/runtime/src/helpers/redirects' import { getCustomImageResponseHeaders, getRemotePatterns, ImagesConfig, redirectsForNext404Route, } from '../../packages/runtime/src/helpers/utils' +import { getMiddleware } from '../../packages/runtime/src/helpers/files' +import path from "path" + +const basePrerenderManifest: PrerenderManifest = { + version: 3, + routes: {}, + dynamicRoutes: {}, + notFoundRoutes: [], +} const chance = new Chance() @@ -131,4 +142,121 @@ describe('redirectsForNext404Route', () => { { force: false, from: '/fr/test', status: 404, to: '/server/pages/fr/404.html' }, ]) }) + + it.only('returns static 404 redirects when LEGACY_FALLBACK_FALSE is not set', async () => { + const prerenderManifest: PrerenderManifest = { + ...basePrerenderManifest, + dynamicRoutes: { + "/getStaticProps/[id]": { + "routeRegex": "^/getStaticProps/([^/]+?)(?:/)?$", + "dataRoute": "/_next/data/build-id/getStaticProps/[id].json", + "fallback": false, + "dataRouteRegex": "^/_next/data/build\\-id/getStaticProps/([^/]+?)\\.json$" + }, + }, + } + + const dynamicRoutes = [ + { + "page": "/getStaticProps/[id]", + "regex": "^/getStaticProps/([^/]+?)(?:/)?$", + "routeKeys": { + "nextParamid": "nextParamid" + }, + "namedRegex": "^/getStaticProps/(?[^/]+?)(?:/)?$" + }, + ] + + const middleware = await getMiddleware(path.resolve('.next')) + + const route = { + dynamicRoutes, + prerenderedDynamicRoutes: prerenderManifest.dynamicRoutes, + basePath: '', + i18n: null, + buildId: 'test', + middleware, + is404Isr: false, + } + + const expected = { + "dynamicRewrites": [ + { + "force": false, + "from": "/_next/data/test/getStaticProps/:id.json", + "status": 404, + "to": "/server/pages/404.html", + }, + { + "force": false, + "from": "/getStaticProps/:id", + "status": 404, + "to": "/server/pages/404.html", + } + ], + "dynamicRoutesThatMatchMiddleware": [] + } + + expect(generateDynamicRewrites(route)).toStrictEqual(expected) + }) + + it.only('does not return static 404 redirects when LEGACY_FALLBACK_FALSE is true', async () => { + process.env.LEGACY_FALLBACK_FALSE = 'true' + + const prerenderManifest: PrerenderManifest = { + ...basePrerenderManifest, + dynamicRoutes: { + "/getStaticProps/[id]": { + "routeRegex": "^/getStaticProps/([^/]+?)(?:/)?$", + "dataRoute": "/_next/data/build-id/getStaticProps/[id].json", + "fallback": false, + "dataRouteRegex": "^/_next/data/build\\-id/getStaticProps/([^/]+?)\\.json$" + }, + }, + } + + const dynamicRoutes = [ + { + "page": "/getStaticProps/[id]", + "regex": "^/getStaticProps/([^/]+?)(?:/)?$", + "routeKeys": { + "nextParamid": "nextParamid" + }, + "namedRegex": "^/getStaticProps/(?[^/]+?)(?:/)?$" + }, + ] + + const middleware = await getMiddleware(path.resolve('.next')) + + const route = { + dynamicRoutes, + prerenderedDynamicRoutes: prerenderManifest.dynamicRoutes, + basePath: '', + i18n: null, + buildId: 'test', + middleware, + is404Isr: false, + } + + const expected = { + "dynamicRewrites": [ + { + "force": false, + "from": "/_next/data/test/getStaticProps/:id.json", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, + { + "force": false, + "from": "/getStaticProps/:id", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + } + ], + "dynamicRoutesThatMatchMiddleware": [] + } + + expect(generateDynamicRewrites(route)).toStrictEqual(expected) + }) }) + From cabf05982d2ebf97d4f53702acdbae9366fc1bae Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 28 Apr 2023 18:10:02 -0500 Subject: [PATCH 07/18] fix: forgot to export --- packages/runtime/src/helpers/redirects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/helpers/redirects.ts b/packages/runtime/src/helpers/redirects.ts index ba8b4def45..e2651bc4c1 100644 --- a/packages/runtime/src/helpers/redirects.ts +++ b/packages/runtime/src/helpers/redirects.ts @@ -194,7 +194,7 @@ const generateStaticIsrRewrites = ({ /** * Generate rewrites for all dynamic routes */ -const generateDynamicRewrites = ({ +export const generateDynamicRewrites = ({ dynamicRoutes, prerenderedDynamicRoutes, middleware, From a949179e6d79b82eb96e0a0517dc3528e2a66239 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Mon, 1 May 2023 09:36:53 -0500 Subject: [PATCH 08/18] chore: updated readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5c6d561c27..d902eafbd7 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,10 @@ The Next.js Runtime fully supports ISR on Netlify. For more details see Note that Netlify has a minimum TTL of 60 seconds for revalidation. +## Disable Static 404 on Dynamic Routes with fallback:false + +Currently when hitting a non-prerendered path with `fallback=false` it will default to a 404 page. You can now change this default setting by using the environemnt variable `LEGACY_FALLBACK_FALSE=true`. With the environment variable set, those non-prerendered paths will now be routed through using the ISR Handler and will allow you to add redirects for those non-prerendered paths. + ## Use with `next export` If you are using `next export` to generate a static site, you do not need most of the functionality of this Next.js From 81554c85588f3531b7d135ba39809f2a0d2020a9 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Mon, 1 May 2023 14:54:04 -0500 Subject: [PATCH 09/18] chore: remove it.only from tests --- test/helpers/utils.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/helpers/utils.spec.ts b/test/helpers/utils.spec.ts index 7b14346d7a..c6e915b2be 100644 --- a/test/helpers/utils.spec.ts +++ b/test/helpers/utils.spec.ts @@ -143,7 +143,7 @@ describe('redirectsForNext404Route', () => { ]) }) - it.only('returns static 404 redirects when LEGACY_FALLBACK_FALSE is not set', async () => { + it('returns static 404 redirects when LEGACY_FALLBACK_FALSE is not set', async () => { const prerenderManifest: PrerenderManifest = { ...basePrerenderManifest, dynamicRoutes: { @@ -200,7 +200,7 @@ describe('redirectsForNext404Route', () => { expect(generateDynamicRewrites(route)).toStrictEqual(expected) }) - it.only('does not return static 404 redirects when LEGACY_FALLBACK_FALSE is true', async () => { + it('does not return static 404 redirects when LEGACY_FALLBACK_FALSE is true', async () => { process.env.LEGACY_FALLBACK_FALSE = 'true' const prerenderManifest: PrerenderManifest = { From 457ba6aa5f9655b710e7f2dc8879cc2032992999 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Wed, 3 May 2023 12:55:58 -0500 Subject: [PATCH 10/18] fix: use destr --- packages/runtime/src/helpers/redirects.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/helpers/redirects.ts b/packages/runtime/src/helpers/redirects.ts index e2651bc4c1..1375bc4472 100644 --- a/packages/runtime/src/helpers/redirects.ts +++ b/packages/runtime/src/helpers/redirects.ts @@ -1,5 +1,6 @@ import type { NetlifyConfig } from '@netlify/build' import { yellowBright } from 'chalk' +import destr from 'destr' import { readJSON } from 'fs-extra' import type { NextConfig } from 'next' import type { PrerenderManifest, SsgRoute } from 'next/dist/build' @@ -241,7 +242,7 @@ export const generateDynamicRewrites = ({ } else if ( prerenderedDynamicRoutes[route.page].fallback === false && !is404Isr && - !process.env.LEGACY_FALLBACK_FALSE + !destr(process.env.LEGACY_FALLBACK_FALSE) ) { dynamicRewrites.push(...redirectsForNext404Route({ route: route.page, buildId, basePath, i18n })) } else { From d4876f7a7453d8ad7056ca2b8af2b23969481d84 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Wed, 3 May 2023 14:15:08 -0500 Subject: [PATCH 11/18] chore: refactored tests --- test/helpers/utils.spec.ts | 130 +++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 71 deletions(-) diff --git a/test/helpers/utils.spec.ts b/test/helpers/utils.spec.ts index c6e915b2be..21f44a6e67 100644 --- a/test/helpers/utils.spec.ts +++ b/test/helpers/utils.spec.ts @@ -8,8 +8,6 @@ import { ImagesConfig, redirectsForNext404Route, } from '../../packages/runtime/src/helpers/utils' -import { getMiddleware } from '../../packages/runtime/src/helpers/files' -import path from "path" const basePrerenderManifest: PrerenderManifest = { version: 3, @@ -18,6 +16,39 @@ const basePrerenderManifest: PrerenderManifest = { notFoundRoutes: [], } +const prerenderManifest: PrerenderManifest = { + ...basePrerenderManifest, + dynamicRoutes: { + "/getStaticProps/[id]": { + "routeRegex": "^/getStaticProps/([^/]+?)(?:/)?$", + "dataRoute": "/_next/data/build-id/getStaticProps/[id].json", + "fallback": false, + "dataRouteRegex": "^/_next/data/build\\-id/getStaticProps/([^/]+?)\\.json$" + }, + }, +} + +const dynamicRoutes = [ + { + "page": "/getStaticProps/[id]", + "regex": "^/getStaticProps/([^/]+?)(?:/)?$", + "routeKeys": { + "nextParamid": "nextParamid" + }, + "namedRegex": "^/getStaticProps/(?[^/]+?)(?:/)?$" +}, +] + +const route = { + dynamicRoutes, + prerenderedDynamicRoutes: prerenderManifest.dynamicRoutes, + basePath: '', + i18n: null, + buildId: 'test', + middleware: [], + is404Isr: false, +} + const chance = new Chance() describe('getCustomImageResponseHeaders', () => { @@ -144,40 +175,6 @@ describe('redirectsForNext404Route', () => { }) it('returns static 404 redirects when LEGACY_FALLBACK_FALSE is not set', async () => { - const prerenderManifest: PrerenderManifest = { - ...basePrerenderManifest, - dynamicRoutes: { - "/getStaticProps/[id]": { - "routeRegex": "^/getStaticProps/([^/]+?)(?:/)?$", - "dataRoute": "/_next/data/build-id/getStaticProps/[id].json", - "fallback": false, - "dataRouteRegex": "^/_next/data/build\\-id/getStaticProps/([^/]+?)\\.json$" - }, - }, - } - - const dynamicRoutes = [ - { - "page": "/getStaticProps/[id]", - "regex": "^/getStaticProps/([^/]+?)(?:/)?$", - "routeKeys": { - "nextParamid": "nextParamid" - }, - "namedRegex": "^/getStaticProps/(?[^/]+?)(?:/)?$" - }, - ] - - const middleware = await getMiddleware(path.resolve('.next')) - - const route = { - dynamicRoutes, - prerenderedDynamicRoutes: prerenderManifest.dynamicRoutes, - basePath: '', - i18n: null, - buildId: 'test', - middleware, - is404Isr: false, - } const expected = { "dynamicRewrites": [ @@ -203,41 +200,6 @@ describe('redirectsForNext404Route', () => { it('does not return static 404 redirects when LEGACY_FALLBACK_FALSE is true', async () => { process.env.LEGACY_FALLBACK_FALSE = 'true' - const prerenderManifest: PrerenderManifest = { - ...basePrerenderManifest, - dynamicRoutes: { - "/getStaticProps/[id]": { - "routeRegex": "^/getStaticProps/([^/]+?)(?:/)?$", - "dataRoute": "/_next/data/build-id/getStaticProps/[id].json", - "fallback": false, - "dataRouteRegex": "^/_next/data/build\\-id/getStaticProps/([^/]+?)\\.json$" - }, - }, - } - - const dynamicRoutes = [ - { - "page": "/getStaticProps/[id]", - "regex": "^/getStaticProps/([^/]+?)(?:/)?$", - "routeKeys": { - "nextParamid": "nextParamid" - }, - "namedRegex": "^/getStaticProps/(?[^/]+?)(?:/)?$" - }, - ] - - const middleware = await getMiddleware(path.resolve('.next')) - - const route = { - dynamicRoutes, - prerenderedDynamicRoutes: prerenderManifest.dynamicRoutes, - basePath: '', - i18n: null, - buildId: 'test', - middleware, - is404Isr: false, - } - const expected = { "dynamicRewrites": [ { @@ -258,5 +220,31 @@ describe('redirectsForNext404Route', () => { expect(generateDynamicRewrites(route)).toStrictEqual(expected) }) + + it('returns static 404 redirects when LEGACY_FALLBACK_FALSE is set as "false"', async () => { + // testing to make sure that the any other string other than 'true' still returns the static 404 redirects + process.env.LEGACY_FALLBACK_FALSE = 'false' + + const expected = { + "dynamicRewrites": [ + { + "force": false, + "from": "/_next/data/test/getStaticProps/:id.json", + "status": 404, + "to": "/server/pages/404.html", + }, + { + "force": false, + "from": "/getStaticProps/:id", + "status": 404, + "to": "/server/pages/404.html", + } + ], + "dynamicRoutesThatMatchMiddleware": [] + } + + expect(generateDynamicRewrites(route)).toStrictEqual(expected) + }) }) + From a52411b658f40c4e35d1598b2d0a299505c3e703 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Wed, 3 May 2023 14:32:14 -0500 Subject: [PATCH 12/18] fix: imports --- test/helpers/utils.spec.ts | 113 ++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 58 deletions(-) diff --git a/test/helpers/utils.spec.ts b/test/helpers/utils.spec.ts index 10d87f9df8..24c0f80330 100644 --- a/test/helpers/utils.spec.ts +++ b/test/helpers/utils.spec.ts @@ -1,8 +1,8 @@ import Chance from 'chance' -import { ExperimentalConfig } from 'next/dist/server/config-shared' import type { PrerenderManifest } from 'next/dist/build' -import { generateDynamicRewrites } from '../../packages/runtime/src/helpers/redirects' +import { ExperimentalConfig } from 'next/dist/server/config-shared' +import { generateDynamicRewrites } from '../../packages/runtime/src/helpers/redirects' import { getCustomImageResponseHeaders, getRemotePatterns, @@ -20,24 +20,24 @@ const basePrerenderManifest: PrerenderManifest = { const prerenderManifest: PrerenderManifest = { ...basePrerenderManifest, dynamicRoutes: { - "/getStaticProps/[id]": { - "routeRegex": "^/getStaticProps/([^/]+?)(?:/)?$", - "dataRoute": "/_next/data/build-id/getStaticProps/[id].json", - "fallback": false, - "dataRouteRegex": "^/_next/data/build\\-id/getStaticProps/([^/]+?)\\.json$" - }, + '/getStaticProps/[id]': { + routeRegex: '^/getStaticProps/([^/]+?)(?:/)?$', + dataRoute: '/_next/data/build-id/getStaticProps/[id].json', + fallback: false, + dataRouteRegex: '^/_next/data/build\\-id/getStaticProps/([^/]+?)\\.json$', + }, }, } const dynamicRoutes = [ { - "page": "/getStaticProps/[id]", - "regex": "^/getStaticProps/([^/]+?)(?:/)?$", - "routeKeys": { - "nextParamid": "nextParamid" + page: '/getStaticProps/[id]', + regex: '^/getStaticProps/([^/]+?)(?:/)?$', + routeKeys: { + nextParamid: 'nextParamid', }, - "namedRegex": "^/getStaticProps/(?[^/]+?)(?:/)?$" -}, + namedRegex: '^/getStaticProps/(?[^/]+?)(?:/)?$', + }, ] const route = { @@ -176,23 +176,22 @@ describe('redirectsForNext404Route', () => { }) it('returns static 404 redirects when LEGACY_FALLBACK_FALSE is not set', async () => { - const expected = { - "dynamicRewrites": [ + dynamicRewrites: [ { - "force": false, - "from": "/_next/data/test/getStaticProps/:id.json", - "status": 404, - "to": "/server/pages/404.html", - }, + force: false, + from: '/_next/data/test/getStaticProps/:id.json', + status: 404, + to: '/server/pages/404.html', + }, { - "force": false, - "from": "/getStaticProps/:id", - "status": 404, - "to": "/server/pages/404.html", - } - ], - "dynamicRoutesThatMatchMiddleware": [] + force: false, + from: '/getStaticProps/:id', + status: 404, + to: '/server/pages/404.html', + }, + ], + dynamicRoutesThatMatchMiddleware: [], } expect(generateDynamicRewrites(route)).toStrictEqual(expected) @@ -202,21 +201,21 @@ describe('redirectsForNext404Route', () => { process.env.LEGACY_FALLBACK_FALSE = 'true' const expected = { - "dynamicRewrites": [ + dynamicRewrites: [ { - "force": false, - "from": "/_next/data/test/getStaticProps/:id.json", - "status": 200, - "to": "/.netlify/builders/___netlify-odb-handler", - }, + force: false, + from: '/_next/data/test/getStaticProps/:id.json', + status: 200, + to: '/.netlify/builders/___netlify-odb-handler', + }, { - "force": false, - "from": "/getStaticProps/:id", - "status": 200, - "to": "/.netlify/builders/___netlify-odb-handler", - } - ], - "dynamicRoutesThatMatchMiddleware": [] + force: false, + from: '/getStaticProps/:id', + status: 200, + to: '/.netlify/builders/___netlify-odb-handler', + }, + ], + dynamicRoutesThatMatchMiddleware: [], } expect(generateDynamicRewrites(route)).toStrictEqual(expected) @@ -225,27 +224,25 @@ describe('redirectsForNext404Route', () => { it('returns static 404 redirects when LEGACY_FALLBACK_FALSE is set as "false"', async () => { // testing to make sure that the any other string other than 'true' still returns the static 404 redirects process.env.LEGACY_FALLBACK_FALSE = 'false' - + const expected = { - "dynamicRewrites": [ + dynamicRewrites: [ { - "force": false, - "from": "/_next/data/test/getStaticProps/:id.json", - "status": 404, - "to": "/server/pages/404.html", - }, + force: false, + from: '/_next/data/test/getStaticProps/:id.json', + status: 404, + to: '/server/pages/404.html', + }, { - "force": false, - "from": "/getStaticProps/:id", - "status": 404, - "to": "/server/pages/404.html", - } - ], - "dynamicRoutesThatMatchMiddleware": [] + force: false, + from: '/getStaticProps/:id', + status: 404, + to: '/server/pages/404.html', + }, + ], + dynamicRoutesThatMatchMiddleware: [], } - + expect(generateDynamicRewrites(route)).toStrictEqual(expected) }) }) - - From ebec9b5b1ab75a98d3091623df629056ad847057 Mon Sep 17 00:00:00 2001 From: Tatyana <43764894+taty2010@users.noreply.github.com> Date: Wed, 3 May 2023 22:38:09 -0500 Subject: [PATCH 13/18] Update test/helpers/utils.spec.ts Co-authored-by: Nick Taylor --- test/helpers/utils.spec.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/test/helpers/utils.spec.ts b/test/helpers/utils.spec.ts index 24c0f80330..f8b4859a05 100644 --- a/test/helpers/utils.spec.ts +++ b/test/helpers/utils.spec.ts @@ -221,28 +221,4 @@ describe('redirectsForNext404Route', () => { expect(generateDynamicRewrites(route)).toStrictEqual(expected) }) - it('returns static 404 redirects when LEGACY_FALLBACK_FALSE is set as "false"', async () => { - // testing to make sure that the any other string other than 'true' still returns the static 404 redirects - process.env.LEGACY_FALLBACK_FALSE = 'false' - - const expected = { - dynamicRewrites: [ - { - force: false, - from: '/_next/data/test/getStaticProps/:id.json', - status: 404, - to: '/server/pages/404.html', - }, - { - force: false, - from: '/getStaticProps/:id', - status: 404, - to: '/server/pages/404.html', - }, - ], - dynamicRoutesThatMatchMiddleware: [], - } - - expect(generateDynamicRewrites(route)).toStrictEqual(expected) - }) }) From 5e2e702af3c0d29b14d5f65b652474aee0bf7a4b Mon Sep 17 00:00:00 2001 From: Tatyana <43764894+taty2010@users.noreply.github.com> Date: Wed, 3 May 2023 22:38:35 -0500 Subject: [PATCH 14/18] Update test/helpers/utils.spec.ts Co-authored-by: Nick Taylor --- test/helpers/utils.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/helpers/utils.spec.ts b/test/helpers/utils.spec.ts index f8b4859a05..e008cb46b0 100644 --- a/test/helpers/utils.spec.ts +++ b/test/helpers/utils.spec.ts @@ -197,7 +197,7 @@ describe('redirectsForNext404Route', () => { expect(generateDynamicRewrites(route)).toStrictEqual(expected) }) - it('does not return static 404 redirects when LEGACY_FALLBACK_FALSE is true', async () => { + it('does not return static 404 redirects when LEGACY_FALLBACK_FALSE is set', async () => { process.env.LEGACY_FALLBACK_FALSE = 'true' const expected = { From 14fac5de3acd3a5e5e2dfcff3a33d65ce84fa516 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Thu, 4 May 2023 10:10:34 -0500 Subject: [PATCH 15/18] chore: formatting --- test/helpers/utils.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/helpers/utils.spec.ts b/test/helpers/utils.spec.ts index e008cb46b0..8b85e5cb17 100644 --- a/test/helpers/utils.spec.ts +++ b/test/helpers/utils.spec.ts @@ -220,5 +220,4 @@ describe('redirectsForNext404Route', () => { expect(generateDynamicRewrites(route)).toStrictEqual(expected) }) - }) From c82d4e5472e72a904d4a6806f26a147bc0c9f783 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Thu, 4 May 2023 11:39:17 -0500 Subject: [PATCH 16/18] chore: empty commit From ea49fd61108c1e90b370773c4c312161b6059466 Mon Sep 17 00:00:00 2001 From: Lennart Date: Fri, 5 May 2023 14:14:09 +0200 Subject: [PATCH 17/18] chore: delete env var at end of test --- test/helpers/utils.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/helpers/utils.spec.ts b/test/helpers/utils.spec.ts index 8b85e5cb17..37dd8fb96d 100644 --- a/test/helpers/utils.spec.ts +++ b/test/helpers/utils.spec.ts @@ -219,5 +219,7 @@ describe('redirectsForNext404Route', () => { } expect(generateDynamicRewrites(route)).toStrictEqual(expected) + + delete process.env.LEGACY_FALLBACK_FALSE }) }) From 7a7b5799bad3638312277d5089d15686de268cd1 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Fri, 5 May 2023 14:18:56 +0200 Subject: [PATCH 18/18] chore: linting --- test/helpers/utils.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/helpers/utils.spec.ts b/test/helpers/utils.spec.ts index 37dd8fb96d..19d70fcae2 100644 --- a/test/helpers/utils.spec.ts +++ b/test/helpers/utils.spec.ts @@ -219,7 +219,7 @@ describe('redirectsForNext404Route', () => { } expect(generateDynamicRewrites(route)).toStrictEqual(expected) - + delete process.env.LEGACY_FALLBACK_FALSE }) })