Skip to content

Commit 0732219

Browse files
fix: preview mode for odb/fallback pages (#564)
* fix: preview mode for odb/fallback pages * chore: add new preview redirect to standard function for fallback srcRoutes * chore: fix basePath redirects for fallback preview mode lol pain * chore: fix incorrect pathing to new preview function * chore: add additional test * fix: revalidate pages with fallback werent getting new preview redirects Co-authored-by: Matt Kane <[email protected]>
1 parent 248a36e commit 0732219

14 files changed

+131
-50
lines changed

Diff for: src/lib/config.js

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ const CUSTOM_HEADERS_PATH = join('.', '_headers')
3838
// creating the next/image redirect
3939
const NEXT_IMAGE_FUNCTION_NAME = 'next_image'
4040

41+
const PREVIEW_MODE_COOKIES = ['Cookie=__prerender_bypass,__next_preview_data']
42+
4143
const SRC_FILES = [PUBLIC_PATH, NEXT_CONFIG_PATH, CUSTOM_REDIRECTS_PATH, CUSTOM_HEADERS_PATH, ...NEXT_SRC_DIRS]
4244

4345
module.exports = {
@@ -52,4 +54,5 @@ module.exports = {
5254
CUSTOM_HEADERS_PATH,
5355
NEXT_IMAGE_FUNCTION_NAME,
5456
SRC_FILES,
57+
PREVIEW_MODE_COOKIES,
5558
}

Diff for: src/lib/helpers/convertToBasePathRedirects.js

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ const convertToBasePathRedirects = ({ basePath, nextRedirects }) => {
3434
},
3535
]
3636
basePathRedirects.push(...indexRedirects)
37+
} else if (r.specialPreviewMode) {
38+
basePathRedirects.push({
39+
route: `${basePath}${r.route}`,
40+
target: r.target,
41+
force: true,
42+
conditions: r.conditions,
43+
})
3744
} else if (!r.route.includes('_next/') && r.target.includes('/.netlify/functions') && r.conditions) {
3845
// If this is a preview mode redirect, we need different behavior than other function targets below
3946
// because the conditions prevent us from doing a route -> basePath/route force

Diff for: src/lib/helpers/getPreviewModeFunctionName.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Some pages (getStaticProps/withFallback) require a separate standard function for preview mode; this provides the name for that function, to be called in several places
2+
3+
const getPreviewModeFunctionName = (functionName) => `preview-${functionName}`
4+
5+
module.exports = getPreviewModeFunctionName

Diff for: src/lib/helpers/isRouteWithFallback.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const getPrerenderManifest = require('./getPrerenderManifest')
22

33
const isRouteWithFallback = async (route) => {
4+
if (!route) return false
5+
46
const { dynamicRoutes } = await getPrerenderManifest()
57

68
// Fallback "blocking" routes will have fallback: null in manifest

Diff for: src/lib/helpers/setupNetlifyFunctionForPage.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ const getTemplate = require('../templates/getTemplate')
88
const copyDynamicImportChunks = require('./copyDynamicImportChunks')
99
const getNetlifyFunctionName = require('./getNetlifyFunctionName')
1010
const getNextDistDir = require('./getNextDistDir')
11+
const getPreviewModeFunctionName = require('./getPreviewModeFunctionName')
1112
const { logItem } = require('./logger')
1213

1314
// Create a Netlify Function for the page with the given file path
14-
const setupNetlifyFunctionForPage = async ({ filePath, functionsPath, isApiPage, isISR }) => {
15+
const setupNetlifyFunctionForPage = async ({ filePath, functionsPath, isApiPage, isODB, forFallbackPreviewMode }) => {
1516
// Set function name based on file path
16-
const functionName = getNetlifyFunctionName(filePath, isApiPage)
17+
const defaultFunctionName = getNetlifyFunctionName(filePath, isApiPage)
18+
const functionName = forFallbackPreviewMode ? getPreviewModeFunctionName(defaultFunctionName) : defaultFunctionName
1719
const functionDirectory = join(functionsPath, functionName)
1820

1921
await ensureDir(functionDirectory)
@@ -24,7 +26,7 @@ const setupNetlifyFunctionForPage = async ({ filePath, functionsPath, isApiPage,
2426

2527
// Write entry point to function directory
2628
const entryPointPath = join(functionDirectory, `${functionName}.js`)
27-
await writeFile(entryPointPath, getTemplate({ filePath, isISR }))
29+
await writeFile(entryPointPath, getTemplate({ filePath, isODB }))
2830

2931
// Copy function helper
3032
await copy(join(TEMPLATES_DIR, 'getHandlerFunction.js'), join(functionDirectory, 'getHandlerFunction.js'))

Diff for: src/lib/pages/getStaticProps/pages.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
const asyncForEach = require('../../helpers/asyncForEach')
12
const getPrerenderManifest = require('../../helpers/getPrerenderManifest')
3+
const isRouteWithFallback = require('../../helpers/isRouteWithFallback')
24

35
// Get pages using getStaticProps
46
const getPages = async () => {
@@ -7,9 +9,10 @@ const getPages = async () => {
79
// Collect pages
810
const pages = []
911

10-
Object.entries(routes).forEach(([route, { dataRoute, initialRevalidateSeconds, srcRoute }]) => {
11-
// Ignore pages with revalidate, these will need to be SSRed
12-
if (initialRevalidateSeconds) return
12+
await asyncForEach(Object.entries(routes), async ([route, { dataRoute, initialRevalidateSeconds, srcRoute }]) => {
13+
// Ignore pages with revalidate (but no fallback), these will need to be SSRed
14+
const isFallbackRoute = await isRouteWithFallback(srcRoute)
15+
if (initialRevalidateSeconds && !isFallbackRoute) return
1316

1417
pages.push({
1518
route,

Diff for: src/lib/pages/getStaticProps/redirects.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const addDefaultLocaleRedirect = require('../../helpers/addDefaultLocaleRedirect
66
const asyncForEach = require('../../helpers/asyncForEach')
77
const getFilePathForRoute = require('../../helpers/getFilePathForRoute')
88
const getNetlifyFunctionName = require('../../helpers/getNetlifyFunctionName')
9+
const getPreviewModeFunctionName = require('../../helpers/getPreviewModeFunctionName')
10+
const isRouteWithFallback = require('../../helpers/isRouteWithFallback')
911

1012
const getPages = require('./pages')
1113

@@ -35,11 +37,15 @@ const getRedirects = async () => {
3537
const relativePath = getFilePathForRoute(srcRoute || route, 'js')
3638
const filePath = slash(join('pages', relativePath))
3739
const functionName = getNetlifyFunctionName(filePath)
40+
const isODB = await isRouteWithFallback(srcRoute)
3841

3942
// Preview mode conditions
4043
const conditions = ['Cookie=__prerender_bypass,__next_preview_data']
44+
// ODB pages' preview mode needs a special flagged standard function because
45+
// their default function (an ODB) is not functional for preview mode
4146
const target = `/.netlify/functions/${functionName}`
42-
const previewModeRedirect = { conditions, force: true, target }
47+
const previewModeTarget = isODB ? `/.netlify/functions/${getPreviewModeFunctionName(functionName)}` : target
48+
const previewModeRedirect = { conditions, force: true, target: previewModeTarget }
4349

4450
// Add a preview mode redirect for the standard route
4551
redirects.push({
@@ -54,7 +60,7 @@ const getRedirects = async () => {
5460
})
5561

5662
// Preview mode default locale redirect must precede normal default locale redirect
57-
await addDefaultLocaleRedirect(redirects, route, target, previewModeRedirect)
63+
await addDefaultLocaleRedirect(redirects, route, target, { conditions, force: true })
5864
await addDefaultLocaleRedirect(redirects, route)
5965
})
6066

Diff for: src/lib/pages/getStaticPropsWithFallback/redirects.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ const { join } = require('path')
22

33
const slash = require('slash')
44

5+
const { PREVIEW_MODE_COOKIES } = require('../../config')
56
const addLocaleRedirects = require('../../helpers/addLocaleRedirects')
67
const asyncForEach = require('../../helpers/asyncForEach')
78
const getFilePathForRoute = require('../../helpers/getFilePathForRoute')
89
const getNetlifyFunctionName = require('../../helpers/getNetlifyFunctionName')
10+
const getPreviewModeFunctionName = require('../../helpers/getPreviewModeFunctionName')
911

1012
const getPages = require('./pages')
1113

@@ -18,10 +20,20 @@ const getRedirects = async () => {
1820
const filePath = slash(join('pages', relativePath))
1921
const functionName = getNetlifyFunctionName(filePath)
2022
const target = `/.netlify/functions/${functionName}`
23+
const previewModeTarget = `/.netlify/functions/${getPreviewModeFunctionName(functionName)}`
2124

2225
await addLocaleRedirects(redirects, route, target)
2326

24-
// Add one redirect for the page
27+
// Add a redirect for preview mode pointing to the standard function
28+
redirects.push({
29+
route,
30+
target: previewModeTarget,
31+
conditions: PREVIEW_MODE_COOKIES,
32+
force: true,
33+
specialPreviewMode: true,
34+
})
35+
36+
// Add one redirect pointing to the ODB
2537
redirects.push({
2638
route,
2739
target,

Diff for: src/lib/pages/getStaticPropsWithFallback/setup.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@ const setup = async (functionsPath) => {
1414
const pages = await getPages()
1515

1616
// Create Netlify Function for every page
17-
return pages.map(({ route }) => {
17+
return pages.reduce((jobs, { route }) => {
1818
const relativePath = getFilePathForRoute(route, 'js')
1919
const filePath = slash(join('pages', relativePath))
20-
return { type: 'function', filePath, functionsPath, isISR: true }
21-
})
20+
// Need two different functions - one ODB for normal pages, one standard for preview mode
21+
return [
22+
...jobs,
23+
{ type: 'function', filePath, functionsPath, isODB: true },
24+
{ type: 'function', filePath, functionsPath, forFallbackPreviewMode: true },
25+
]
26+
}, [])
2227
}
2328

2429
module.exports = setup

Diff for: src/lib/templates/getTemplate.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
const getTemplate = ({ filePath, isISR }) => {
2-
if (isISR) {
1+
const getTemplate = ({ filePath, isODB }) => {
2+
if (isODB) {
33
return `// Auto-generated file. DO NOT MODIFY.
44
const { getHandlerFunction } = require('./getHandlerFunction')
55
const { builder } = require('@netlify/functions')

Diff for: src/tests/__snapshots__/basePath.test.js.snap

+22-12
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ exports[`Routing creates Netlify redirects 1`] = `
88
/_next/data/%BUILD_ID%/getStaticProps/2.json /.netlify/functions/next_getStaticProps_id 200! Cookie=__prerender_bypass,__next_preview_data
99
/_next/data/%BUILD_ID%/getStaticProps/static.json /.netlify/functions/next_getStaticProps_static 200! Cookie=__prerender_bypass,__next_preview_data
1010
/_next/data/%BUILD_ID%/getStaticProps/with-revalidate.json /.netlify/functions/next_getStaticProps_withrevalidate 200
11-
/_next/data/%BUILD_ID%/getStaticProps/withFallback/3.json /.netlify/functions/next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
12-
/_next/data/%BUILD_ID%/getStaticProps/withFallback/4.json /.netlify/functions/next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
13-
/_next/data/%BUILD_ID%/getStaticProps/withFallback/my/path/1.json /.netlify/functions/next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
14-
/_next/data/%BUILD_ID%/getStaticProps/withFallback/my/path/2.json /.netlify/functions/next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
15-
/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/3.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
16-
/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/4.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
11+
/_next/data/%BUILD_ID%/getStaticProps/withFallback/3.json /.netlify/functions/preview-next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
12+
/_next/data/%BUILD_ID%/getStaticProps/withFallback/4.json /.netlify/functions/preview-next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
13+
/_next/data/%BUILD_ID%/getStaticProps/withFallback/my/path/1.json /.netlify/functions/preview-next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
14+
/_next/data/%BUILD_ID%/getStaticProps/withFallback/my/path/2.json /.netlify/functions/preview-next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
15+
/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/3.json /.netlify/functions/preview-next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
16+
/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/4.json /.netlify/functions/preview-next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
1717
/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/1.json /.netlify/functions/next_getStaticProps_withRevalidate_id 200
1818
/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/2.json /.netlify/functions/next_getStaticProps_withRevalidate_id 200
19+
/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/withFallback/1.json /.netlify/functions/preview-next_getStaticProps_withRevalidate_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
20+
/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/withFallback/2.json /.netlify/functions/preview-next_getStaticProps_withRevalidate_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
1921
/api/hello-background /foo/api/hello-background 301!
2022
/api/static /foo/api/static 301!
2123
/foo /.netlify/functions/next_index 200
@@ -31,20 +33,24 @@ exports[`Routing creates Netlify redirects 1`] = `
3133
/foo/getStaticProps/static /.netlify/functions/next_getStaticProps_static 200! Cookie=__prerender_bypass,__next_preview_data
3234
/foo/getStaticProps/static /getStaticProps/static 200
3335
/foo/getStaticProps/with-revalidate /.netlify/functions/next_getStaticProps_withrevalidate 200
34-
/foo/getStaticProps/withFallback/3 /.netlify/functions/next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
36+
/foo/getStaticProps/withFallback/3 /.netlify/functions/preview-next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
3537
/foo/getStaticProps/withFallback/3 /getStaticProps/withFallback/3 200
36-
/foo/getStaticProps/withFallback/4 /.netlify/functions/next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
38+
/foo/getStaticProps/withFallback/4 /.netlify/functions/preview-next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
3739
/foo/getStaticProps/withFallback/4 /getStaticProps/withFallback/4 200
38-
/foo/getStaticProps/withFallback/my/path/1 /.netlify/functions/next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
40+
/foo/getStaticProps/withFallback/my/path/1 /.netlify/functions/preview-next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
3941
/foo/getStaticProps/withFallback/my/path/1 /getStaticProps/withFallback/my/path/1 200
40-
/foo/getStaticProps/withFallback/my/path/2 /.netlify/functions/next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
42+
/foo/getStaticProps/withFallback/my/path/2 /.netlify/functions/preview-next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
4143
/foo/getStaticProps/withFallback/my/path/2 /getStaticProps/withFallback/my/path/2 200
42-
/foo/getStaticProps/withFallbackBlocking/3 /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
44+
/foo/getStaticProps/withFallbackBlocking/3 /.netlify/functions/preview-next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
4345
/foo/getStaticProps/withFallbackBlocking/3 /getStaticProps/withFallbackBlocking/3 200
44-
/foo/getStaticProps/withFallbackBlocking/4 /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
46+
/foo/getStaticProps/withFallbackBlocking/4 /.netlify/functions/preview-next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
4547
/foo/getStaticProps/withFallbackBlocking/4 /getStaticProps/withFallbackBlocking/4 200
4648
/foo/getStaticProps/withRevalidate/1 /.netlify/functions/next_getStaticProps_withRevalidate_id 200
4749
/foo/getStaticProps/withRevalidate/2 /.netlify/functions/next_getStaticProps_withRevalidate_id 200
50+
/foo/getStaticProps/withRevalidate/withFallback/1 /.netlify/functions/preview-next_getStaticProps_withRevalidate_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
51+
/foo/getStaticProps/withRevalidate/withFallback/1 /getStaticProps/withRevalidate/withFallback/1 200
52+
/foo/getStaticProps/withRevalidate/withFallback/2 /.netlify/functions/preview-next_getStaticProps_withRevalidate_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
53+
/foo/getStaticProps/withRevalidate/withFallback/2 /getStaticProps/withRevalidate/withFallback/2 200
4854
/foo/static /static 200
4955
/getServerSideProps/static /foo/getServerSideProps/static 301!
5056
/getStaticProps/with-revalidate /foo/getStaticProps/with-revalidate 301!
@@ -65,9 +71,13 @@ exports[`Routing creates Netlify redirects 1`] = `
6571
/foo/getServerSideProps/all /.netlify/functions/next_getServerSideProps_all_slug 200
6672
/foo/getServerSideProps/all/* /.netlify/functions/next_getServerSideProps_all_slug 200
6773
/foo/getServerSideProps/:id /.netlify/functions/next_getServerSideProps_id 200
74+
/foo/getStaticProps/withFallback/:id /.netlify/functions/preview-next_getStaticProps_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
6875
/foo/getStaticProps/withFallback/:id /.netlify/functions/next_getStaticProps_withFallback_id 200
76+
/foo/getStaticProps/withFallback/:slug/* /.netlify/functions/preview-next_getStaticProps_withFallback_slug 200! Cookie=__prerender_bypass,__next_preview_data
6977
/foo/getStaticProps/withFallback/:slug/* /.netlify/functions/next_getStaticProps_withFallback_slug 200
78+
/foo/getStaticProps/withFallbackBlocking/:id /.netlify/functions/preview-next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
7079
/foo/getStaticProps/withFallbackBlocking/:id /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200
80+
/foo/getStaticProps/withRevalidate/withFallback/:id /.netlify/functions/preview-next_getStaticProps_withRevalidate_withFallback_id 200! Cookie=__prerender_bypass,__next_preview_data
7181
/foo/getStaticProps/withRevalidate/withFallback/:id /.netlify/functions/next_getStaticProps_withRevalidate_withFallback_id 200
7282
/foo/shows/:id /.netlify/functions/next_shows_id 200
7383
/foo/shows/:params/* /.netlify/functions/next_shows_params 200

0 commit comments

Comments
 (0)