1
+ import { PrerenderManifest } from 'next/dist/build'
1
2
import { NodeRequestHandler , Options } from 'next/dist/server/next-server'
2
3
3
4
import {
4
5
netlifyApiFetch ,
5
6
getNextServer ,
6
7
NextServerType ,
7
- removeTrailingSlash ,
8
- ensureLocalePrefix ,
9
- normalizeDataRoute ,
8
+ normalizeRoute ,
9
+ localizeRoute ,
10
+ localizeDataRoute ,
11
+ unlocalizeRoute ,
10
12
} from './handlerUtils'
11
13
12
14
const NextServer : NextServerType = getNextServer ( )
13
15
14
- interface NetlifyOptions {
16
+ interface NetlifyConfig {
15
17
revalidateToken ?: string
16
18
}
17
19
18
20
class NetlifyNextServer extends NextServer {
19
- private netlifyOptions : NetlifyOptions
21
+ private netlifyConfig : NetlifyConfig
22
+ private netlifyPrerenderManifest : PrerenderManifest
20
23
21
- public constructor ( options : Options , netlifyOptions : NetlifyOptions ) {
24
+ public constructor ( options : Options , netlifyConfig : NetlifyConfig ) {
22
25
super ( options )
23
- this . netlifyOptions = netlifyOptions
26
+ this . netlifyConfig = netlifyConfig
27
+ // copy the prerender manifest so it doesn't get mutated by Next.js
28
+ const manifest = this . getPrerenderManifest ( )
29
+ this . netlifyPrerenderManifest = {
30
+ ...manifest ,
31
+ routes : { ...manifest . routes } ,
32
+ dynamicRoutes : { ...manifest . dynamicRoutes } ,
33
+ }
24
34
}
25
35
26
36
public getRequestHandler ( ) : NodeRequestHandler {
27
37
const handler = super . getRequestHandler ( )
28
38
return async ( req , res , parsedUrl ) => {
29
39
// preserve the URL before Next.js mutates it for i18n
30
- const originalUrl = req . url
31
-
40
+ const { url, headers } = req
32
41
// handle the original res.revalidate() request
33
42
await handler ( req , res , parsedUrl )
34
-
35
43
// handle on-demand revalidation by purging the ODB cache
36
- if ( res . statusCode === 200 && req . headers [ 'x-prerender-revalidate' ] ) {
37
- await this . netlifyRevalidate ( originalUrl )
44
+ if ( res . statusCode === 200 && headers [ 'x-prerender-revalidate' ] && this . netlifyConfig . revalidateToken ) {
45
+ await this . netlifyRevalidate ( url )
38
46
}
39
47
}
40
48
}
@@ -48,7 +56,7 @@ class NetlifyNextServer extends NextServer {
48
56
paths : this . getNetlifyPathsForRoute ( route ) ,
49
57
domain : this . hostname ,
50
58
} ,
51
- token : this . netlifyOptions . revalidateToken ,
59
+ token : this . netlifyConfig . revalidateToken ,
52
60
method : 'POST' ,
53
61
} )
54
62
if ( ! result . ok ) {
@@ -61,39 +69,43 @@ class NetlifyNextServer extends NextServer {
61
69
}
62
70
63
71
private getNetlifyPathsForRoute ( route : string ) : string [ ] {
64
- const { routes, dynamicRoutes } = this . getPrerenderManifest ( )
72
+ const { i18n } = this . nextConfig
73
+ const { routes, dynamicRoutes } = this . netlifyPrerenderManifest
65
74
66
- // matches static appDir and non-i18n routes
67
- const normalizedRoute = removeTrailingSlash ( route )
75
+ // matches static non-i18n routes
76
+ const normalizedRoute = normalizeRoute ( route )
68
77
if ( normalizedRoute in routes ) {
69
- const dataRoute = normalizeDataRoute ( routes [ normalizedRoute ] . dataRoute , this . buildId )
78
+ const { dataRoute } = routes [ normalizedRoute ]
70
79
return [ route , dataRoute ]
71
80
}
72
81
73
- // matches static pageDir i18n routes
74
- const localizedRoute = ensureLocalePrefix ( normalizedRoute , this . nextConfig ?. i18n )
75
- if ( localizedRoute in routes ) {
76
- const dataRoute = normalizeDataRoute ( routes [ localizedRoute ] . dataRoute , this . buildId , this . nextConfig ?. i18n )
77
- return [ route , dataRoute ]
82
+ // matches static i18n routes
83
+ if ( i18n ) {
84
+ const localizedRoute = localizeRoute ( normalizedRoute , i18n )
85
+ if ( localizedRoute in routes ) {
86
+ const dataRoute = localizeDataRoute ( routes [ localizedRoute ] . dataRoute , localizedRoute )
87
+ return [ route , dataRoute ]
88
+ }
78
89
}
79
90
80
91
// matches dynamic routes
81
92
for ( const dynamicRoute in dynamicRoutes ) {
82
- const matches = normalizedRoute . match ( dynamicRoutes [ dynamicRoute ] . routeRegex )
93
+ const unlocalizedRoute = i18n ? unlocalizeRoute ( normalizedRoute , i18n ) : normalizedRoute
94
+ const matches = unlocalizedRoute . match ( dynamicRoutes [ dynamicRoute ] . routeRegex )
83
95
if ( matches && matches . length !== 0 ) {
84
96
// remove the first match, which is the full route
85
97
matches . shift ( )
86
98
// replace the dynamic segments with the actual values
87
- const dataRoute = normalizeDataRoute (
88
- dynamicRoutes [ dynamicRoute ] . dataRoute . replace ( / \[ ( . * ? ) ] / g , ( ) => matches . shift ( ) ) ,
89
- this . buildId ,
90
- )
99
+ const interpolatedDataRoute = dynamicRoutes [ dynamicRoute ] . dataRoute . replace ( / \[ ( . * ? ) ] / g , ( ) => matches . shift ( ) )
100
+ const dataRoute = i18n
101
+ ? localizeDataRoute ( interpolatedDataRoute , localizeRoute ( normalizedRoute , i18n ) )
102
+ : interpolatedDataRoute
91
103
return [ route , dataRoute ]
92
104
}
93
105
}
94
106
95
- throw new Error ( `could not find a route to revalidate ` )
107
+ throw new Error ( `not an ISR route` )
96
108
}
97
109
}
98
110
99
- export { NetlifyNextServer }
111
+ export { NetlifyNextServer , NetlifyConfig }
0 commit comments