1
- import fs from "node:fs" ;
2
1
import path from "node:path" ;
3
2
import { IncomingMessage } from "./request.js" ;
4
3
import { ServerResponse } from "./response.js" ;
@@ -7,32 +6,41 @@ import type {
7
6
APIGatewayProxyEvent ,
8
7
CloudFrontRequestEvent ,
9
8
} from "aws-lambda" ;
10
- // @ts -ignore
11
- import NextServer from "next/dist/server/next-server.js" ;
12
- //@ts -ignore
13
- import { getMaybePagePath } from "next/dist/server/require.js" ;
14
- import { generateUniqueId , loadConfig , setNodeEnv } from "./util.js" ;
9
+ import {
10
+ generateUniqueId ,
11
+ loadAppPathsManifest ,
12
+ loadConfig ,
13
+ loadHtmlPages ,
14
+ loadPublicAssets ,
15
+ loadRoutesManifest ,
16
+ setNodeEnv ,
17
+ } from "./util.js" ;
15
18
import { isBinaryContentType } from "./binary.js" ;
16
19
import { debug } from "./logger.js" ;
17
- import type { PublicFiles } from "../build.js" ;
18
20
import { convertFrom , convertTo } from "./event-mapper.js" ;
19
21
import { overrideDefault , overrideReact } from "./require-hooks.js" ;
20
22
import type { WarmerEvent , WarmerResponse } from "./warmer-function.js" ;
21
23
22
24
const NEXT_DIR = path . join ( __dirname , ".next" ) ;
23
25
const OPEN_NEXT_DIR = path . join ( __dirname , ".open-next" ) ;
24
- const NODE_MODULES_DIR = path . join ( __dirname , "node_modules" ) ;
25
26
debug ( { NEXT_DIR , OPEN_NEXT_DIR } ) ;
26
27
27
28
setNodeEnv ( ) ;
28
29
setNextjsServerWorkingDirectory ( ) ;
29
30
const config = loadConfig ( NEXT_DIR ) ;
30
- const htmlPages = loadHtmlPages ( ) ;
31
- const publicAssets = loadPublicAssets ( ) ;
32
- initializeNextjsRequireHooks ( config ) ;
33
-
31
+ const htmlPages = loadHtmlPages ( NEXT_DIR ) ;
32
+ const routesManifest = loadRoutesManifest ( NEXT_DIR ) ;
33
+ const appPathsManifest = loadAppPathsManifest ( NEXT_DIR ) ;
34
+ const publicAssets = loadPublicAssets ( OPEN_NEXT_DIR ) ;
34
35
// Generate a 6 letter unique server ID
35
36
const serverId = `server-${ generateUniqueId ( ) } ` ;
37
+
38
+ // Need to override the require hooks for React before Next.js server
39
+ // overrides them with prebundled ones in the case of app dir
40
+ overrideNextjsRequireHooks ( config ) ;
41
+
42
+ // @ts -ignore
43
+ import NextServer from "next/dist/server/next-server.js" ;
36
44
const requestHandler = new NextServer . default ( {
37
45
hostname : "localhost" ,
38
46
port : Number ( process . env . PORT ) || 3000 ,
@@ -127,34 +135,40 @@ function setNextjsServerWorkingDirectory() {
127
135
process . chdir ( __dirname ) ;
128
136
}
129
137
130
- function initializeNextjsRequireHooks ( config : any ) {
138
+ function overrideNextjsRequireHooks ( config : any ) {
131
139
// WORKAROUND: Set `__NEXT_PRIVATE_PREBUNDLED_REACT` to use prebundled React — https://github.com/serverless-stack/open-next#workaround-set-__next_private_prebundled_react-to-use-prebundled-react
132
- if ( ! isNextjsVersionAtLeast ( "13.1.3" ) ) return ;
133
- overrideDefault ( ) ;
134
- overrideReact ( config ) ;
140
+ try {
141
+ overrideDefault ( ) ;
142
+ overrideReact ( config ) ;
143
+ } catch ( e ) {
144
+ console . error ( "Failed to override Next.js require hooks." , e ) ;
145
+ throw e ;
146
+ }
135
147
}
136
148
137
149
function setNextjsPrebundledReact ( req : IncomingMessage , config : any ) {
138
150
// WORKAROUND: Set `__NEXT_PRIVATE_PREBUNDLED_REACT` to use prebundled React — https://github.com/serverless-stack/open-next#workaround-set-__next_private_prebundled_react-to-use-prebundled-react
139
151
140
- // "getMaybePagePath" is not present in older version of next.js
141
- // => use node_modules React
142
- if ( ! getMaybePagePath ) {
143
- process . env . __NEXT_PRIVATE_PREBUNDLED_REACT = undefined ;
152
+ // Get route pattern
153
+ const route = [
154
+ ...routesManifest . staticRoutes ,
155
+ ...routesManifest . dynamicRoutes ,
156
+ ] . find ( ( route ) => new RegExp ( route . regex ) . test ( req . url ?? "" ) ) ;
157
+
158
+ const isApp = appPathsManifest [ `${ route ?. page } /page` ] ;
159
+ debug ( "setNextjsPrebundledReact" , { url : req . url , isApp } ) ;
160
+
161
+ // app routes => use prebundled React
162
+ if ( isApp ) {
163
+ process . env . __NEXT_PRIVATE_PREBUNDLED_REACT = config . experimental
164
+ . serverActions
165
+ ? "experimental"
166
+ : "next" ;
144
167
return ;
145
168
}
146
169
147
- // pages route => use node_modules React
148
- if ( getMaybePagePath ( req . url , NEXT_DIR , config . i18n ?. locales , false ) ) {
149
- process . env . __NEXT_PRIVATE_PREBUNDLED_REACT = undefined ;
150
- return ;
151
- }
152
-
153
- // app router => use prebundled React
154
- process . env . __NEXT_PRIVATE_PREBUNDLED_REACT = config . experimental
155
- . serverActions
156
- ? "experimental"
157
- : "next" ;
170
+ // page routes => use node_modules React
171
+ process . env . __NEXT_PRIVATE_PREBUNDLED_REACT = undefined ;
158
172
}
159
173
160
174
async function processRequest ( req : IncomingMessage , res : ServerResponse ) {
@@ -197,28 +211,3 @@ function formatWarmerResponse(event: WarmerEvent) {
197
211
} , event . delay ) ;
198
212
} ) ;
199
213
}
200
-
201
- function isNextjsVersionAtLeast ( required : `${number } .${number } .${number } `) {
202
- const version = require ( "next/package.json" ) . version ;
203
- const [ major , minor , patch ] = version . split ( "-" ) [ 0 ] . split ( "." ) . map ( Number ) ;
204
- const [ reqMajor , reqMinor , reqPatch ] = required . split ( "." ) . map ( Number ) ;
205
- return (
206
- major > reqMajor ||
207
- ( major === reqMajor && minor > reqMinor ) ||
208
- ( major === reqMajor && minor === reqMinor && patch >= reqPatch )
209
- ) ;
210
- }
211
-
212
- function loadHtmlPages ( ) {
213
- const filePath = path . join ( NEXT_DIR , "server" , "pages-manifest.json" ) ;
214
- const json = fs . readFileSync ( filePath , "utf-8" ) ;
215
- return Object . entries ( JSON . parse ( json ) )
216
- . filter ( ( [ _ , value ] ) => ( value as string ) . endsWith ( ".html" ) )
217
- . map ( ( [ key ] ) => key ) ;
218
- }
219
-
220
- function loadPublicAssets ( ) {
221
- const filePath = path . join ( OPEN_NEXT_DIR , "public-files.json" ) ;
222
- const json = fs . readFileSync ( filePath , "utf-8" ) ;
223
- return JSON . parse ( json ) as PublicFiles ;
224
- }
0 commit comments