Skip to content
This repository was archived by the owner on May 10, 2021. It is now read-only.

Commit c23aee5

Browse files
Support for SSG preview mode (#50)
* add support for preview mode of pre-rendered pages using getStaticProps * remove README caveat * Add Cypress tests: Optional catch-all route at root-level Test that prerendered pages and static files from /public are correctly served under the redirect engine used with cookie-based redirects when having an optional catch-all route at root-level. * Cleanup: Remove unnecessary require We do not need `existsSync` in the `setupNetlifyFunctionForPage` helper. * miscellaneous finishing touches for ssg preview mode * move preview mode note in readme and update isroutewithfallback helper Co-authored-by: Finn Woelm <[email protected]>
1 parent 2ee0f0d commit c23aee5

25 files changed

+470
-43
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ jspm_packages
3939

4040
# OS
4141
.DS_Store
42+
43+
# Local Netlify folder
44+
.netlify

README.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
- [Custom Netlify Redirects](#custom-netlify-redirects)
3636
- [Custom Netlify Functions](#custom-netlify-functions)
3737
- [Caveats](#caveats)
38-
- [Preview Mode](#preview-mode)
3938
- [Fallbacks for Pages with `getStaticPaths`](#fallbacks-for-pages-with-getstaticpaths)
4039
- [Credits](#credits)
4140
- [Showcase](#showcase)
@@ -157,6 +156,12 @@ From now on, whenever you want to preview your application locally, just run:
157156
1. `npm run build`: This will run `next build` to build your Next.js app and `next-on-netlify` to prepare your Next.js app for compatibility with Netlify
158157
1. `netlify dev`: This will emulate Netlify on your computer and let you preview your app on `http://localhost:8888`.
159158

159+
*Note:*
160+
161+
Preview Mode is not yet available locally, running `netlify dev`, for static pages without revalidate or fallback. This will be supported soon.
162+
163+
For now, Preview Mode *is* supported in production for all Next.js page types.
164+
160165
#### Custom Netlify Redirects
161166

162167
You can define custom redirects in a `_redirects` and/or in your `netlify.toml` file.
@@ -175,10 +180,6 @@ SSR pages and API endpoints. It is currently not possible to create custom Netli
175180

176181
## Caveats
177182

178-
### Preview Mode
179-
180-
[Next.js Preview Mode](https://nextjs.org/docs/advanced-features/preview-mode) does not work on pages that are pre-rendered (pages with `getStaticProps`). Netlify currently does not support cookie-based redirects, which are needed for supporting preview mode on pre-rendered pages. Preview mode works correctly on any server-side-rendered pages (pages with `getInitialProps` or `getServerSideProps`). See: [Issue #10](https://github.com/netlify/next-on-netlify/issues/10)
181-
182183
### Fallbacks for Pages with `getStaticPaths`
183184

184185
[Fallback pages](https://nextjs.org/docs/basic-features/data-fetching#fallback-true) behave differently with `next-on-netlify` than they do with Next.js. On Next.js, when navigating to a path that is not defined in `getStaticPaths`, it first displays the fallback page. Next.js then generates the HTML in the background and caches it for future requests.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const Page = () => <p>root-level optional-catch-all</p>;
2+
3+
export async function getServerSideProps() {
4+
return {
5+
props: {},
6+
};
7+
}
8+
9+
export default Page;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const Static = () => <p>static page</p>;
2+
3+
export async function getStaticProps() {
4+
return {
5+
props: {},
6+
};
7+
}
8+
9+
export default Static;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const Static = () => <p>static page in subfolder</p>;
2+
3+
export async function getStaticPaths() {
4+
return {
5+
paths: [
6+
{
7+
params: {
8+
id: "static",
9+
},
10+
},
11+
{
12+
params: {
13+
id: "test",
14+
},
15+
},
16+
],
17+
fallback: true,
18+
};
19+
}
20+
21+
export async function getStaticProps() {
22+
return {
23+
props: {},
24+
};
25+
}
26+
27+
export default Static;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export default async function preview(req, res) {
2+
const { query } = req;
3+
const { id } = query;
4+
5+
// Enable Preview Mode by setting the cookies
6+
res.setPreviewData({});
7+
8+
// Redirect to the path from the fetched post
9+
// We don't redirect to req.query.slug as that might lead to open redirect vulnerabilities
10+
res.writeHead(307, { Location: `/previewTest/static` });
11+
res.end();
12+
}

cypress/fixtures/pages/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ const Index = ({ shows }) => (
230230
<a>previewTest/222</a>
231231
</Link>
232232
</li>
233+
<li>
234+
<Link href="/previewTest/static">
235+
<a>previewTest/static</a>
236+
</Link>
237+
</li>
233238
</ul>
234239

235240
<h1>6. Static Pages Stay Static</h1>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Link from "next/link";
2+
3+
const StaticTest = ({ number }) => {
4+
return (
5+
<div>
6+
<p>
7+
This page uses getStaticProps() and is SSRed when in preview mode.
8+
<br />
9+
<br />
10+
By default, it shows the TV show by ID (as static HTML).
11+
<br />
12+
But when in preview mode, it shows person by ID instead (SSRed).
13+
</p>
14+
15+
<hr />
16+
17+
<h1>Number: {number}</h1>
18+
19+
<Link href="/">
20+
<a>Go back home</a>
21+
</Link>
22+
</div>
23+
);
24+
};
25+
26+
export const getStaticProps = async ({ preview }) => {
27+
let number;
28+
29+
// In preview mode, use odd number
30+
if (preview) {
31+
number = 3;
32+
}
33+
// In normal mode, use even number
34+
else {
35+
number = 4;
36+
}
37+
38+
return {
39+
props: {
40+
number,
41+
},
42+
};
43+
};
44+
45+
export default StaticTest;

cypress/fixtures/public/file.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a text file
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a text file in a folder
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a text file in a subfolder

cypress/integration/default_spec.js

+67-3
Original file line numberDiff line numberDiff line change
@@ -529,12 +529,18 @@ describe("API endpoint", () => {
529529
});
530530

531531
describe("Preview Mode", () => {
532-
it("redirects to preview test page", () => {
532+
it("redirects to preview test page with dynamic route", () => {
533533
cy.visit("/api/enterPreview?id=999");
534534

535535
cy.url().should("include", "/previewTest/999");
536536
});
537537

538+
it("redirects to static preview test page", () => {
539+
cy.visit("/api/enterPreviewStatic");
540+
541+
cy.url().should("include", "/previewTest/static");
542+
});
543+
538544
it("sets cookies on client", () => {
539545
Cypress.Cookies.debug(true);
540546
cy.getCookie("__prerender_bypass").should("not.exist");
@@ -546,7 +552,18 @@ describe("Preview Mode", () => {
546552
cy.getCookie("__next_preview_data").should("not.be", null);
547553
});
548554

549-
it("renders page in preview mode", () => {
555+
it("sets cookies on client with static redirect", () => {
556+
Cypress.Cookies.debug(true);
557+
cy.getCookie("__prerender_bypass").should("not.exist");
558+
cy.getCookie("__next_preview_data").should("not.exist");
559+
560+
cy.visit("/api/enterPreviewStatic");
561+
562+
cy.getCookie("__prerender_bypass").should("not.be", null);
563+
cy.getCookie("__next_preview_data").should("not.be", null);
564+
});
565+
566+
it("renders serverSideProps page in preview mode", () => {
550567
cy.visit("/api/enterPreview?id=999");
551568

552569
if (Cypress.env("DEPLOY") === "local") {
@@ -557,7 +574,15 @@ describe("Preview Mode", () => {
557574
cy.get("p").should("contain", "Sebastian Lacause");
558575
});
559576

560-
it("can move in and out of preview mode", () => {
577+
it("renders staticProps page in preview mode", () => {
578+
// cypress local (aka netlify dev) doesn't support cookie-based redirects
579+
if (Cypress.env("DEPLOY") !== "local") {
580+
cy.visit("/api/enterPreviewStatic");
581+
cy.get("h1").should("contain", "Number: 3");
582+
}
583+
});
584+
585+
it("can move in and out of preview mode for SSRed page", () => {
561586
cy.visit("/api/enterPreview?id=999");
562587

563588
if (Cypress.env("DEPLOY") === "local") {
@@ -582,6 +607,45 @@ describe("Preview Mode", () => {
582607
cy.get("h1").should("contain", "Show #222");
583608
cy.get("p").should("contain", "Happyland");
584609
});
610+
611+
it("can move in and out of preview mode for static page", () => {
612+
if (Cypress.env("DEPLOY") !== "local") {
613+
cy.visit("/api/enterPreviewStatic");
614+
cy.window().then((w) => (w.noReload = true));
615+
616+
cy.get("h1").should("contain", "Number: 3");
617+
618+
cy.contains("Go back home").click();
619+
620+
// Verify that we're still in preview mode
621+
cy.contains("previewTest/static").click();
622+
cy.get("h1").should("contain", "Number: 3");
623+
624+
cy.window().should("have.property", "noReload", true);
625+
626+
// Exit preview mode
627+
cy.visit("/api/exitPreview");
628+
629+
// TO-DO: test if this is the static html?
630+
// Verify that we're no longer in preview mode
631+
cy.contains("previewTest/static").click();
632+
cy.get("h1").should("contain", "Number: 4");
633+
}
634+
});
635+
636+
it("hits the prerendered html out of preview mode and netlify function in preview mode", () => {
637+
if (Cypress.env("DEPLOY") !== "local") {
638+
cy.request("/previewTest/static").then((response) => {
639+
expect(response.headers["cache-control"]).to.include("public");
640+
});
641+
642+
cy.visit("/api/enterPreviewStatic");
643+
644+
cy.request("/previewTest/static").then((response) => {
645+
expect(response.headers["cache-control"]).to.include("private");
646+
});
647+
}
648+
});
585649
});
586650

587651
describe("pre-rendered HTML pages", () => {

0 commit comments

Comments
 (0)