1
+ /* eslint-disable max-lines */
1
2
import { NetlifyConfig } from '@netlify/build'
3
+ import { yellowBright } from 'chalk'
2
4
import { readJSON } from 'fs-extra'
3
5
import { NextConfig } from 'next'
4
6
import { PrerenderManifest } from 'next/dist/build'
7
+ import { outdent } from 'outdent'
5
8
import { join } from 'pathe'
6
9
7
10
import { HANDLER_FUNCTION_PATH , HIDDEN_PATHS , ODB_FUNCTION_PATH } from '../constants'
8
11
12
+ import { getMiddleware } from './files'
9
13
import { RoutesManifest } from './types'
10
14
import {
11
15
getApiRewrites ,
@@ -14,9 +18,11 @@ import {
14
18
redirectsForNextRoute ,
15
19
redirectsForNextRouteWithData ,
16
20
routeToDataRoute ,
17
- targetForFallback ,
18
21
} from './utils'
19
22
23
+ const matchesMiddleware = ( middleware : Array < string > , route : string ) : boolean =>
24
+ middleware ?. some ( ( middlewarePath ) => route . startsWith ( middlewarePath ) )
25
+
20
26
const generateLocaleRedirects = ( {
21
27
i18n,
22
28
basePath,
@@ -65,6 +71,7 @@ export const generateStaticRedirects = ({
65
71
}
66
72
}
67
73
74
+ // eslint-disable-next-line max-lines-per-function
68
75
export const generateRedirects = async ( {
69
76
netlifyConfig,
70
77
nextConfig : { i18n, basePath, trailingSlash, appDir } ,
@@ -102,6 +109,32 @@ export const generateRedirects = async ({
102
109
...( await getPreviewRewrites ( { basePath, appDir } ) ) ,
103
110
)
104
111
112
+ const middleware = await getMiddleware ( netlifyConfig . build . publish )
113
+ const routesThatMatchMiddleware = new Set < string > ( )
114
+
115
+ const handlerRewrite = ( from : string ) => ( {
116
+ from : `${ basePath } ${ from } ` ,
117
+ to : HANDLER_FUNCTION_PATH ,
118
+ status : 200 ,
119
+ } )
120
+
121
+ // Routes that match middleware need to always use the SSR function
122
+ // This generates a rewrite for every middleware in every locale, both with and without a splat
123
+ netlifyConfig . redirects . push (
124
+ ...middleware
125
+ . map ( ( route ) => [
126
+ handlerRewrite ( `${ route } ` ) ,
127
+ handlerRewrite ( `${ route } /*` ) ,
128
+ handlerRewrite ( routeToDataRoute ( `${ route } /*` , buildId ) ) ,
129
+ ...( i18n ?. locales ?. map ( ( locale ) => [
130
+ handlerRewrite ( `/${ locale } ${ route } ` ) ,
131
+ handlerRewrite ( `/${ locale } ${ route } /*` ) ,
132
+ handlerRewrite ( routeToDataRoute ( `${ route } /*` , buildId , locale ) ) ,
133
+ ] ) ?? [ ] ) ,
134
+ ] )
135
+ . flat ( 2 ) ,
136
+ )
137
+
105
138
const staticRouteEntries = Object . entries ( prerenderedStaticRoutes )
106
139
107
140
const staticRoutePaths = new Set < string > ( )
@@ -121,7 +154,9 @@ export const generateRedirects = async ({
121
154
if ( i18n ?. defaultLocale && route . startsWith ( `/${ i18n . defaultLocale } /` ) ) {
122
155
route = route . slice ( i18n . defaultLocale . length + 1 )
123
156
staticRoutePaths . add ( route )
124
-
157
+ if ( matchesMiddleware ( middleware , route ) ) {
158
+ routesThatMatchMiddleware . add ( route )
159
+ }
125
160
netlifyConfig . redirects . push (
126
161
...redirectsForNextRouteWithData ( {
127
162
route,
@@ -132,6 +167,9 @@ export const generateRedirects = async ({
132
167
} ) ,
133
168
)
134
169
} else {
170
+ if ( matchesMiddleware ( middleware , route ) ) {
171
+ routesThatMatchMiddleware . add ( route )
172
+ }
135
173
// ISR routes use the ODB handler
136
174
netlifyConfig . redirects . push (
137
175
// No i18n, because the route is already localized
@@ -155,11 +193,12 @@ export const generateRedirects = async ({
155
193
return
156
194
}
157
195
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 } ) )
196
+ if ( matchesMiddleware ( middleware , route . page ) ) {
197
+ routesThatMatchMiddleware . add ( route . page )
198
+ }
199
+ netlifyConfig . redirects . push (
200
+ ...redirectsForNextRoute ( { buildId, route : route . page , basePath, to : ODB_FUNCTION_PATH , status : 200 , i18n } ) ,
201
+ )
163
202
} else {
164
203
// If the route isn't prerendered, it's SSR
165
204
netlifyConfig . redirects . push (
@@ -174,4 +213,19 @@ export const generateRedirects = async ({
174
213
to : HANDLER_FUNCTION_PATH ,
175
214
status : 200 ,
176
215
} )
216
+
217
+ const middlewareMatches = routesThatMatchMiddleware . size
218
+ if ( middlewareMatches > 0 ) {
219
+ console . log (
220
+ yellowBright ( outdent `
221
+ There ${
222
+ middlewareMatches === 1
223
+ ? `is one statically-generated or ISR route`
224
+ : `are ${ middlewareMatches } statically-generated or ISR routes`
225
+ } that match a middleware function, which means they will always be served from the SSR function and will not use ISR or be served from the CDN.
226
+ If this was not intended, ensure that your middleware only matches routes that you intend to use SSR.
227
+ ` ) ,
228
+ )
229
+ }
177
230
}
231
+ /* eslint-enable max-lines */
0 commit comments