diff --git a/cypress/fixtures/pages-with-optionalCatchAll-at-root/[bar]/ssr.js b/cypress/fixtures/pages-with-optionalCatchAll-at-root/[bar]/ssr.js
new file mode 100644
index 0000000..404178e
--- /dev/null
+++ b/cypress/fixtures/pages-with-optionalCatchAll-at-root/[bar]/ssr.js
@@ -0,0 +1,44 @@
+import Error from "next/error";
+import Link from "next/link";
+
+const Show = (props) => {
+ const { errorCode, show } = props;
+ // If show item was not found, render 404 page
+ if (errorCode) {
+ return ;
+ }
+
+ // Otherwise, render show
+ return (
+
+ );
+};
+
+export const getServerSideProps = async ({ params }) => {
+ // The ID to render
+ const { bar } = params;
+
+ const res = await fetch(`https://api.tvmaze.com/shows/${bar}`);
+ const data = await res.json();
+
+ // Set error code if show item could not be found
+ const errorCode = res.status > 200 ? res.status : false;
+
+ return {
+ props: {
+ errorCode,
+ show: data,
+ },
+ };
+};
+
+export default Show;
diff --git a/cypress/fixtures/pages-with-optionalCatchAll-at-root/home.js b/cypress/fixtures/pages-with-optionalCatchAll-at-root/home.js
new file mode 100644
index 0000000..36c0f0d
--- /dev/null
+++ b/cypress/fixtures/pages-with-optionalCatchAll-at-root/home.js
@@ -0,0 +1,22 @@
+import Link from "next/link";
+
+const Home = () => (
+
+
NextJS on Netlify
+
+
+
+);
+
+export default Home;
diff --git a/cypress/integration/optionalCatchAll_at_root_spec.js b/cypress/integration/optionalCatchAll_at_root_spec.js
index 268df93..8c2ba56 100644
--- a/cypress/integration/optionalCatchAll_at_root_spec.js
+++ b/cypress/integration/optionalCatchAll_at_root_spec.js
@@ -92,6 +92,42 @@ describe("pre-rendered page: /static.js", () => {
});
});
+describe("SSR'd page: /[bar]/ssr.js", () => {
+ it("loads TV show", () => {
+ cy.visit("/1337/ssr");
+
+ cy.get("h1").should("contain", "Show #1337");
+ cy.get("p").should("contain", "Whodunnit?");
+ });
+
+ it("loads TV show when SSR-ing", () => {
+ cy.ssr("/1337/ssr");
+
+ cy.get("h1").should("contain", "Show #1337");
+ cy.get("p").should("contain", "Whodunnit?");
+ });
+
+ it("loads page props from data .json file when navigating to it", () => {
+ cy.visit("/home");
+ cy.window().then((w) => (w.noReload = true));
+
+ // Navigate to page and test that no reload is performed
+ // See: https://glebbahmutov.com/blog/detect-page-reload/
+ cy.contains("1337/ssr").click();
+
+ cy.get("h1").should("contain", "Show #1337");
+ cy.get("p").should("contain", "Whodunnit?");
+
+ cy.contains("Go back home").click();
+ cy.contains("1338/ssr").click();
+
+ cy.get("h1").should("contain", "Show #1338");
+ cy.get("p").should("contain", "The Whole Truth");
+
+ cy.window().should("have.property", "noReload", true);
+ });
+});
+
describe("pre-rendered pages: /subfolder/[id].js", () => {
it("serves /subfolder/static", () => {
cy.visit("/subfolder/static");
diff --git a/lib/helpers/getSortedRedirects.js b/lib/helpers/getSortedRedirects.js
index b31b016..dc6463e 100644
--- a/lib/helpers/getSortedRedirects.js
+++ b/lib/helpers/getSortedRedirects.js
@@ -1,9 +1,7 @@
const {
getSortedRoutes: getSortedRoutesFromNext,
} = require("next/dist/next-server/lib/router/utils/sorted-routes");
-
-// Remove the file extension form the route
-const removeFileExtension = (route) => route.replace(/\.[a-zA-Z]+$/, "");
+const removeFileExtension = require("./removeFileExtension");
// Return an array of redirects sorted in order of specificity, i.e., more generic
// routes precede more specific ones
diff --git a/lib/helpers/removeFileExtension.js b/lib/helpers/removeFileExtension.js
new file mode 100644
index 0000000..c504bd7
--- /dev/null
+++ b/lib/helpers/removeFileExtension.js
@@ -0,0 +1,4 @@
+// Remove the file extension form the route
+const removeFileExtension = (route) => route.replace(/\.[a-zA-Z]+$/, "");
+
+module.exports = removeFileExtension;
diff --git a/lib/steps/copyNextAssets.js b/lib/steps/copyNextAssets.js
index 9b946f2..1e23faa 100644
--- a/lib/steps/copyNextAssets.js
+++ b/lib/steps/copyNextAssets.js
@@ -8,7 +8,9 @@ const { NEXT_DIST_DIR } = require("../config");
const copyNextAssets = (publishPath) => {
const staticAssetsPath = join(NEXT_DIST_DIR, "static");
if (!existsSync(staticAssetsPath)) {
- throw new Error("No static assets found in .next dist (aka no /.next/static). Please check your project configuration. Your next.config.js must be one of `serverless` or `experimental-serverless-trace`. Your build command should include `next build`.");
+ throw new Error(
+ "No static assets found in .next dist (aka no /.next/static). Please check your project configuration. Your next.config.js must be one of `serverless` or `experimental-serverless-trace`. Your build command should include `next build`."
+ );
}
logTitle("💼 Copying static NextJS assets to", publishPath);
copySync(staticAssetsPath, join(publishPath, "_next", "static"), {
diff --git a/lib/steps/setupRedirects.js b/lib/steps/setupRedirects.js
index 355b7a2..e70c8f3 100644
--- a/lib/steps/setupRedirects.js
+++ b/lib/steps/setupRedirects.js
@@ -9,6 +9,7 @@ const getSortedRedirects = require("../helpers/getSortedRedirects");
const getNetlifyRoutes = require("../helpers/getNetlifyRoutes");
const isRootCatchAllRedirect = require("../helpers/isRootCatchAllRedirect");
const isDynamicRoute = require("../helpers/isDynamicRoute");
+const removeFileExtension = require("../helpers/removeFileExtension");
// Setup _redirects file that routes all requests to the appropriate location,
// such as one of the Netlify functions or one of the static files.
@@ -37,10 +38,10 @@ const setupRedirects = (publishPath) => {
redirects.push("# Next-on-Netlify Redirects");
const staticRedirects = nextRedirects.filter(
- ({ route }) => !isDynamicRoute(route)
+ ({ route }) => !isDynamicRoute(removeFileExtension(route))
);
const dynamicRedirects = nextRedirects.filter(({ route }) =>
- isDynamicRoute(route)
+ isDynamicRoute(removeFileExtension(route))
);
// Add next/image redirect to our image function
diff --git a/tests/__snapshots__/defaults.test.js.snap b/tests/__snapshots__/defaults.test.js.snap
index 9e08179..62f0900 100644
--- a/tests/__snapshots__/defaults.test.js.snap
+++ b/tests/__snapshots__/defaults.test.js.snap
@@ -11,10 +11,7 @@ exports[`Headers creates Netlify headers 1`] = `
exports[`Routing creates Netlify redirects 1`] = `
"# Next-on-Netlify Redirects
/ /.netlify/functions/next_index 200
-/_next/data/%BUILD_ID%/getServerSideProps/all.json /.netlify/functions/next_getServerSideProps_all_slug 200
-/_next/data/%BUILD_ID%/getServerSideProps/all/* /.netlify/functions/next_getServerSideProps_all_slug 200
/_next/data/%BUILD_ID%/getServerSideProps/static.json /.netlify/functions/next_getServerSideProps_static 200
-/_next/data/%BUILD_ID%/getServerSideProps/:id.json /.netlify/functions/next_getServerSideProps_id 200
/_next/data/%BUILD_ID%/getStaticProps/1.json /.netlify/functions/next_getStaticProps_id 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/getStaticProps/2.json /.netlify/functions/next_getStaticProps_id 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/getStaticProps/static.json /.netlify/functions/next_getStaticProps_static 200! Cookie=__prerender_bypass,__next_preview_data
@@ -23,14 +20,10 @@ exports[`Routing creates Netlify redirects 1`] = `
/_next/data/%BUILD_ID%/getStaticProps/withFallback/4.json /.netlify/functions/next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/getStaticProps/withFallback/my/path/1.json /.netlify/functions/next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/getStaticProps/withFallback/my/path/2.json /.netlify/functions/next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
-/_next/data/%BUILD_ID%/getStaticProps/withFallback/:id.json /.netlify/functions/next_getStaticProps_withFallback_id 200
-/_next/data/%BUILD_ID%/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/3.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/4.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
-/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/:id.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200
/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/1.json /.netlify/functions/next_getStaticProps_withRevalidate_id 200
/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/2.json /.netlify/functions/next_getStaticProps_withRevalidate_id 200
-/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/withFallback/:id.json /.netlify/functions/next_getStaticProps_withRevalidate_withFallback_id 200
/api/static /.netlify/functions/next_api_static 200
/getServerSideProps/static /.netlify/functions/next_getServerSideProps_static 200
/getStaticProps/1 /.netlify/functions/next_getStaticProps_id 200! Cookie=__prerender_bypass,__next_preview_data
@@ -45,6 +38,13 @@ exports[`Routing creates Netlify redirects 1`] = `
/getStaticProps/withFallbackBlocking/4 /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
/getStaticProps/withRevalidate/1 /.netlify/functions/next_getStaticProps_withRevalidate_id 200
/getStaticProps/withRevalidate/2 /.netlify/functions/next_getStaticProps_withRevalidate_id 200
+/_next/data/%BUILD_ID%/getServerSideProps/all.json /.netlify/functions/next_getServerSideProps_all_slug 200
+/_next/data/%BUILD_ID%/getServerSideProps/all/* /.netlify/functions/next_getServerSideProps_all_slug 200
+/_next/data/%BUILD_ID%/getServerSideProps/:id.json /.netlify/functions/next_getServerSideProps_id 200
+/_next/data/%BUILD_ID%/getStaticProps/withFallback/:id.json /.netlify/functions/next_getStaticProps_withFallback_id 200
+/_next/data/%BUILD_ID%/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
+/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/:id.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200
+/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/withFallback/:id.json /.netlify/functions/next_getStaticProps_withRevalidate_withFallback_id 200
/_next/image* url=:url w=:width q=:quality /.netlify/functions/next_image?url=:url&w=:width&q=:quality 200
/api/shows/:id /.netlify/functions/next_api_shows_id 200
/api/shows/:params/* /.netlify/functions/next_api_shows_params 200
diff --git a/tests/__snapshots__/i18n.test.js.snap b/tests/__snapshots__/i18n.test.js.snap
index 52b9086..b1f4d55 100644
--- a/tests/__snapshots__/i18n.test.js.snap
+++ b/tests/__snapshots__/i18n.test.js.snap
@@ -5,10 +5,7 @@ exports[`Routing creates Netlify redirects 1`] = `
/ /.netlify/functions/next_index 200
/404 /en/404.html 200
/_next/data/%BUILD_ID%/en.json /.netlify/functions/next_index 200
-/_next/data/%BUILD_ID%/en/getServerSideProps/all.json /.netlify/functions/next_getServerSideProps_all_slug 200
-/_next/data/%BUILD_ID%/en/getServerSideProps/all/* /.netlify/functions/next_getServerSideProps_all_slug 200
/_next/data/%BUILD_ID%/en/getServerSideProps/static.json /.netlify/functions/next_getServerSideProps_static 200
-/_next/data/%BUILD_ID%/en/getServerSideProps/:id.json /.netlify/functions/next_getServerSideProps_id 200
/_next/data/%BUILD_ID%/en/getStaticProps/1.json /.netlify/functions/next_getStaticProps_id 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/en/getStaticProps/2.json /.netlify/functions/next_getStaticProps_id 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/en/getStaticProps/static.json /.netlify/functions/next_getStaticProps_static 200! Cookie=__prerender_bypass,__next_preview_data
@@ -17,37 +14,15 @@ exports[`Routing creates Netlify redirects 1`] = `
/_next/data/%BUILD_ID%/en/getStaticProps/withFallback/4.json /.netlify/functions/next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/en/getStaticProps/withFallback/my/path/1.json /.netlify/functions/next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/en/getStaticProps/withFallback/my/path/2.json /.netlify/functions/next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
-/_next/data/%BUILD_ID%/en/getStaticProps/withFallback/:id.json /.netlify/functions/next_getStaticProps_withFallback_id 200
-/_next/data/%BUILD_ID%/en/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
/_next/data/%BUILD_ID%/en/getStaticProps/withFallbackBlocking/3.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/en/getStaticProps/withFallbackBlocking/4.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
-/_next/data/%BUILD_ID%/en/getStaticProps/withFallbackBlocking/:id.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200
/_next/data/%BUILD_ID%/en/getStaticProps/withRevalidate/1.json /.netlify/functions/next_getStaticProps_withRevalidate_id 200
/_next/data/%BUILD_ID%/en/getStaticProps/withRevalidate/2.json /.netlify/functions/next_getStaticProps_withRevalidate_id 200
-/_next/data/%BUILD_ID%/en/getStaticProps/withRevalidate/withFallback/:id.json /.netlify/functions/next_getStaticProps_withRevalidate_withFallback_id 200
-/_next/data/%BUILD_ID%/en/shows/:id.json /.netlify/functions/next_shows_id 200
-/_next/data/%BUILD_ID%/en/shows/:params/* /.netlify/functions/next_shows_params 200
/_next/data/%BUILD_ID%/es.json /.netlify/functions/next_index 200
-/_next/data/%BUILD_ID%/es/getServerSideProps/all.json /.netlify/functions/next_getServerSideProps_all_slug 200
-/_next/data/%BUILD_ID%/es/getServerSideProps/all/* /.netlify/functions/next_getServerSideProps_all_slug 200
/_next/data/%BUILD_ID%/es/getServerSideProps/static.json /.netlify/functions/next_getServerSideProps_static 200
-/_next/data/%BUILD_ID%/es/getServerSideProps/:id.json /.netlify/functions/next_getServerSideProps_id 200
/_next/data/%BUILD_ID%/es/getStaticProps/static.json /.netlify/functions/next_getStaticProps_static 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/es/getStaticProps/with-revalidate.json /.netlify/functions/next_getStaticProps_withrevalidate 200
-/_next/data/%BUILD_ID%/es/getStaticProps/withFallback/:id.json /.netlify/functions/next_getStaticProps_withFallback_id 200
-/_next/data/%BUILD_ID%/es/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
-/_next/data/%BUILD_ID%/es/getStaticProps/withFallbackBlocking/:id.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200
-/_next/data/%BUILD_ID%/es/getStaticProps/withRevalidate/withFallback/:id.json /.netlify/functions/next_getStaticProps_withRevalidate_withFallback_id 200
-/_next/data/%BUILD_ID%/es/shows/:id.json /.netlify/functions/next_shows_id 200
-/_next/data/%BUILD_ID%/es/shows/:params/* /.netlify/functions/next_shows_params 200
-/_next/data/%BUILD_ID%/getServerSideProps/all.json /.netlify/functions/next_getServerSideProps_all_slug 200
-/_next/data/%BUILD_ID%/getServerSideProps/all/* /.netlify/functions/next_getServerSideProps_all_slug 200
/_next/data/%BUILD_ID%/getServerSideProps/static.json /.netlify/functions/next_getServerSideProps_static 200
-/_next/data/%BUILD_ID%/getServerSideProps/:id.json /.netlify/functions/next_getServerSideProps_id 200
-/_next/data/%BUILD_ID%/getStaticProps/withFallback/:id.json /.netlify/functions/next_getStaticProps_withFallback_id 200
-/_next/data/%BUILD_ID%/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
-/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/:id.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200
-/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/withFallback/:id.json /.netlify/functions/next_getStaticProps_withRevalidate_withFallback_id 200
/api/static /.netlify/functions/next_api_static 200
/en /.netlify/functions/next_index 200
/en/getServerSideProps/static /.netlify/functions/next_getServerSideProps_static 200
@@ -90,6 +65,31 @@ exports[`Routing creates Netlify redirects 1`] = `
/getStaticProps/withRevalidate/1 /.netlify/functions/next_getStaticProps_withRevalidate_id 200
/getStaticProps/withRevalidate/2 /.netlify/functions/next_getStaticProps_withRevalidate_id 200
/static /en/static.html 200
+/_next/data/%BUILD_ID%/en/getServerSideProps/all.json /.netlify/functions/next_getServerSideProps_all_slug 200
+/_next/data/%BUILD_ID%/en/getServerSideProps/all/* /.netlify/functions/next_getServerSideProps_all_slug 200
+/_next/data/%BUILD_ID%/en/getServerSideProps/:id.json /.netlify/functions/next_getServerSideProps_id 200
+/_next/data/%BUILD_ID%/en/getStaticProps/withFallback/:id.json /.netlify/functions/next_getStaticProps_withFallback_id 200
+/_next/data/%BUILD_ID%/en/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
+/_next/data/%BUILD_ID%/en/getStaticProps/withFallbackBlocking/:id.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200
+/_next/data/%BUILD_ID%/en/getStaticProps/withRevalidate/withFallback/:id.json /.netlify/functions/next_getStaticProps_withRevalidate_withFallback_id 200
+/_next/data/%BUILD_ID%/en/shows/:id.json /.netlify/functions/next_shows_id 200
+/_next/data/%BUILD_ID%/en/shows/:params/* /.netlify/functions/next_shows_params 200
+/_next/data/%BUILD_ID%/es/getServerSideProps/all.json /.netlify/functions/next_getServerSideProps_all_slug 200
+/_next/data/%BUILD_ID%/es/getServerSideProps/all/* /.netlify/functions/next_getServerSideProps_all_slug 200
+/_next/data/%BUILD_ID%/es/getServerSideProps/:id.json /.netlify/functions/next_getServerSideProps_id 200
+/_next/data/%BUILD_ID%/es/getStaticProps/withFallback/:id.json /.netlify/functions/next_getStaticProps_withFallback_id 200
+/_next/data/%BUILD_ID%/es/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
+/_next/data/%BUILD_ID%/es/getStaticProps/withFallbackBlocking/:id.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200
+/_next/data/%BUILD_ID%/es/getStaticProps/withRevalidate/withFallback/:id.json /.netlify/functions/next_getStaticProps_withRevalidate_withFallback_id 200
+/_next/data/%BUILD_ID%/es/shows/:id.json /.netlify/functions/next_shows_id 200
+/_next/data/%BUILD_ID%/es/shows/:params/* /.netlify/functions/next_shows_params 200
+/_next/data/%BUILD_ID%/getServerSideProps/all.json /.netlify/functions/next_getServerSideProps_all_slug 200
+/_next/data/%BUILD_ID%/getServerSideProps/all/* /.netlify/functions/next_getServerSideProps_all_slug 200
+/_next/data/%BUILD_ID%/getServerSideProps/:id.json /.netlify/functions/next_getServerSideProps_id 200
+/_next/data/%BUILD_ID%/getStaticProps/withFallback/:id.json /.netlify/functions/next_getStaticProps_withFallback_id 200
+/_next/data/%BUILD_ID%/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
+/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/:id.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200
+/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/withFallback/:id.json /.netlify/functions/next_getStaticProps_withRevalidate_withFallback_id 200
/_next/image* url=:url w=:width q=:quality /.netlify/functions/next_image?url=:url&w=:width&q=:quality 200
/api/shows/:id /.netlify/functions/next_api_shows_id 200
/api/shows/:params/* /.netlify/functions/next_api_shows_params 200
diff --git a/tests/__snapshots__/optionalCatchAll.test.js.snap b/tests/__snapshots__/optionalCatchAll.test.js.snap
index 095bb51..8958cfb 100644
--- a/tests/__snapshots__/optionalCatchAll.test.js.snap
+++ b/tests/__snapshots__/optionalCatchAll.test.js.snap
@@ -3,9 +3,9 @@
exports[`Routing creates Netlify redirects 1`] = `
"# Next-on-Netlify Redirects
/_next/data/%BUILD_ID%/page.json /.netlify/functions/next_page 200
+/page /.netlify/functions/next_page 200
/_next/data/%BUILD_ID%/index.json /.netlify/functions/next_all 200
/_next/data/%BUILD_ID%/* /.netlify/functions/next_all 200
-/page /.netlify/functions/next_page 200
/_next/image* url=:url w=:width q=:quality /.netlify/functions/next_image?url=:url&w=:width&q=:quality 200
/ /.netlify/functions/next_all 200
/_next/* /_next/:splat 200