Skip to content
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

Fallback: "blocking" #1007

Merged
merged 7 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ describe("Pages Tests", () => {
});
});

describe("Dynamic SSG fallback blocking", () => {
[
{ path: "/fallback-blocking/a" },
{ path: "/en/fallback-blocking/a" },
{ path: "/en/fallback-blocking/c" },
{ path: "/fr/fallback-blocking/a" }
].forEach(({ path }) => {
it(`serves page ${path} with correct content immediately`, () => {
cy.visit(path);
cy.location("pathname").should("eq", path);
cy.contains(`Hello ${path.slice(-1)}`);
});
});
});

describe("Dynamic SSG fallback", () => {
[
{ path: "/fallback/c" },
Expand Down Expand Up @@ -164,6 +179,33 @@ describe("Pages Tests", () => {
});
});

describe("Dynamic SSG fallback blocking", () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you meant "Dynamic SSG fallback"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not only that, but it duplicates (some of) the test above. It's a rebase artifact, fixed now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And since they duplicated the "not cached" test, they failed the e2e test run.

[
{ path: "/fallback/c" },
{ path: "/en/fallback/d" },
{ path: "/fr/fallback/e" }
].forEach(({ path }) => {
it(`serves page ${path} with fallback at first`, () => {
cy.visit(path);
cy.location("pathname").should("eq", path);
cy.contains("Hello fallback");
});
});

[
{ path: "/fallback/c" },
{ path: "/en/fallback/d" },
{ path: "/fr/fallback/e" },
{ path: "/fr/fallback/a" }
].forEach(({ path }) => {
it(`serves page ${path} with correct content soon`, () => {
cy.visit(path);
cy.location("pathname").should("eq", path);
cy.contains(`Hello ${path.slice(-1)}`);
});
});
});

describe("Dynamic SSG no fallback", () => {
[
{ path: "/no-fallback/c" },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import { GetStaticProps } from "next";

type DynamicIndexPageProps = {
slug: string;
};

export default function DynamicIndexPage(
props: DynamicIndexPageProps
): JSX.Element {
return (
<React.Fragment>
<div>
{`Hello ${props.slug}. This is a dynamic SSG page using getStaticProps() with fallback blocking.`}
</div>
</React.Fragment>
);
}

export const getStaticProps: GetStaticProps = async (ctx) => {
return {
props: {
slug: ctx.params?.slug as string
}
};
};

export async function getStaticPaths() {
return {
paths: [{ params: { slug: "a" } }, { params: { slug: "b" } }],
fallback: "blocking"
};
}
34 changes: 21 additions & 13 deletions packages/libs/lambda-at-edge/src/default-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,15 @@ const handleOriginResponse = async ({
});
const s3BasePath = basePath ? `${basePath.replace(/^\//, "")}/` : "";
let pagePath;
const hasFallback = Object.values(manifest.pages.ssg.dynamic).find(
(routeConfig) => {
const re = new RegExp(routeConfig.routeRegex);
return re.test(uri);
}
);
const isFallbackBlocking = hasFallback?.fallback === null;
if (
isDataRequest(uri) &&
(isDataRequest(uri) || isFallbackBlocking) &&
!(pagePath = router(manifest, routesManifest)(uri)).endsWith(".html")
) {
// eslint-disable-next-line
Expand All @@ -652,10 +659,12 @@ const handleOriginResponse = async ({
"passthrough"
);
if (isSSG) {
const jsonKey = uri.replace(/^\//, "");
const htmlKey = uri
.replace(/^\/?_next\/data/, "static-pages")
.replace(/.json$/, ".html");
const baseKey = uri
.replace(/^\//, "")
.replace(/\.(json|html)$/, "")
.replace(/^_next\/data\/[^\/]*\//, "");
const jsonKey = `_next/data/${manifest.buildId}/${baseKey}.json`;
const htmlKey = `static-pages/${manifest.buildId}/${baseKey}.html`;
const s3JsonParams = {
Bucket: bucketName,
Key: `${s3BasePath}${jsonKey}`,
Expand All @@ -679,16 +688,15 @@ const handleOriginResponse = async ({
]);
}
res.writeHead(200, response.headers as any);
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(renderOpts.pageData));
if (isDataRequest(uri)) {
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(renderOpts.pageData));
} else {
res.setHeader("Content-Type", "text/html");
res.end(html);
}
return await responsePromise;
} else {
const hasFallback = Object.values(manifest.pages.ssg.dynamic).find(
(routeConfig) => {
const re = new RegExp(routeConfig.routeRegex);
return re.test(uri);
}
);
if (!hasFallback) return response;

// Make sure we get locale-specific S3 page
Expand Down
78 changes: 76 additions & 2 deletions packages/libs/lambda-at-edge/tests/build/build-dynamic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ describe("Builder Tests (dynamic)", () => {

// These could be removed from build?
expect(dynamic).toEqual({
"/en/fallback-blocking/:slug": {
file: "pages/fallback-blocking/[slug].js",
regex: "^\\/en\\/fallback-blocking(?:\\/([^\\/#\\?]+?))[\\/#\\?]?$"
},
"/en/fallback/:slug": {
file: "pages/fallback/[slug].js",
regex: "^\\/en\\/fallback(?:\\/([^\\/#\\?]+?))[\\/#\\?]?$"
Expand All @@ -88,10 +92,18 @@ describe("Builder Tests (dynamic)", () => {
file: "pages/no-fallback/[slug].js",
regex: "^\\/en\\/no-fallback(?:\\/([^\\/#\\?]+?))[\\/#\\?]?$"
},
"/fallback-blocking/:slug": {
file: "pages/fallback-blocking/[slug].js",
regex: "^\\/fallback-blocking(?:\\/([^\\/#\\?]+?))[\\/#\\?]?$"
},
"/fallback/:slug": {
file: "pages/fallback/[slug].js",
regex: "^\\/fallback(?:\\/([^\\/#\\?]+?))[\\/#\\?]?$"
},
"/nl/fallback-blocking/:slug": {
file: "pages/fallback-blocking/[slug].js",
regex: "^\\/nl\\/fallback-blocking(?:\\/([^\\/#\\?]+?))[\\/#\\?]?$"
},
"/nl/fallback/:slug": {
file: "pages/fallback/[slug].js",
regex: "^\\/nl\\/fallback(?:\\/([^\\/#\\?]+?))[\\/#\\?]?$"
Expand Down Expand Up @@ -174,6 +186,14 @@ describe("Builder Tests (dynamic)", () => {
// Should non-localized variants be removed?
expect(ssg).toEqual({
dynamic: {
"/en/fallback-blocking/[slug]": {
dataRoute:
"/_next/data/test-build-id/en/fallback-blocking/[slug].json",
dataRouteRegex:
"^/_next/data/test-build-id/en/fallback\\-blocking/([^/]+?)\\.json$",
fallback: null,
routeRegex: "^/en/fallback\\-blocking/([^/]+?)(?:/)?$"
},
"/en/fallback/[slug]": {
dataRoute: "/_next/data/test-build-id/en/fallback/[slug].json",
dataRouteRegex:
Expand All @@ -188,13 +208,29 @@ describe("Builder Tests (dynamic)", () => {
fallback: false,
routeRegex: "^/en/no\\-fallback/([^/]+?)(?:/)?$"
},
"/fallback-blocking/[slug]": {
dataRoute:
"/_next/data/test-build-id/fallback-blocking/[slug].json",
dataRouteRegex:
"^/_next/data/test-build-id/fallback\\-blocking/([^/]+?)\\.json$",
fallback: null,
routeRegex: "^/fallback\\-blocking/([^/]+?)(?:/)?$"
},
"/fallback/[slug]": {
dataRoute: "/_next/data/test-build-id/fallback/[slug].json",
dataRouteRegex:
"^/_next/data/test-build-id/fallback/([^/]+?)\\.json$",
fallback: "/fallback/[slug].html",
routeRegex: "^/fallback/([^/]+?)(?:/)?$"
},
"/nl/fallback-blocking/[slug]": {
dataRoute:
"/_next/data/test-build-id/nl/fallback-blocking/[slug].json",
dataRouteRegex:
"^/_next/data/test-build-id/nl/fallback\\-blocking/([^/]+?)\\.json$",
fallback: null,
routeRegex: "^/nl/fallback\\-blocking/([^/]+?)(?:/)?$"
},
"/nl/fallback/[slug]": {
dataRoute: "/_next/data/test-build-id/nl/fallback/[slug].json",
dataRouteRegex:
Expand Down Expand Up @@ -228,6 +264,11 @@ describe("Builder Tests (dynamic)", () => {
initialRevalidateSeconds: false,
srcRoute: null
},
"/en/fallback-blocking/a": {
dataRoute: "/_next/data/test-build-id/en/fallback-blocking/a.json",
initialRevalidateSeconds: false,
srcRoute: "/en/fallback-blocking/[slug]"
},
"/en/fallback/a": {
dataRoute: "/_next/data/test-build-id/en/fallback/a.json",
initialRevalidateSeconds: false,
Expand All @@ -253,6 +294,11 @@ describe("Builder Tests (dynamic)", () => {
initialRevalidateSeconds: false,
srcRoute: null
},
"/fallback-blocking/a": {
dataRoute: "/_next/data/test-build-id/fallback-blocking/a.json",
initialRevalidateSeconds: false,
srcRoute: "/fallback-blocking/[slug]"
},
"/fallback/a": {
dataRoute: "/_next/data/test-build-id/fallback/a.json",
initialRevalidateSeconds: false,
Expand All @@ -268,6 +314,11 @@ describe("Builder Tests (dynamic)", () => {
initialRevalidateSeconds: false,
srcRoute: null
},
"/nl/fallback-blocking/a": {
dataRoute: "/_next/data/test-build-id/nl/fallback-blocking/a.json",
initialRevalidateSeconds: false,
srcRoute: "/nl/fallback-blocking/[slug]"
},
"/nl/fallback/a": {
dataRoute: "/_next/data/test-build-id/nl/fallback/a.json",
initialRevalidateSeconds: false,
Expand Down Expand Up @@ -340,6 +391,9 @@ describe("Builder Tests (dynamic)", () => {
const enFallbackPages = await fse.readdir(
join(outputDir, `${DEFAULT_LAMBDA_CODE_DIR}/pages/en/fallback`)
);
const enFallbackBlockingPages = await fse.readdir(
join(outputDir, `${DEFAULT_LAMBDA_CODE_DIR}/pages/en/fallback-blocking`)
);
const enNoFallbackPages = await fse.readdir(
join(outputDir, `${DEFAULT_LAMBDA_CODE_DIR}/pages/en/no-fallback`)
);
Expand All @@ -352,6 +406,9 @@ describe("Builder Tests (dynamic)", () => {
const fallbackPages = await fse.readdir(
join(outputDir, `${DEFAULT_LAMBDA_CODE_DIR}/pages/fallback`)
);
const fallbackBlockingPages = await fse.readdir(
join(outputDir, `${DEFAULT_LAMBDA_CODE_DIR}/pages/fallback-blocking`)
);
const nofallbackPages = await fse.readdir(
join(outputDir, `${DEFAULT_LAMBDA_CODE_DIR}/pages/no-fallback`)
);
Expand All @@ -376,6 +433,7 @@ describe("Builder Tests (dynamic)", () => {
"catchall",
"en",
"fallback",
"fallback-blocking",
"index.js",
"nl",
"no-fallback",
Expand All @@ -385,14 +443,16 @@ describe("Builder Tests (dynamic)", () => {
]);

// These could be removed
expect(enPages).toEqual(["fallback", "no-fallback"]);
expect(enPages).toEqual(["fallback", "fallback-blocking", "no-fallback"]);
expect(enFallbackPages).toEqual([]);
expect(enFallbackBlockingPages).toEqual([]);
expect(enNoFallbackPages).toEqual([]);

expect(catchallPages).toEqual(["[...slug].js"]);
expect(optionalCatchallPages).toEqual(["[[...slug]].js"]);

expect(fallbackPages).toEqual(["[slug].js"]);
expect(fallbackBlockingPages).toEqual(["[slug].js"]);
expect(nofallbackPages).toEqual(["[slug].js"]);
});
});
Expand All @@ -414,7 +474,12 @@ describe("Builder Tests (dynamic)", () => {
const enNextDataFiles = await fse.readdir(
join(outputDir, `${ASSETS_DIR}/_next/data/test-build-id/en`)
);
expect(enNextDataFiles).toEqual(["fallback", "no-fallback", "ssg.json"]);
expect(enNextDataFiles).toEqual([
"fallback",
"fallback-blocking",
"no-fallback",
"ssg.json"
]);

const enPageFiles = await fse.readdir(
join(outputDir, `${ASSETS_DIR}/static-pages/test-build-id/en`)
Expand All @@ -423,6 +488,7 @@ describe("Builder Tests (dynamic)", () => {
"404.html",
"500.html",
"fallback",
"fallback-blocking",
"no-fallback",
"ssg.html",
"static.html"
Expand All @@ -433,6 +499,14 @@ describe("Builder Tests (dynamic)", () => {
);
expect(enFallbackFiles).toEqual(["[slug].html", "a.html"]);

const enFallbackBlockingFiles = await fse.readdir(
join(
outputDir,
`${ASSETS_DIR}/static-pages/test-build-id/en/fallback-blocking`
)
);
expect(enFallbackBlockingFiles).toEqual(["a.html"]);

const enNoFallbackFiles = await fse.readdir(
join(
outputDir,
Expand Down