Skip to content

Commit bbcdfbd

Browse files
ascorbickodiakhq[bot]
andauthoredFeb 2, 2022
fix: don't use ODB for routes that match middleware (#1171)
* fix: don't use ODB for routes that match middleware * chore: fix duplicate rules * chore: changes from review * chore: add return types Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
·
1 parent bf4d309 commit bbcdfbd

File tree

9 files changed

+461
-91
lines changed

9 files changed

+461
-91
lines changed
 

‎demos/default/local-plugin/package-lock.json

+1-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { useRouter } from 'next/router'
2+
import Link from 'next/link'
3+
4+
const Show = ({ show }) => {
5+
const router = useRouter()
6+
7+
// This is never shown on Netlify. We just need it for NextJS to be happy,
8+
// because NextJS will render a fallback HTML page.
9+
if (router.isFallback) {
10+
return <div>Loading...</div>
11+
}
12+
13+
return (
14+
<div>
15+
<p>
16+
Check the network panel for the header <code>x-middleware-date</code> to ensure that it is running
17+
</p>
18+
19+
<hr />
20+
21+
<h1>Show #{show.id}</h1>
22+
<p>{show.name}</p>
23+
24+
<hr />
25+
26+
<Link href="/">
27+
<a>Go back home</a>
28+
</Link>
29+
</div>
30+
)
31+
}
32+
33+
export async function getStaticPaths() {
34+
// Set the paths we want to pre-render
35+
const paths = [{ params: { slug: ['my', 'path', '1'] } }, { params: { slug: ['my', 'path', '2'] } }]
36+
37+
// We'll pre-render these paths at build time.
38+
// { fallback: true } means other routes will be rendered at runtime.
39+
return { paths, fallback: true }
40+
}
41+
42+
export async function getStaticProps({ params }) {
43+
// The ID to render
44+
const { slug } = params
45+
const id = slug[slug.length - 1]
46+
47+
const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
48+
const data = await res.json()
49+
50+
return {
51+
props: {
52+
show: data,
53+
},
54+
}
55+
}
56+
57+
export default Show
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { useRouter } from 'next/router'
2+
import Link from 'next/link'
3+
4+
const Show = ({ show }) => {
5+
const router = useRouter()
6+
7+
// This is never shown on Netlify. We just need it for NextJS to be happy,
8+
// because NextJS will render a fallback HTML page.
9+
if (router.isFallback) {
10+
return <div>Loading...</div>
11+
}
12+
13+
return (
14+
<div>
15+
<p>
16+
Check the network panel for the header <code>x-middleware-date</code> to ensure that it is running
17+
</p>
18+
<hr />
19+
20+
<h1>Show #{show.id}</h1>
21+
<p>{show.name}</p>
22+
23+
<hr />
24+
25+
<Link href="/">
26+
<a>Go back home</a>
27+
</Link>
28+
</div>
29+
)
30+
}
31+
32+
export async function getStaticPaths() {
33+
// Set the paths we want to pre-render
34+
const paths = [{ params: { id: '3' } }, { params: { id: '4' } }]
35+
36+
// We'll pre-render these paths at build time.
37+
// { fallback: true } means other routes will be rendered at runtime.
38+
return { paths, fallback: true }
39+
}
40+
41+
export async function getStaticProps({ params }) {
42+
// The ID to render
43+
const { id } = params
44+
45+
const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
46+
const data = await res.json()
47+
48+
return {
49+
props: {
50+
show: data,
51+
},
52+
}
53+
}
54+
55+
export default Show
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { NextResponse } from 'next/server'
2+
3+
export function middleware() {
4+
const res = NextResponse.next()
5+
res.headers.set('x-middleware-date', new Date().toISOString())
6+
return res
7+
}

‎demos/default/pages/index.js

+14-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ const Index = ({ shows, nodeEnv }) => {
88

99
return (
1010
<div>
11-
<img src="/next-on-netlify.png" alt="NextJS on Netlify Banner" className='self-center w-full max-h-80 max-w-5xl m-auto' />
11+
<img
12+
src="/next-on-netlify.png"
13+
alt="NextJS on Netlify Banner"
14+
className="self-center w-full max-h-80 max-w-5xl m-auto"
15+
/>
1216

1317
<div>
1418
<Header />
@@ -18,7 +22,8 @@ const Index = ({ shows, nodeEnv }) => {
1822
<h2>Server-Side Rendering</h2>
1923

2024
<p>
21-
This page is server-side rendered. It fetches a random list of five TV shows from the TVmaze REST API. Refresh this page to see it change.
25+
This page is server-side rendered. It fetches a random list of five TV shows from the TVmaze REST API. Refresh
26+
this page to see it change.
2227
</p>
2328
<code>NODE_ENV: {nodeEnv}</code>
2429

@@ -86,8 +91,8 @@ const Index = ({ shows, nodeEnv }) => {
8691

8792
<h2>Localization</h2>
8893
<p>
89-
Localization (i18n) is supported! This demo uses <code>fr</code> with <code>en</code> as the default locale (at{' '}
90-
<code>/</code>).
94+
Localization (i18n) is supported! This demo uses <code>fr</code> with <code>en</code> as the default locale
95+
(at <code>/</code>).
9196
</p>
9297
<strong>The current locale is {locale}</strong>
9398
<p>Click on the links below to see the above text change</p>
@@ -175,6 +180,11 @@ const Index = ({ shows, nodeEnv }) => {
175180
<a>Middleware</a>
176181
</Link>
177182
</li>
183+
<li>
184+
<Link href="/getStaticProps/withFallbackAndMiddleware/4">
185+
<a>Middleware matching a pre-rendered dynamic route</a>
186+
</Link>
187+
</li>
178188
</ul>
179189
<h4>Preview mode</h4>
180190
<p>Preview mode: </p>

‎src/helpers/files.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ export const matchesRewrite = (file: string, rewrites: Rewrites): boolean => {
5858
return matchesRedirect(file, rewrites.beforeFiles)
5959
}
6060

61+
export const getMiddleware = async (publish: string): Promise<Array<string>> => {
62+
const manifestPath = join(publish, 'server', 'middleware-manifest.json')
63+
if (existsSync(manifestPath)) {
64+
const manifest = await readJson(manifestPath, { throws: false })
65+
return manifest?.sortedMiddleware ?? []
66+
}
67+
return []
68+
}
69+
6170
// eslint-disable-next-line max-lines-per-function
6271
export const moveStaticPages = async ({
6372
netlifyConfig,
@@ -75,14 +84,8 @@ export const moveStaticPages = async ({
7584
const dataDir = join('_next', 'data', buildId)
7685
await ensureDir(dataDir)
7786
// Load the middleware manifest so we can check if a file matches it before moving
78-
let middleware
79-
const manifestPath = join(outputDir, 'middleware-manifest.json')
80-
if (existsSync(manifestPath)) {
81-
const manifest = await readJson(manifestPath)
82-
if (manifest?.middleware) {
83-
middleware = Object.keys(manifest.middleware).map((path) => path.slice(1))
84-
}
85-
}
87+
const middlewarePaths = await getMiddleware(netlifyConfig.build.publish)
88+
const middleware = middlewarePaths.map((path) => path.slice(1))
8689

8790
const prerenderManifest: PrerenderManifest = await readJson(
8891
join(netlifyConfig.build.publish, 'prerender-manifest.json'),

‎src/helpers/redirects.ts

+193-52
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import { NetlifyConfig } from '@netlify/build'
1+
/* eslint-disable max-lines */
2+
import type { NetlifyConfig } from '@netlify/build'
3+
import { yellowBright } from 'chalk'
24
import { readJSON } from 'fs-extra'
3-
import { NextConfig } from 'next'
4-
import { PrerenderManifest } from 'next/dist/build'
5+
import type { NextConfig } from 'next'
6+
import type { PrerenderManifest, SsgRoute } from 'next/dist/build'
7+
import { outdent } from 'outdent'
58
import { join } from 'pathe'
69

710
import { HANDLER_FUNCTION_PATH, HIDDEN_PATHS, ODB_FUNCTION_PATH } from '../constants'
811

12+
import { getMiddleware } from './files'
913
import { RoutesManifest } from './types'
1014
import {
1115
getApiRewrites,
@@ -14,9 +18,11 @@ import {
1418
redirectsForNextRoute,
1519
redirectsForNextRouteWithData,
1620
routeToDataRoute,
17-
targetForFallback,
1821
} from './utils'
1922

23+
const matchesMiddleware = (middleware: Array<string>, route: string): boolean =>
24+
middleware.some((middlewarePath) => route.startsWith(middlewarePath))
25+
2026
const generateLocaleRedirects = ({
2127
i18n,
2228
basePath,
@@ -65,6 +71,150 @@ export const generateStaticRedirects = ({
6571
}
6672
}
6773

74+
/**
75+
* Routes that match middleware need to always use the SSR function
76+
* This generates a rewrite for every middleware in every locale, both with and without a splat
77+
*/
78+
const generateMiddlewareRewrites = ({ basePath, middleware, i18n, buildId }) => {
79+
const handlerRewrite = (from: string) => ({
80+
from: `${basePath}${from}`,
81+
to: HANDLER_FUNCTION_PATH,
82+
status: 200,
83+
})
84+
85+
return (
86+
middleware
87+
.map((route) => {
88+
const unlocalized = [handlerRewrite(`${route}`), handlerRewrite(`${route}/*`)]
89+
if (i18n?.locales?.length > 0) {
90+
const localized = i18n.locales.map((locale) => [
91+
handlerRewrite(`/${locale}${route}`),
92+
handlerRewrite(`/${locale}${route}/*`),
93+
handlerRewrite(`/_next/data/${buildId}/${locale}${route}/*`),
94+
])
95+
// With i18n, all data routes are prefixed with the locale, but the HTML also has the unprefixed default
96+
return [...unlocalized, ...localized]
97+
}
98+
return [...unlocalized, handlerRewrite(`/_next/data/${buildId}${route}/*`)]
99+
})
100+
// Flatten the array of arrays. Can't use flatMap as it might be 2 levels deep
101+
.flat(2)
102+
)
103+
}
104+
105+
const generateStaticIsrRewrites = ({
106+
staticRouteEntries,
107+
basePath,
108+
i18n,
109+
buildId,
110+
middleware,
111+
}: {
112+
staticRouteEntries: Array<[string, SsgRoute]>
113+
basePath: string
114+
i18n: NextConfig['i18n']
115+
buildId: string
116+
middleware: Array<string>
117+
}): {
118+
staticRoutePaths: Set<string>
119+
staticIsrRoutesThatMatchMiddleware: Array<string>
120+
staticIsrRewrites: NetlifyConfig['redirects']
121+
} => {
122+
const staticIsrRoutesThatMatchMiddleware: Array<string> = []
123+
const staticRoutePaths = new Set<string>()
124+
const staticIsrRewrites: NetlifyConfig['redirects'] = []
125+
staticRouteEntries.forEach(([route, { initialRevalidateSeconds }]) => {
126+
if (isApiRoute(route)) {
127+
return
128+
}
129+
staticRoutePaths.add(route)
130+
131+
if (initialRevalidateSeconds === false) {
132+
// These can be ignored, as they're static files handled by the CDN
133+
return
134+
}
135+
// The default locale is served from the root, not the localised path
136+
if (i18n?.defaultLocale && route.startsWith(`/${i18n.defaultLocale}/`)) {
137+
route = route.slice(i18n.defaultLocale.length + 1)
138+
staticRoutePaths.add(route)
139+
if (matchesMiddleware(middleware, route)) {
140+
staticIsrRoutesThatMatchMiddleware.push(route)
141+
}
142+
staticIsrRewrites.push(
143+
...redirectsForNextRouteWithData({
144+
route,
145+
dataRoute: routeToDataRoute(route, buildId, i18n.defaultLocale),
146+
basePath,
147+
to: ODB_FUNCTION_PATH,
148+
force: true,
149+
}),
150+
)
151+
} else if (matchesMiddleware(middleware, route)) {
152+
// Routes that match middleware can't use the ODB
153+
staticIsrRoutesThatMatchMiddleware.push(route)
154+
} else {
155+
// ISR routes use the ODB handler
156+
staticIsrRewrites.push(
157+
// No i18n, because the route is already localized
158+
...redirectsForNextRoute({ route, basePath, to: ODB_FUNCTION_PATH, force: true, buildId, i18n: null }),
159+
)
160+
}
161+
})
162+
163+
return {
164+
staticRoutePaths,
165+
staticIsrRoutesThatMatchMiddleware,
166+
staticIsrRewrites,
167+
}
168+
}
169+
170+
/**
171+
* Generate rewrites for all dynamic routes
172+
*/
173+
const generateDynamicRewrites = ({
174+
dynamicRoutes,
175+
prerenderedDynamicRoutes,
176+
middleware,
177+
basePath,
178+
buildId,
179+
i18n,
180+
}: {
181+
dynamicRoutes: RoutesManifest['dynamicRoutes']
182+
prerenderedDynamicRoutes: PrerenderManifest['dynamicRoutes']
183+
basePath: string
184+
i18n: NextConfig['i18n']
185+
buildId: string
186+
middleware: Array<string>
187+
}): {
188+
dynamicRoutesThatMatchMiddleware: Array<string>
189+
dynamicRewrites: NetlifyConfig['redirects']
190+
} => {
191+
const dynamicRewrites: NetlifyConfig['redirects'] = []
192+
const dynamicRoutesThatMatchMiddleware: Array<string> = []
193+
dynamicRoutes.forEach((route) => {
194+
if (isApiRoute(route.page)) {
195+
return
196+
}
197+
if (route.page in prerenderedDynamicRoutes) {
198+
if (matchesMiddleware(middleware, route.page)) {
199+
dynamicRoutesThatMatchMiddleware.push(route.page)
200+
} else {
201+
dynamicRewrites.push(
202+
...redirectsForNextRoute({ buildId, route: route.page, basePath, to: ODB_FUNCTION_PATH, status: 200, i18n }),
203+
)
204+
}
205+
} else {
206+
// If the route isn't prerendered, it's SSR
207+
dynamicRewrites.push(
208+
...redirectsForNextRoute({ route: route.page, buildId, basePath, to: HANDLER_FUNCTION_PATH, i18n }),
209+
)
210+
}
211+
})
212+
return {
213+
dynamicRoutesThatMatchMiddleware,
214+
dynamicRewrites,
215+
}
216+
}
217+
68218
export const generateRedirects = async ({
69219
netlifyConfig,
70220
nextConfig: { i18n, basePath, trailingSlash, appDir },
@@ -102,43 +252,26 @@ export const generateRedirects = async ({
102252
...(await getPreviewRewrites({ basePath, appDir })),
103253
)
104254

105-
const staticRouteEntries = Object.entries(prerenderedStaticRoutes)
255+
const middleware = await getMiddleware(netlifyConfig.build.publish)
106256

107-
const staticRoutePaths = new Set<string>()
257+
netlifyConfig.redirects.push(...generateMiddlewareRewrites({ basePath, i18n, middleware, buildId }))
108258

109-
// First add all static ISR routes
110-
staticRouteEntries.forEach(([route, { initialRevalidateSeconds }]) => {
111-
if (isApiRoute(route)) {
112-
return
113-
}
114-
staticRoutePaths.add(route)
259+
const staticRouteEntries = Object.entries(prerenderedStaticRoutes)
115260

116-
if (initialRevalidateSeconds === false) {
117-
// These can be ignored, as they're static files handled by the CDN
118-
return
119-
}
120-
// The default locale is served from the root, not the localised path
121-
if (i18n?.defaultLocale && route.startsWith(`/${i18n.defaultLocale}/`)) {
122-
route = route.slice(i18n.defaultLocale.length + 1)
123-
staticRoutePaths.add(route)
261+
const routesThatMatchMiddleware: Array<string> = []
124262

125-
netlifyConfig.redirects.push(
126-
...redirectsForNextRouteWithData({
127-
route,
128-
dataRoute: routeToDataRoute(route, buildId, i18n.defaultLocale),
129-
basePath,
130-
to: ODB_FUNCTION_PATH,
131-
force: true,
132-
}),
133-
)
134-
} else {
135-
// ISR routes use the ODB handler
136-
netlifyConfig.redirects.push(
137-
// No i18n, because the route is already localized
138-
...redirectsForNextRoute({ route, basePath, to: ODB_FUNCTION_PATH, force: true, buildId, i18n: null }),
139-
)
140-
}
263+
const { staticRoutePaths, staticIsrRewrites, staticIsrRoutesThatMatchMiddleware } = generateStaticIsrRewrites({
264+
staticRouteEntries,
265+
basePath,
266+
i18n,
267+
buildId,
268+
middleware,
141269
})
270+
271+
routesThatMatchMiddleware.push(...staticIsrRoutesThatMatchMiddleware)
272+
273+
netlifyConfig.redirects.push(...staticIsrRewrites)
274+
142275
// Add rewrites for all static SSR routes. This is Next 12+
143276
staticRoutes?.forEach((route) => {
144277
if (staticRoutePaths.has(route.page) || isApiRoute(route.page)) {
@@ -150,28 +283,36 @@ export const generateRedirects = async ({
150283
)
151284
})
152285
// Add rewrites for all dynamic routes (both SSR and ISR)
153-
dynamicRoutes.forEach((route) => {
154-
if (isApiRoute(route.page)) {
155-
return
156-
}
157-
if (route.page in prerenderedDynamicRoutes) {
158-
const { fallback } = prerenderedDynamicRoutes[route.page]
159-
160-
const { to, status } = targetForFallback(fallback)
161-
162-
netlifyConfig.redirects.push(...redirectsForNextRoute({ buildId, route: route.page, basePath, to, status, i18n }))
163-
} else {
164-
// If the route isn't prerendered, it's SSR
165-
netlifyConfig.redirects.push(
166-
...redirectsForNextRoute({ route: route.page, buildId, basePath, to: HANDLER_FUNCTION_PATH, i18n }),
167-
)
168-
}
286+
const { dynamicRewrites, dynamicRoutesThatMatchMiddleware } = generateDynamicRewrites({
287+
dynamicRoutes,
288+
prerenderedDynamicRoutes,
289+
middleware,
290+
basePath,
291+
buildId,
292+
i18n,
169293
})
294+
netlifyConfig.redirects.push(...dynamicRewrites)
295+
routesThatMatchMiddleware.push(...dynamicRoutesThatMatchMiddleware)
170296

171297
// Final fallback
172298
netlifyConfig.redirects.push({
173299
from: `${basePath}/*`,
174300
to: HANDLER_FUNCTION_PATH,
175301
status: 200,
176302
})
303+
304+
const middlewareMatches = new Set(routesThatMatchMiddleware).size
305+
if (middlewareMatches > 0) {
306+
console.log(
307+
yellowBright(outdent`
308+
There ${
309+
middlewareMatches === 1
310+
? `is one statically-generated or ISR route that matches`
311+
: `are ${middlewareMatches} statically-generated or ISR routes that match`
312+
} a middleware function. Matched routes will always be served from the SSR function and will not use ISR or be served from the CDN.
313+
If this was not intended, ensure that your middleware only matches routes that you intend to use SSR.
314+
`),
315+
)
316+
}
177317
}
318+
/* eslint-enable max-lines */

‎src/helpers/utils.ts

+1-17
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@ import { NetlifyConfig } from '@netlify/build'
22
import globby from 'globby'
33
import { join } from 'pathe'
44

5-
import {
6-
OPTIONAL_CATCH_ALL_REGEX,
7-
CATCH_ALL_REGEX,
8-
DYNAMIC_PARAMETER_REGEX,
9-
ODB_FUNCTION_PATH,
10-
HANDLER_FUNCTION_PATH,
11-
} from '../constants'
5+
import { OPTIONAL_CATCH_ALL_REGEX, CATCH_ALL_REGEX, DYNAMIC_PARAMETER_REGEX, HANDLER_FUNCTION_PATH } from '../constants'
126

137
import { I18n } from './types'
148

@@ -77,16 +71,6 @@ const netlifyRoutesForNextRoute = (route: string, buildId: string, i18n?: I18n):
7771

7872
export const isApiRoute = (route: string) => route.startsWith('/api/') || route === '/api'
7973

80-
export const targetForFallback = (fallback: string | false) => {
81-
if (fallback === null || fallback === false) {
82-
// fallback = null mean "blocking", which uses ODB. For fallback=false then anything prerendered should 404.
83-
// However i18n pages may not have been prerendered, so we still need to hit the origin
84-
return { to: ODB_FUNCTION_PATH, status: 200 }
85-
}
86-
// fallback = true is also ODB
87-
return { to: ODB_FUNCTION_PATH, status: 200 }
88-
}
89-
9074
export const redirectsForNextRoute = ({
9175
route,
9276
buildId,

‎test/__snapshots__/index.js.snap

+122
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ exports.resolvePages = () => {
2323
require.resolve('../../../.next/server/pages/getStaticProps/with-revalidate.js')
2424
require.resolve('../../../.next/server/pages/getStaticProps/withFallback/[...slug].js')
2525
require.resolve('../../../.next/server/pages/getStaticProps/withFallback/[id].js')
26+
require.resolve('../../../.next/server/pages/getStaticProps/withFallbackAndMiddleware/[...slug].js')
27+
require.resolve('../../../.next/server/pages/getStaticProps/withFallbackAndMiddleware/[id].js')
28+
require.resolve('../../../.next/server/pages/getStaticProps/withFallbackAndMiddleware/_middleware.js')
2629
require.resolve('../../../.next/server/pages/getStaticProps/withFallbackBlocking/[id].js')
2730
require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/[id].js')
2831
require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/withFallback/[id].js')
@@ -58,6 +61,9 @@ exports.resolvePages = () => {
5861
require.resolve('../../../.next/server/pages/getStaticProps/with-revalidate.js')
5962
require.resolve('../../../.next/server/pages/getStaticProps/withFallback/[...slug].js')
6063
require.resolve('../../../.next/server/pages/getStaticProps/withFallback/[id].js')
64+
require.resolve('../../../.next/server/pages/getStaticProps/withFallbackAndMiddleware/[...slug].js')
65+
require.resolve('../../../.next/server/pages/getStaticProps/withFallbackAndMiddleware/[id].js')
66+
require.resolve('../../../.next/server/pages/getStaticProps/withFallbackAndMiddleware/_middleware.js')
6167
require.resolve('../../../.next/server/pages/getStaticProps/withFallbackBlocking/[id].js')
6268
require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/[id].js')
6369
require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/withFallback/[id].js')
@@ -93,6 +99,9 @@ exports.resolvePages = () => {
9399
require.resolve('../../../web/.next/server/pages/getStaticProps/with-revalidate.js')
94100
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallback/[...slug].js')
95101
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallback/[id].js')
102+
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackAndMiddleware/[...slug].js')
103+
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackAndMiddleware/[id].js')
104+
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackAndMiddleware/_middleware.js')
96105
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackBlocking/[id].js')
97106
require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/[id].js')
98107
require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/withFallback/[id].js')
@@ -128,6 +137,9 @@ exports.resolvePages = () => {
128137
require.resolve('../../../web/.next/server/pages/getStaticProps/with-revalidate.js')
129138
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallback/[...slug].js')
130139
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallback/[id].js')
140+
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackAndMiddleware/[...slug].js')
141+
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackAndMiddleware/[id].js')
142+
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackAndMiddleware/_middleware.js')
131143
require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackBlocking/[id].js')
132144
require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/[id].js')
133145
require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/withFallback/[id].js')
@@ -441,6 +453,116 @@ Array [
441453
"status": 200,
442454
"to": "/.netlify/functions/___netlify-handler",
443455
},
456+
Object {
457+
"from": "/getStaticProps/withFallbackAndMiddleware",
458+
"status": 200,
459+
"to": "/.netlify/functions/___netlify-handler",
460+
},
461+
Object {
462+
"from": "/getStaticProps/withFallbackAndMiddleware/*",
463+
"status": 200,
464+
"to": "/.netlify/functions/___netlify-handler",
465+
},
466+
Object {
467+
"from": "/en/getStaticProps/withFallbackAndMiddleware",
468+
"status": 200,
469+
"to": "/.netlify/functions/___netlify-handler",
470+
},
471+
Object {
472+
"from": "/en/getStaticProps/withFallbackAndMiddleware/*",
473+
"status": 200,
474+
"to": "/.netlify/functions/___netlify-handler",
475+
},
476+
Object {
477+
"from": "/_next/data/build-id/en/getStaticProps/withFallbackAndMiddleware/*",
478+
"status": 200,
479+
"to": "/.netlify/functions/___netlify-handler",
480+
},
481+
Object {
482+
"from": "/es/getStaticProps/withFallbackAndMiddleware",
483+
"status": 200,
484+
"to": "/.netlify/functions/___netlify-handler",
485+
},
486+
Object {
487+
"from": "/es/getStaticProps/withFallbackAndMiddleware/*",
488+
"status": 200,
489+
"to": "/.netlify/functions/___netlify-handler",
490+
},
491+
Object {
492+
"from": "/_next/data/build-id/es/getStaticProps/withFallbackAndMiddleware/*",
493+
"status": 200,
494+
"to": "/.netlify/functions/___netlify-handler",
495+
},
496+
Object {
497+
"from": "/fr/getStaticProps/withFallbackAndMiddleware",
498+
"status": 200,
499+
"to": "/.netlify/functions/___netlify-handler",
500+
},
501+
Object {
502+
"from": "/fr/getStaticProps/withFallbackAndMiddleware/*",
503+
"status": 200,
504+
"to": "/.netlify/functions/___netlify-handler",
505+
},
506+
Object {
507+
"from": "/_next/data/build-id/fr/getStaticProps/withFallbackAndMiddleware/*",
508+
"status": 200,
509+
"to": "/.netlify/functions/___netlify-handler",
510+
},
511+
Object {
512+
"from": "/middle",
513+
"status": 200,
514+
"to": "/.netlify/functions/___netlify-handler",
515+
},
516+
Object {
517+
"from": "/middle/*",
518+
"status": 200,
519+
"to": "/.netlify/functions/___netlify-handler",
520+
},
521+
Object {
522+
"from": "/en/middle",
523+
"status": 200,
524+
"to": "/.netlify/functions/___netlify-handler",
525+
},
526+
Object {
527+
"from": "/en/middle/*",
528+
"status": 200,
529+
"to": "/.netlify/functions/___netlify-handler",
530+
},
531+
Object {
532+
"from": "/_next/data/build-id/en/middle/*",
533+
"status": 200,
534+
"to": "/.netlify/functions/___netlify-handler",
535+
},
536+
Object {
537+
"from": "/es/middle",
538+
"status": 200,
539+
"to": "/.netlify/functions/___netlify-handler",
540+
},
541+
Object {
542+
"from": "/es/middle/*",
543+
"status": 200,
544+
"to": "/.netlify/functions/___netlify-handler",
545+
},
546+
Object {
547+
"from": "/_next/data/build-id/es/middle/*",
548+
"status": 200,
549+
"to": "/.netlify/functions/___netlify-handler",
550+
},
551+
Object {
552+
"from": "/fr/middle",
553+
"status": 200,
554+
"to": "/.netlify/functions/___netlify-handler",
555+
},
556+
Object {
557+
"from": "/fr/middle/*",
558+
"status": 200,
559+
"to": "/.netlify/functions/___netlify-handler",
560+
},
561+
Object {
562+
"from": "/_next/data/build-id/fr/middle/*",
563+
"status": 200,
564+
"to": "/.netlify/functions/___netlify-handler",
565+
},
444566
Object {
445567
"force": true,
446568
"from": "/_next/data/build-id/en/getStaticProps/with-revalidate.json",

0 commit comments

Comments
 (0)
Please sign in to comment.